am 0950c5de: Merge change 21226 into donut
Merge commit '0950c5de864d1ad83ed96efc5c2d1569b4d36188' into eclair
* commit '0950c5de864d1ad83ed96efc5c2d1569b4d36188':
Fix bug 2046705 where the output of the speech synthesizer is too low.
diff --git a/Android.mk b/Android.mk
index 5233f72..2bc83b3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -65,8 +65,11 @@
## READ ME: ########################################################
LOCAL_SRC_FILES += \
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
- core/java/android/accessibilityservice/IEventListener.aidl \
- core/java/android/accounts/IAccountsService.aidl \
+ core/java/android/accessibilityservice/IEventListener.aidl \
+ core/java/android/accounts/IAccountManager.aidl \
+ core/java/android/accounts/IAccountManagerResponse.aidl \
+ core/java/android/accounts/IAccountAuthenticator.aidl \
+ core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IActivityWatcher.aidl \
@@ -80,15 +83,15 @@
core/java/android/app/IStatusBar.aidl \
core/java/android/app/IThumbnailReceiver.aidl \
core/java/android/app/ITransientNotification.aidl \
- core/java/android/app/IWallpaperService.aidl \
- core/java/android/app/IWallpaperServiceCallback.aidl \
+ core/java/android/app/IWallpaperManager.aidl \
+ core/java/android/app/IWallpaperManagerCallback.aidl \
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/IBluetoothDeviceCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
+ core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/content/IContentService.aidl \
core/java/android/content/IIntentReceiver.aidl \
core/java/android/content/IIntentSender.aidl \
@@ -111,6 +114,9 @@
core/java/android/os/IParentalControlCallback.aidl \
core/java/android/os/IPermissionController.aidl \
core/java/android/os/IPowerManager.aidl \
+ core/java/android/service/wallpaper/IWallpaperConnection.aidl \
+ core/java/android/service/wallpaper/IWallpaperEngine.aidl \
+ core/java/android/service/wallpaper/IWallpaperService.aidl \
core/java/android/text/IClipboard.aidl \
core/java/android/view/accessibility/IAccessibilityManager.aidl \
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
@@ -195,7 +201,10 @@
# relative to the root of the build tree.
# ============================================================
aidl_files := \
- frameworks/base/core/java/android/accounts/IAccountsService.aidl \
+ frameworks/base/core/java/android/accounts/IAccountManager.aidl \
+ frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \
+ frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl \
+ frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
frameworks/base/core/java/android/app/Notification.aidl \
frameworks/base/core/java/android/app/PendingIntent.aidl \
frameworks/base/core/java/android/content/ComponentName.aidl \
@@ -364,6 +373,34 @@
-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-hdf sdk.current $(framework_docs_SDK_CURRENT_DIR)
+# ==== the api stubs and current.xml ===========================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+
+LOCAL_MODULE := api-stubs
+
+LOCAL_DROIDDOC_OPTIONS:=\
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \
+ -apixml $(INTERNAL_PLATFORM_API_FILE) \
+ -nodocs
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk
+
+include $(BUILD_DROIDDOC)
+
+$(full_target): $(framework_built)
+$(INTERNAL_PLATFORM_API_FILE): $(full_target)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
+
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
@@ -382,10 +419,7 @@
-title "Android SDK" \
-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
-todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \
- -apixml $(INTERNAL_PLATFORM_API_FILE) \
-sdkvalues $(OUT_DOCS) \
- -warning 3 \
-hdf android.whichdoc offline
ifeq ($(framework_docs_SDK_PREVIEW),true)
@@ -405,8 +439,6 @@
$(full_target): $(static_doc_index_redirect)
$(full_target): $(framework_built)
-$(INTERNAL_PLATFORM_API_FILE): $(full_target)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
# ==== docs for the web (on the google app engine server) =======================
@@ -491,5 +523,3 @@
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call first-makefiles-under,$(LOCAL_PATH))
endif
-
-
diff --git a/api/4.xml b/api/4.xml
index c8a2e83..cac3ae8 100644
--- a/api/4.xml
+++ b/api/4.xml
@@ -256713,7 +256713,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -258766,7 +258766,7 @@
<package name="java.util.concurrent.locks"
>
<class name="AbstractQueuedSynchronizer"
- extends="java.lang.Object"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
abstract="true"
static="false"
final="false"
diff --git a/api/current.xml b/api/current.xml
index ffbe6e2..ca8d81f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -122,6 +122,28 @@
visibility="public"
>
</field>
+<field name="ACCOUNT_MANAGER_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.ACCOUNT_MANAGER_SERVICE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATE_ACCOUNTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.AUTHENTICATE_ACCOUNTS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BATTERY_STATS"
type="java.lang.String"
transient="false"
@@ -155,6 +177,17 @@
visibility="public"
>
</field>
+<field name="BIND_WALLPAPER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.BIND_WALLPAPER""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BLUETOOTH"
type="java.lang.String"
transient="false"
@@ -573,6 +606,17 @@
visibility="public"
>
</field>
+<field name="MANAGE_ACCOUNTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.MANAGE_ACCOUNTS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MANAGE_APP_TOKENS"
type="java.lang.String"
transient="false"
@@ -1057,6 +1101,17 @@
visibility="public"
>
</field>
+<field name="USE_CREDENTIALS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.permission.USE_CREDENTIALS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VIBRATE"
type="java.lang.String"
transient="false"
@@ -1604,6 +1659,17 @@
visibility="public"
>
</field>
+<field name="accountType"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843406"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="action"
type="int"
transient="false"
@@ -2594,6 +2660,17 @@
visibility="public"
>
</field>
+<field name="contentAuthority"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843407"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="contentDescription"
type="int"
transient="false"
@@ -8677,6 +8754,17 @@
visibility="public"
>
</field>
+<field name="windowShowWallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843408"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowSoftInputMode"
type="int"
transient="false"
@@ -12516,6 +12604,39 @@
visibility="public"
>
</field>
+<field name="Theme_Wallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973918"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973919"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar_Fullscreen"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973920"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget"
type="int"
transient="false"
@@ -13250,6 +13371,1962 @@
</field>
</class>
</package>
+<package name="android.accounts"
+>
+<class name="AbstractAccountAuthenticator"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AbstractAccountAuthenticator"
+ type="android.accounts.AbstractAccountAuthenticator"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="addAccount"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+</method>
+<method name="confirmPassword"
+ return="boolean"
+ abstract="true"
+ 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>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="editProperties"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<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"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="getAuthTokenLabel"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getIAccountAuthenticator"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasFeatures"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="updateCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Account"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ 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="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="name"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountAuthenticatorActivity"
+ extends="android.app.Activity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AccountAuthenticatorActivity"
+ type="android.accounts.AccountAuthenticatorActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="setAccountAuthenticatorResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="AccountAuthenticatorResponse"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+</constructor>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="addAccount"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
+ 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="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="addAccountExplicitly"
+ 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="addOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<parameter name="updateImmediately" type="boolean">
+</parameter>
+</method>
+<method name="blockingGetAuthToken"
+ 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>
+<parameter name="notifyAuthFailure" type="boolean">
+</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="clearPassword"
+ 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="confirmCredentials"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
+ 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="activity" type="android.app.Activity">
+</parameter>
+<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.AccountManagerFuture<java.lang.Boolean>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<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.AccountManagerFuture<android.os.Bundle>"
+ 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="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="get"
+ return="android.accounts.AccountManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getAccounts"
+ return="android.accounts.Account[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAccountsByType"
+ 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>
+</method>
+<method name="getAccountsByTypeAndFeatures"
+ return="android.accounts.AccountManagerFuture<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>
+<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.AccountManagerFuture<android.os.Bundle>"
+ 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="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<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.AccountManagerFuture<android.os.Bundle>"
+ 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="notifyAuthFailure" type="boolean">
+</parameter>
+<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthTokenByFeatures"
+ 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="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<parameter name="activityForPrompting" type="android.app.Activity">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<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.AuthenticatorDescription[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPassword"
+ 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="getUserData"
+ 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="invalidateAuthToken"
+ 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="peekAuthToken"
+ 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="removeAccount"
+ return="android.accounts.AccountManagerFuture<java.lang.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="callback" type="android.accounts.AccountManagerCallback<java.lang.Boolean>">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="removeOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+</method>
+<method name="setAuthToken"
+ 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="setPassword"
+ 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="setUserData"
+ 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="updateCredentials"
+ return="android.accounts.AccountManagerFuture<android.os.Bundle>"
+ 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="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<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"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AuthenticatorDescription"
+ type="android.accounts.AuthenticatorDescription"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="labelId" type="int">
+</parameter>
+<parameter name="iconId" type="int">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newKey"
+ return="android.accounts.AuthenticatorDescription"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="iconId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="labelId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="packageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AuthenticatorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="ChooseAccountActivity"
+ extends="android.app.ListActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ChooseAccountActivity"
+ type="android.accounts.ChooseAccountActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Constants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="ACCOUNTS_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""accounts""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_AUTHENTICATOR_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""accountAuthenticatorResponse""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_MANAGER_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""accountManagerResponse""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_NAME_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""authAccount""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_TYPE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""accountType""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_ATTRIBUTES_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""account-authenticator""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_INTENT_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.accounts.AccountAuthenticator""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_META_DATA_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.accounts.AccountAuthenticator""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_TYPES_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""authenticator_types""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHTOKEN_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""authtoken""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTH_FAILED_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""authFailedMessage""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTH_TOKEN_LABEL_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""authTokenLabelKey""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOOLEAN_RESULT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""booleanResult""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_BAD_ARGUMENTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_BAD_REQUEST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_INVALID_RESPONSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""errorCode""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_NETWORK_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_REMOTE_EXCEPTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_UNSUPPORTED_OPERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""errorMessage""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INTENT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""intent""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOGIN_ACCOUNTS_CHANGED_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.accounts.LOGIN_ACCOUNTS_CHANGED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ 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"
+ volatile="false"
+ value=""userdata""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="IAccountAuthenticator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="addAccount"
+ 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="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ 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="confirmPassword"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="editProperties"
+ 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="accountType" type="java.lang.String">
+</parameter>
+<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"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="getAuthTokenLabel"
+ 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="authTokenType" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="hasFeatures"
+ 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>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="updateCredentials"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticator.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticator">
+</implements>
+<constructor name="IAccountAuthenticator.Stub"
+ type="android.accounts.IAccountAuthenticator.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<interface name="IAccountAuthenticatorResponse"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticatorResponse.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticatorResponse">
+</implements>
+<constructor name="IAccountAuthenticatorResponse.Stub"
+ type="android.accounts.IAccountAuthenticatorResponse.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticatorResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<class name="NetworkErrorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<interface name="OnAccountsUpdatedListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onAccountsUpdated"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accounts" type="android.accounts.Account[]">
+</parameter>
+</method>
+</interface>
+<class name="OperationCanceledException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+</package>
<package name="android.app"
>
<class name="Activity"
@@ -21868,6 +23945,175 @@
</parameter>
</method>
</interface>
+<class name="WallpaperManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="clear"
+ 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="clearWallpaperOffsets"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="getDesiredMinimumHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDesiredMinimumWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="android.app.WallpaperManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="peekDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setBitmap"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bitmap" type="android.graphics.Bitmap">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resid" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setStream"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="java.io.InputStream">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setWallpaperOffsets"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+<parameter name="xOffset" type="float">
+</parameter>
+<parameter name="yOffset" type="float">
+</parameter>
+</method>
+<method name="suggestDesiredDimensions"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="minimumWidth" type="int">
+</parameter>
+<parameter name="minimumHeight" type="int">
+</parameter>
+</method>
+</class>
</package>
<package name="android.appwidget"
>
@@ -22616,6 +24862,75 @@
</package>
<package name="android.content"
>
+<class name="AbstractCursorEntityIterator"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.EntityIterator">
+</implements>
+<constructor name="AbstractCursorEntityIterator"
+ type="android.content.AbstractCursorEntityIterator"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="entityCursor" type="android.database.Cursor">
+</parameter>
+</constructor>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newEntityFromCursorLocked"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -22738,6 +25053,23 @@
<parameter name="cursor" type="android.database.Cursor">
</parameter>
</method>
+<method name="onQueryEntitiesComplete"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<parameter name="iterator" type="android.content.EntityIterator">
+</parameter>
+</method>
<method name="onUpdateComplete"
return="void"
abstract="false"
@@ -22820,6 +25152,29 @@
<parameter name="orderBy" type="java.lang.String">
</parameter>
</method>
+<method name="startQueryEntities"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="orderBy" type="java.lang.String">
+</parameter>
+</method>
<method name="startUpdate"
return="void"
abstract="false"
@@ -23445,6 +25800,21 @@
visibility="public"
>
</constructor>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+</method>
<method name="attachInfo"
return="void"
abstract="false"
@@ -23564,6 +25934,21 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
<method name="isTemporary"
return="boolean"
abstract="false"
@@ -23682,6 +26067,25 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+</method>
<method name="setPathPermissions"
return="void"
abstract="false"
@@ -23740,6 +26144,671 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
+</class>
+<class name="ContentProviderClient"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="bulkInsert"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="initialValues" type="android.content.ContentValues[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="delete"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="getLocalContentProvider"
+ return="android.content.ContentProvider"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="insert"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="initialValues" type="android.content.ContentValues">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="openAssetFile"
+ return="android.content.res.AssetFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="openFile"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="query"
+ return="android.database.Cursor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="projection" type="java.lang.String[]">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="release"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="update"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<class name="ContentProviderOperation"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="apply"
+ return="android.content.ContentProviderResult"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProvider">
+</parameter>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</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="getUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isReadOperation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isWriteOperation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newAssertQuery"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newDelete"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newInsert"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newUpdate"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="resolveSelectionArgsBackReferences"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+</method>
+<method name="resolveValueBackReferences"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="ContentProviderOperation.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="build"
+ return="android.content.ContentProviderOperation"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="withExpectedCount"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="count" type="int">
+</parameter>
+</method>
+<method name="withSelection"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="withSelectionBackReference"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selectionArgIndex" type="int">
+</parameter>
+<parameter name="previousResult" type="int">
+</parameter>
+</method>
+<method name="withValue"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+<method name="withValueBackReference"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="previousResult" type="int">
+</parameter>
+</method>
+<method name="withValueBackReferences"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backReferences" type="android.content.ContentValues">
+</parameter>
+</method>
+<method name="withValues"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</method>
+</class>
+<class name="ContentProviderResult"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</constructor>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="count" type="int">
+</parameter>
+</constructor>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ 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="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="count"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="uri"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="ContentQueryMap"
extends="java.util.Observable"
@@ -23843,6 +26912,66 @@
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
+<method name="acquireContentProviderClient"
+ return="android.content.ContentProviderClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="acquireContentProviderClient"
+ return="android.content.ContentProviderClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="addStatusChangeListener"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mask" type="int">
+</parameter>
+<parameter name="callback" type="android.content.SyncStatusObserver">
+</parameter>
+</method>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="operations" type="java.util.ArrayList<android.content.ContentProviderOperation>">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="bulkInsert"
return="int"
abstract="false"
@@ -23865,12 +26994,27 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
+<method name="cancelSync"
+ 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>
+</method>
<method name="delete"
return="int"
abstract="false"
@@ -23888,6 +27032,58 @@
<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"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSyncAdapterTypes"
+ return="android.content.SyncAdapterType[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSyncAutomatically"
+ return="boolean"
+ 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="getType"
return="java.lang.String"
abstract="false"
@@ -23916,6 +27112,36 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="isSyncActive"
+ return="boolean"
+ 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="isSyncPending"
+ return="boolean"
+ 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="notifyChange"
return="void"
abstract="false"
@@ -24050,6 +27276,27 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="registerContentObserver"
return="void"
abstract="false"
@@ -24067,6 +27314,83 @@
<parameter name="observer" type="android.database.ContentObserver">
</parameter>
</method>
+<method name="removeStatusChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handle" type="java.lang.Object">
+</parameter>
+</method>
+<method name="requestSync"
+ 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="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"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
+<method name="setSyncAutomatically"
+ 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="sync" type="boolean">
+</parameter>
+</method>
<method name="startSync"
return="void"
abstract="false"
@@ -24074,7 +27398,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
@@ -24189,7 +27513,7 @@
value=""account""
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -24222,6 +27546,17 @@
value=""force""
static="true"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="SYNC_EXTRAS_MANUAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""force""
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -24900,7 +28235,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<exception name="IOException" type="java.io.IOException">
@@ -25349,7 +28684,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25360,7 +28695,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25371,7 +28706,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25523,7 +28858,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25690,7 +29025,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="bitmap" type="android.graphics.Bitmap">
@@ -25705,7 +29040,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="data" type="java.io.InputStream">
@@ -25806,6 +29141,17 @@
visibility="public"
>
</field>
+<field name="ACCOUNT_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""account""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTIVITY_SERVICE"
type="java.lang.String"
transient="false"
@@ -27298,6 +30644,186 @@
</parameter>
</method>
</interface>
+<class name="Entity"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Entity"
+ type="android.content.Entity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</constructor>
+<method name="addSubValue"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEntityValues"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubValues"
+ return="java.util.ArrayList<android.content.Entity.NamedContentValues>"
+ 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="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Entity.NamedContentValues"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Entity.NamedContentValues"
+ type="android.content.Entity.NamedContentValues"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</constructor>
+<field name="uri"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="values"
+ type="android.content.ContentValues"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="EntityIterator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="close"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -29416,7 +32942,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""android.intent.action.ACTION_POWER_CONNECTED""
+ value=""android.intent.action.POWER_CONNECTED""
static="true"
final="true"
deprecated="not deprecated"
@@ -29427,7 +32953,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value=""android.intent.action.ACTION_POWER_DISCONNECTED""
+ value=""android.intent.action.POWER_DISCONNECTED""
static="true"
final="true"
deprecated="not deprecated"
@@ -29467,6 +32993,17 @@
visibility="public"
>
</field>
+<field name="ACTION_REMOTE_INTENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.action.REMOTE_INTENT""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_RUN"
type="java.lang.String"
transient="false"
@@ -30016,6 +33553,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_REMOTE_INTENT_TOKEN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.extra.remote_intent_token""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_REPLACING"
type="java.lang.String"
transient="false"
@@ -31622,6 +35170,55 @@
</parameter>
</method>
</class>
+<class name="OperationApplicationException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<class name="ReceiverCallNotAllowedException"
extends="android.util.AndroidRuntimeException"
abstract="false"
@@ -32112,6 +35709,127 @@
</parameter>
</method>
</interface>
+<class name="SyncAdapterType"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="SyncAdapterType"
+ type="android.content.SyncAdapterType"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="SyncAdapterType"
+ type="android.content.SyncAdapterType"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ 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="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="accountType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="authority"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="isUserFacing"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ value="true"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="SyncStatusObserver"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onStatusChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="which" type="int">
+</parameter>
+</method>
+</interface>
<class name="UriMatcher"
extends="java.lang.Object"
abstract="false"
@@ -33971,6 +37689,21 @@
<parameter name="pkg2" type="java.lang.String">
</parameter>
</method>
+<method name="checkSignatures"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid1" type="int">
+</parameter>
+<parameter name="uid2" type="int">
+</parameter>
+</method>
<method name="clearPackagePreferredActivities"
return="void"
abstract="true"
@@ -34182,6 +37915,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="true"
@@ -35570,7 +39316,7 @@
volatile="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -39384,6 +43130,32 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="isFloat"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<method name="isLong"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="isNull"
return="boolean"
abstract="false"
@@ -39397,6 +43169,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="isString"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="setWindow"
return="void"
abstract="false"
@@ -40477,6 +44262,36 @@
<parameter name="col" type="int">
</parameter>
</method>
+<method name="isFloat"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
+<method name="isLong"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
<method name="isNull"
return="boolean"
abstract="false"
@@ -40492,6 +44307,21 @@
<parameter name="col" type="int">
</parameter>
</method>
+<method name="isString"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
<method name="newFromParcel"
return="android.database.CursorWindow"
abstract="false"
@@ -41687,6 +45517,21 @@
<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
</exception>
</method>
+<method name="readExceptionWithOperationApplicationExceptionFromParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+</method>
<method name="sqlEscapeString"
return="java.lang.String"
abstract="false"
@@ -57029,6 +60874,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"
@@ -60038,6 +63904,19 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="setZoomCallback"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cb" type="android.hardware.Camera.ZoomCallback">
+</parameter>
+</method>
<method name="startPreview"
return="void"
abstract="false"
@@ -60077,6 +63956,25 @@
<parameter name="jpeg" type="android.hardware.Camera.PictureCallback">
</parameter>
</method>
+<method name="takePicture"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="shutter" type="android.hardware.Camera.ShutterCallback">
+</parameter>
+<parameter name="raw" type="android.hardware.Camera.PictureCallback">
+</parameter>
+<parameter name="postview" type="android.hardware.Camera.PictureCallback">
+</parameter>
+<parameter name="jpeg" type="android.hardware.Camera.PictureCallback">
+</parameter>
+</method>
<field name="CAMERA_ERROR_SERVER_DIED"
type="int"
transient="false"
@@ -60478,6 +64376,29 @@
>
</field>
</class>
+<interface name="Camera.ZoomCallback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onZoomUpdate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="zoomLevel" type="int">
+</parameter>
+<parameter name="camera" type="android.hardware.Camera">
+</parameter>
+</method>
+</interface>
<class name="GeomagneticField"
extends="java.lang.Object"
abstract="false"
@@ -65545,6 +69466,29 @@
</parameter>
</method>
</interface>
+<interface name="GpsStatus.NmeaListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onNmeaReceived"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timestamp" type="long">
+</parameter>
+<parameter name="nmea" type="java.lang.String">
+</parameter>
+</method>
+</interface>
<class name="Location"
extends="java.lang.Object"
abstract="false"
@@ -66148,6 +70092,19 @@
<parameter name="listener" type="android.location.GpsStatus.Listener">
</parameter>
</method>
+<method name="addNmeaListener"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
<method name="addProximityAlert"
return="void"
abstract="false"
@@ -66358,6 +70315,19 @@
<parameter name="listener" type="android.location.GpsStatus.Listener">
</parameter>
</method>
+<method name="removeNmeaListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
<method name="removeProximityAlert"
return="void"
abstract="false"
@@ -66842,7 +70812,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66853,7 +70823,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66864,7 +70834,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66875,6 +70845,380 @@
value="3"
static="true"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_INVALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_BACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_BACK_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_FRONT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_FRONT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_LEFT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_MONO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_PRESSURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_RIGHT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_STEREO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_VOICE_DNLINK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32768"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_VOICE_UPLINK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16384"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_X_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_Y_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4096"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_Z_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_5POINT1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="252"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_7POINT1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1020"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_LEFT_OF_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_RIGHT_OF_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_LOW_FREQUENCY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_MONO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_QUAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="204"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_STEREO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_SURROUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1052"
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -66992,6 +71336,19 @@
visibility="public"
>
</method>
+<method name="getParameters"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keys" type="java.lang.String">
+</parameter>
+</method>
<method name="getRingerMode"
return="int"
abstract="false"
@@ -67110,6 +71467,17 @@
visibility="public"
>
</method>
+<method name="isWiredHeadsetOn"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="loadSoundEffects"
return="void"
abstract="false"
@@ -67156,7 +71524,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="on" type="boolean">
@@ -67201,6 +71569,19 @@
<parameter name="mode" type="int">
</parameter>
</method>
+<method name="setParameters"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyValuePairs" type="java.lang.String">
+</parameter>
+</method>
<method name="setRingerMode"
return="void"
abstract="false"
@@ -67306,6 +71687,19 @@
<parameter name="vibrateSetting" type="int">
</parameter>
</method>
+<method name="setWiredHeadsetOn"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="on" type="boolean">
+</parameter>
+</method>
<method name="shouldVibrate"
return="boolean"
abstract="false"
@@ -67678,7 +72072,7 @@
value="-1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67700,7 +72094,7 @@
value="16"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67711,7 +72105,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67722,7 +72116,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67733,7 +72127,7 @@
value="8"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67744,7 +72138,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67759,6 +72153,17 @@
visibility="public"
>
</field>
+<field name="STREAM_DTMF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="STREAM_MUSIC"
type="int"
transient="false"
@@ -69494,6 +73899,21 @@
visibility="public"
>
</method>
+<method name="invoke"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+</method>
<method name="isLooping"
return="boolean"
abstract="false"
@@ -69516,6 +73936,17 @@
visibility="public"
>
</method>
+<method name="newRequest"
+ return="android.os.Parcel"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="pause"
return="void"
abstract="false"
@@ -69921,6 +74352,17 @@
visibility="public"
>
</field>
+<field name="MEDIA_INFO_METADATA_UPDATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="802"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MEDIA_INFO_NOT_SEEKABLE"
type="int"
transient="false"
@@ -101260,6 +105702,17 @@
visibility="public"
>
</field>
+<field name="GROUP_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""group_sync_account_type""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="GROUP_SYNC_ID"
type="java.lang.String"
transient="false"
@@ -103202,6 +107655,17 @@
visibility="public"
>
</field>
+<field name="_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""_sync_account_type""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<class name="LiveFolders"
extends="java.lang.Object"
@@ -107209,6 +111673,17 @@
visibility="public"
>
</field>
+<field name="ALARM_ALERT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""alarm_alert""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ALWAYS_FINISH_ACTIVITIES"
type="java.lang.String"
transient="false"
@@ -107329,6 +111804,16 @@
visibility="public"
>
</field>
+<field name="DEFAULT_ALARM_ALERT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="DEFAULT_NOTIFICATION_URI"
type="android.net.Uri"
transient="false"
@@ -108252,6 +112737,170 @@
>
</field>
</class>
+<class name="SyncStateContract"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SyncStateContract"
+ type="android.provider.SyncStateContract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="SyncStateContract.Columns"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<field name="ACCOUNT_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""account_name""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""account_type""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""data""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
+<class name="SyncStateContract.Constants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.SyncStateContract.Columns">
+</implements>
+<constructor name="SyncStateContract.Constants"
+ type="android.provider.SyncStateContract.Constants"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CONTENT_DIRECTORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""syncstate""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SyncStateContract.Helpers"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SyncStateContract.Helpers"
+ type="android.provider.SyncStateContract.Helpers"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProviderClient">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="newSetOperation"
+ return="android.content.ContentProviderOperation"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+</method>
+<method name="set"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProviderClient">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
<class name="UserDictionary"
extends="java.lang.Object"
abstract="false"
@@ -115178,7 +119827,7 @@
>
<parameter name="uri" type="android.net.Uri">
</parameter>
-<parameter name="account" type="java.lang.String">
+<parameter name="accountName" type="java.lang.String">
</parameter>
<parameter name="authority" type="java.lang.String">
</parameter>
@@ -117194,6 +121843,21 @@
<parameter name="pkg2" type="java.lang.String">
</parameter>
</method>
+<method name="checkSignatures"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid1" type="int">
+</parameter>
+<parameter name="uid2" type="int">
+</parameter>
+</method>
<method name="clearPackagePreferredActivities"
return="void"
abstract="false"
@@ -117405,6 +122069,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="false"
@@ -122693,6 +127370,16 @@
visibility="public"
>
</field>
+<field name="density"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="drawableState"
type="int[]"
transient="false"
@@ -123904,6 +128591,27 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="formatDateRange"
+ return="java.util.Formatter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="formatter" type="java.util.Formatter">
+</parameter>
+<parameter name="startMillis" type="long">
+</parameter>
+<parameter name="endMillis" type="long">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<method name="formatDateTime"
return="java.lang.String"
abstract="false"
@@ -127670,6 +132378,18 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="size" type="int">
+</parameter>
+<parameter name="dip" type="boolean">
+</parameter>
+</constructor>
+<constructor name="AbsoluteSizeSpan"
+ type="android.text.style.AbsoluteSizeSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="src" type="android.os.Parcel">
</parameter>
</constructor>
@@ -127684,6 +132404,17 @@
visibility="public"
>
</method>
+<method name="getDip"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSize"
return="int"
abstract="false"
@@ -129074,6 +133805,41 @@
</parameter>
</method>
</interface>
+<interface name="LineHeightSpan.WithDensity"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.text.style.LineHeightSpan">
+</implements>
+<method name="chooseHeight"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="spanstartv" type="int">
+</parameter>
+<parameter name="v" type="int">
+</parameter>
+<parameter name="fm" type="android.graphics.Paint.FontMetricsInt">
+</parameter>
+<parameter name="paint" type="android.text.TextPaint">
+</parameter>
+</method>
+</interface>
<class name="MaskFilterSpan"
extends="android.text.style.CharacterStyle"
abstract="false"
@@ -132365,6 +137131,62 @@
>
</method>
</class>
+<class name="Pair"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Pair"
+ type="android.util.Pair"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="first" type="F">
+</parameter>
+<parameter name="second" type="S">
+</parameter>
+</constructor>
+<method name="create"
+ return="android.util.Pair<A, B>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="a" type="A">
+</parameter>
+<parameter name="b" type="B">
+</parameter>
+</method>
+<field name="first"
+ type="F"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="second"
+ type="S"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="PrintStreamPrinter"
extends="java.lang.Object"
abstract="false"
@@ -135335,6 +140157,17 @@
visibility="public"
>
</field>
+<field name="VIRTUAL_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="InflateException"
extends="java.lang.RuntimeException"
@@ -136175,6 +141008,17 @@
visibility="public"
>
</method>
+<method name="isCanceled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isModifierKey"
return="boolean"
abstract="false"
@@ -136290,6 +141134,17 @@
visibility="public"
>
</field>
+<field name="FLAG_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_EDITOR_ACTION"
type="int"
transient="false"
@@ -136334,6 +141189,17 @@
visibility="public"
>
</field>
+<field name="FLAG_VIRTUAL_HARD_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_WOKE_HERE"
type="int"
transient="false"
@@ -138697,6 +143563,19 @@
visibility="public"
>
</method>
+<method name="findPointerIndex"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerId" type="int">
+</parameter>
+</method>
<method name="getAction"
return="int"
abstract="false"
@@ -138778,6 +143657,21 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalPressure"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistoricalSize"
return="float"
abstract="false"
@@ -138791,6 +143685,34 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalSize"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistoricalX"
return="float"
abstract="false"
@@ -138801,6 +143723,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="pointerIndex" type="int">
+</parameter>
<parameter name="pos" type="int">
</parameter>
</method>
@@ -138817,6 +143741,21 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistorySize"
return="int"
abstract="false"
@@ -138839,6 +143778,30 @@
visibility="public"
>
</method>
+<method name="getPointerCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPointerId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getPressure"
return="float"
abstract="false"
@@ -138850,6 +143813,19 @@
visibility="public"
>
</method>
+<method name="getPressure"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getRawX"
return="float"
abstract="false"
@@ -138883,6 +143859,19 @@
visibility="public"
>
</method>
+<method name="getSize"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getX"
return="float"
abstract="false"
@@ -138894,6 +143883,19 @@
visibility="public"
>
</method>
+<method name="getX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getXPrecision"
return="float"
abstract="false"
@@ -138916,6 +143918,19 @@
visibility="public"
>
</method>
+<method name="getY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getYPrecision"
return="float"
abstract="false"
@@ -138978,6 +143993,43 @@
</parameter>
<parameter name="action" type="int">
</parameter>
+<parameter name="pointers" type="int">
+</parameter>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="pressure" type="float">
+</parameter>
+<parameter name="size" type="float">
+</parameter>
+<parameter name="metaState" type="int">
+</parameter>
+<parameter name="xPrecision" type="float">
+</parameter>
+<parameter name="yPrecision" type="float">
+</parameter>
+<parameter name="deviceId" type="int">
+</parameter>
+<parameter name="edgeFlags" type="int">
+</parameter>
+</method>
+<method name="obtain"
+ return="android.view.MotionEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="downTime" type="long">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
<parameter name="x" type="float">
</parameter>
<parameter name="y" type="float">
@@ -138998,6 +144050,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"
@@ -139102,6 +144167,17 @@
visibility="public"
>
</field>
+<field name="ACTION_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_MOVE"
type="int"
transient="false"
@@ -139124,6 +144200,116 @@
visibility="public"
>
</field>
+<field name="ACTION_POINTER_1_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_1_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_2_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="261"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_2_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="262"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_3_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="517"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_3_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="518"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_ID_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_ID_SHIFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_UP"
type="int"
transient="false"
@@ -139924,7 +145110,7 @@
value="40"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -139935,7 +145121,7 @@
value="16"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -140285,7 +145471,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -140296,7 +145482,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -149594,6 +154780,28 @@
visibility="public"
>
</field>
+<field name="FLAG_SHOW_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SHOW_WHEN_LOCKED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_TOUCHABLE_WHEN_WAKING"
type="int"
transient="false"
@@ -149689,7 +154897,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -149700,7 +154908,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -150144,6 +155352,17 @@
visibility="public"
>
</field>
+<field name="TYPE_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2013"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="alpha"
type="float"
transient="false"
@@ -156580,6 +161799,27 @@
<parameter name="contentLength" type="long">
</parameter>
</method>
+<method name="onExceededDatabaseQuota"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="databaseIdentifier" type="java.lang.String">
+</parameter>
+<parameter name="currentQuota" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onFormResubmission"
return="void"
abstract="false"
@@ -157401,14 +162641,14 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Plugin"
type="android.webkit.Plugin"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="name" type="java.lang.String">
@@ -157427,7 +162667,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -157440,7 +162680,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157451,7 +162691,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157462,7 +162702,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157473,7 +162713,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157484,7 +162724,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.Plugin.PreferencesClickHandler">
@@ -157497,7 +162737,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="description" type="java.lang.String">
@@ -157510,7 +162750,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="fileName" type="java.lang.String">
@@ -157523,7 +162763,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="name" type="java.lang.String">
@@ -157536,7 +162776,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="path" type="java.lang.String">
@@ -157569,14 +162809,14 @@
abstract="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="PluginData"
type="android.webkit.PluginData"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="stream" type="java.io.InputStream">
@@ -157595,7 +162835,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157606,7 +162846,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157617,7 +162857,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157628,7 +162868,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157638,14 +162878,14 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="PluginList"
type="android.webkit.PluginList"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -157656,7 +162896,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="plugin" type="android.webkit.Plugin">
@@ -157669,7 +162909,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157680,7 +162920,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157691,7 +162931,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -157706,7 +162946,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="plugin" type="android.webkit.Plugin">
@@ -157983,7 +163223,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="getPluginData"
@@ -157993,7 +163233,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -158022,7 +163262,7 @@
abstract="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="UrlInterceptRegistry"
@@ -158040,7 +163280,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -158070,7 +163310,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.UrlInterceptHandler">
@@ -158083,7 +163323,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="disabled" type="boolean">
@@ -158096,7 +163336,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.UrlInterceptHandler">
@@ -158109,7 +163349,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -158221,6 +163461,27 @@
<parameter name="resultMsg" type="android.os.Message">
</parameter>
</method>
+<method name="onExceededDatabaseQuota"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="databaseIdentifier" type="java.lang.String">
+</parameter>
+<parameter name="currentQuota" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onJsAlert"
return="boolean"
abstract="false"
@@ -158606,6 +163867,28 @@
visibility="public"
>
</method>
+<method name="getDatabaseEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDatabasePath"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDefaultFixedFontSize"
return="int"
abstract="false"
@@ -158844,7 +164127,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -158946,6 +164229,32 @@
<parameter name="font" type="java.lang.String">
</parameter>
</method>
+<method name="setDatabaseEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
+<method name="setDatabasePath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="databasePath" type="java.lang.String">
+</parameter>
+</method>
<method name="setDefaultFixedFontSize"
return="void"
abstract="false"
@@ -159278,7 +164587,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="use" type="boolean">
@@ -159500,6 +164809,44 @@
>
</method>
</class>
+<class name="WebStorage"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WebStorage"
+ type="android.webkit.WebStorage"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="WebStorage.QuotaUpdater"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="updateQuota"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newQuota" type="long">
+</parameter>
+</method>
+</interface>
<class name="WebSyncManager"
extends="java.lang.Object"
abstract="true"
@@ -159996,7 +165343,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -160267,7 +165614,7 @@
visibility="public"
>
</method>
-<method name="refreshPlugins"
+<method name="postUrl"
return="void"
abstract="false"
native="false"
@@ -160277,6 +165624,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="postData" type="byte[]">
+</parameter>
+</method>
+<method name="refreshPlugins"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
<parameter name="reloadOpenPages" type="boolean">
</parameter>
</method>
@@ -163603,6 +168965,17 @@
visibility="public"
>
</method>
+<method name="getDropDownBackground"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDropDownHeight"
return="int"
abstract="false"
@@ -163614,6 +168987,28 @@
visibility="public"
>
</method>
+<method name="getDropDownHorizontalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownVerticalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDropDownWidth"
return="int"
abstract="false"
@@ -163837,6 +169232,32 @@
<parameter name="id" type="int">
</parameter>
</method>
+<method name="setDropDownBackgroundDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setDropDownBackgroundResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
<method name="setDropDownHeight"
return="void"
abstract="false"
@@ -163850,6 +169271,32 @@
<parameter name="height" type="int">
</parameter>
</method>
+<method name="setDropDownHorizontalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setDropDownVerticalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
<method name="setDropDownWidth"
return="void"
abstract="false"
@@ -173550,6 +178997,30 @@
<parameter name="isExpanded" type="boolean">
</parameter>
</method>
+<method name="getViewBinder"
+ return="android.widget.SimpleCursorTreeAdapter.ViewBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setViewBinder"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewBinder" type="android.widget.SimpleCursorTreeAdapter.ViewBinder">
+</parameter>
+</method>
<method name="setViewImage"
return="void"
abstract="false"
@@ -173565,7 +179036,47 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
+<method name="setViewText"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="java.lang.String">
+</parameter>
+</method>
</class>
+<interface name="SimpleCursorTreeAdapter.ViewBinder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="setViewValue"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+</interface>
<class name="SimpleExpandableListAdapter"
extends="android.widget.BaseExpandableListAdapter"
abstract="false"
@@ -178497,6 +184008,211 @@
</parameter>
</method>
</class>
+<class name="ZoomButtonsController"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.View.OnTouchListener">
+</implements>
+<constructor name="ZoomButtonsController"
+ type="android.widget.ZoomButtonsController"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ownerView" type="android.view.View">
+</parameter>
+</constructor>
+<method name="getContainer"
+ return="android.view.ViewGroup"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getZoomControls"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isAutoDismissed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isVisible"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onTouch"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+<parameter name="event" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="setAutoDismissed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="autoDismiss" type="boolean">
+</parameter>
+</method>
+<method name="setFocusable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="focusable" type="boolean">
+</parameter>
+</method>
+<method name="setOnZoomListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.ZoomButtonsController.OnZoomListener">
+</parameter>
+</method>
+<method name="setVisible"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="visible" type="boolean">
+</parameter>
+</method>
+<method name="setZoomInEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
+<method name="setZoomOutEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
+<method name="setZoomSpeed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="speed" type="long">
+</parameter>
+</method>
+</class>
+<interface name="ZoomButtonsController.OnZoomListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onVisibilityChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="visible" type="boolean">
+</parameter>
+</method>
+<method name="onZoom"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="zoomIn" type="boolean">
+</parameter>
+</method>
+</interface>
<class name="ZoomControls"
extends="android.widget.LinearLayout"
abstract="false"
@@ -186305,7 +192021,7 @@
<method name="valid"
return="boolean"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -191428,7 +197144,7 @@
return="java.nio.channels.FileChannel"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="false"
final="true"
deprecated="not deprecated"
@@ -200298,7 +206014,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="i" type="int">
+<parameter name="value" type="int">
</parameter>
</method>
<method name="toString"
@@ -201098,10 +206814,10 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="y" type="double">
-</parameter>
<parameter name="x" type="double">
</parameter>
+<parameter name="y" type="double">
+</parameter>
</method>
<method name="cbrt"
return="double"
@@ -266458,7 +272174,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266471,7 +272187,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266482,7 +272198,7 @@
return="int"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266517,7 +272233,7 @@
return="boolean"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266552,7 +272268,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -268897,7 +274613,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -269353,24 +275069,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="isDaemon" type="boolean">
-</parameter>
-</constructor>
-<constructor name="Timer"
- type="java.util.Timer"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<constructor name="Timer"
- type="java.util.Timer"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
<parameter name="name" type="java.lang.String">
</parameter>
<parameter name="isDaemon" type="boolean">
@@ -269386,6 +275084,24 @@
<parameter name="name" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="Timer"
+ type="java.util.Timer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="isDaemon" type="boolean">
+</parameter>
+</constructor>
+<constructor name="Timer"
+ type="java.util.Timer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="cancel"
return="void"
abstract="false"
@@ -270263,7 +275979,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -270743,7 +276459,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -270756,7 +276472,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -270814,7 +276530,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -270874,7 +276590,20 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="drainTo"
@@ -270915,7 +276644,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -270928,7 +276657,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -270964,7 +276693,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -270980,6 +276709,19 @@
visibility="public"
>
</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="take"
return="E"
abstract="true"
@@ -271197,7 +276939,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="java.util.Map<? extends K, ? extends V>">
+<parameter name="m" type="java.util.Map<? extends K, ? extends V>">
</parameter>
</constructor>
<method name="contains"
@@ -271360,7 +277102,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -271510,7 +277252,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="array" type="E[]">
+<parameter name="toCopyIn" type="E[]">
</parameter>
</constructor>
<method name="add"
@@ -271538,7 +277280,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="addAll"
@@ -271666,9 +277408,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="indexOf"
@@ -271681,7 +277421,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="isEmpty"
@@ -271716,9 +277458,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="lastIndexOf"
@@ -271731,7 +277471,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="listIterator"
@@ -271822,7 +277564,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="size"
@@ -272186,7 +277928,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -272199,7 +277941,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -272227,12 +277969,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="time" type="long">
-</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
-</parameter>
-<exception name="InterruptedException" type="java.lang.InterruptedException">
-</exception>
</method>
<method name="poll"
return="E"
@@ -272244,6 +277980,12 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
</method>
<method name="put"
return="void"
@@ -272255,7 +277997,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -273326,7 +279068,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -273345,7 +279087,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -273397,7 +279139,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -273550,7 +279292,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -273563,7 +279305,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -273619,7 +279361,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -274349,7 +280091,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -275054,7 +280796,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -275068,9 +280810,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="long">
+<parameter name="sourceDuration" type="long">
</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
+<parameter name="sourceUnit" type="java.util.concurrent.TimeUnit">
</parameter>
</method>
<method name="sleep"
@@ -277106,12 +282848,55 @@
</package>
<package name="java.util.concurrent.locks"
>
-<class name="AbstractQueuedSynchronizer"
+<class name="AbstractOwnableSynchronizer"
extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
+ visibility=""
+>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractOwnableSynchronizer"
+ type="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="getExclusiveOwnerThread"
+ return="java.lang.Thread"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="setExclusiveOwnerThread"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="t" type="java.lang.Thread">
+</parameter>
+</method>
+</class>
+<class name="AbstractQueuedSynchronizer"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
visibility="public"
>
<implements name="java.io.Serializable">
@@ -284679,7 +290464,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="val" type="int">
+<parameter name="buf" type="byte[]">
+</parameter>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="nbytes" type="int">
</parameter>
</method>
<method name="update"
@@ -284692,11 +290481,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="off" type="int">
-</parameter>
-<parameter name="nbytes" type="int">
+<parameter name="val" type="int">
</parameter>
</method>
</interface>
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index 96cc512..ecaebff 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -25,6 +25,10 @@
LOCAL_MODULE:= libcamerastub
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
+
LOCAL_SHARED_LIBRARIES:= libui
include $(BUILD_STATIC_LIBRARY)
@@ -42,12 +46,17 @@
LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
+ libbinder \
libcutils \
libmedia
LOCAL_MODULE:= libcameraservice
-LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
+LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\"
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
ifeq ($(USE_CAMERA_STUB), true)
LOCAL_STATIC_LIBRARIES += libcamerastub
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index a7af57c..24496bb 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -33,13 +33,11 @@
mRawHeap(0),
mFakeCamera(0),
mPreviewFrameSize(0),
- mRawPictureCallback(0),
- mJpegPictureCallback(0),
- mPictureCallbackCookie(0),
- mPreviewCallback(0),
- mPreviewCallbackCookie(0),
- mAutoFocusCallback(0),
- mAutoFocusCallbackCookie(0),
+ mNotifyCb(0),
+ mDataCb(0),
+ mDataCbTimestamp(0),
+ mCallbackCookie(0),
+ mMsgEnabled(0),
mCurrentPreviewFrame(0)
{
initDefaultParameters();
@@ -112,6 +110,36 @@
return mRawHeap;
}
+void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+{
+ Mutex::Autolock lock(mLock);
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCallbackCookie = user;
+}
+
+void CameraHardwareStub::enableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled |= msgType;
+}
+
+void CameraHardwareStub::disableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled &= ~msgType;
+}
+
+bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ return (mMsgEnabled & msgType);
+}
+
// ---------------------------------------------------------------------------
int CameraHardwareStub::previewThread()
@@ -150,7 +178,8 @@
//LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
// Notify the client of a new frame.
- mPreviewCallback(buffer, mPreviewCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
+ mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
// Advance the buffer pointer.
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
@@ -162,15 +191,13 @@
return NO_ERROR;
}
-status_t CameraHardwareStub::startPreview(preview_callback cb, void* user)
+status_t CameraHardwareStub::startPreview()
{
Mutex::Autolock lock(mLock);
if (mPreviewThread != 0) {
// already running
return INVALID_OPERATION;
}
- mPreviewCallback = cb;
- mPreviewCallbackCookie = user;
mPreviewThread = new PreviewThread(this);
return NO_ERROR;
}
@@ -197,7 +224,7 @@
return mPreviewThread != 0;
}
-status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+status_t CameraHardwareStub::startRecording()
{
return UNKNOWN_ERROR;
}
@@ -225,25 +252,14 @@
int CameraHardwareStub::autoFocusThread()
{
- if (mAutoFocusCallback != NULL) {
- mAutoFocusCallback(true, mAutoFocusCallbackCookie);
- mAutoFocusCallback = NULL;
- return NO_ERROR;
- }
- return UNKNOWN_ERROR;
+ if (mMsgEnabled & CAMERA_MSG_FOCUS)
+ mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
+ return NO_ERROR;
}
-status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
- void *user)
+status_t CameraHardwareStub::autoFocus()
{
Mutex::Autolock lock(mLock);
-
- if (mAutoFocusCallback != NULL) {
- return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
- }
-
- mAutoFocusCallback = af_cb;
- mAutoFocusCallbackCookie = user;
if (createThread(beginAutoFocusThread, this) == false)
return UNKNOWN_ERROR;
return NO_ERROR;
@@ -257,10 +273,10 @@
int CameraHardwareStub::pictureThread()
{
- if (mShutterCallback)
- mShutterCallback(mPictureCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_SHUTTER)
+ mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
- if (mRawPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
//FIXME: use a canned YUV image!
// In the meantime just make another fake camera picture.
int w, h;
@@ -268,42 +284,28 @@
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
FakeCamera cam(w, h);
cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
- if (mRawPictureCallback)
- mRawPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
}
- if (mJpegPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
- if (mJpegPictureCallback)
- mJpegPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
}
return NO_ERROR;
}
-status_t CameraHardwareStub::takePicture(shutter_callback shutter_cb,
- raw_callback raw_cb,
- jpeg_callback jpeg_cb,
- void* user)
+status_t CameraHardwareStub::takePicture()
{
stopPreview();
- mShutterCallback = shutter_cb;
- mRawPictureCallback = raw_cb;
- mJpegPictureCallback = jpeg_cb;
- mPictureCallbackCookie = user;
if (createThread(beginPictureThread, this) == false)
return -1;
return NO_ERROR;
}
-status_t CameraHardwareStub::cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg)
+status_t CameraHardwareStub::cancelPicture()
{
- if (cancel_shutter) mShutterCallback = NULL;
- if (cancel_raw) mRawPictureCallback = NULL;
- if (cancel_jpeg) mJpegPictureCallback = NULL;
return NO_ERROR;
}
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 0d26d47..000906a 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -21,8 +21,8 @@
#include "FakeCamera.h"
#include <utils/threads.h>
#include <ui/CameraHardwareInterface.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <utils/threads.h>
namespace android {
@@ -32,23 +32,27 @@
virtual sp<IMemoryHeap> getPreviewHeap() const;
virtual sp<IMemoryHeap> getRawHeap() const;
- virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user);
+
+ virtual void enableMsgType(int32_t msgType);
+ virtual void disableMsgType(int32_t msgType);
+ virtual bool msgTypeEnabled(int32_t msgType);
+
+ virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t startRecording(recording_callback cb, void* user);
+ virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
- virtual status_t autoFocus(autofocus_callback, void *user);
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user);
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg);
+ virtual status_t autoFocus();
+ virtual status_t takePicture();
+ virtual status_t cancelPicture();
virtual status_t dump(int fd, const Vector<String16>& args) const;
virtual status_t setParameters(const CameraParameters& params);
virtual CameraParameters getParameters() const;
@@ -67,8 +71,15 @@
class PreviewThread : public Thread {
CameraHardwareStub* mHardware;
public:
- PreviewThread(CameraHardwareStub* hw)
- : Thread(false), mHardware(hw) { }
+ PreviewThread(CameraHardwareStub* hw) :
+#ifdef SINGLE_PROCESS
+ // In single process mode this thread needs to be a java thread,
+ // since we won't be calling through the binder.
+ Thread(true),
+#else
+ Thread(false),
+#endif
+ mHardware(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
@@ -102,18 +113,15 @@
bool mPreviewRunning;
int mPreviewFrameSize;
- shutter_callback mShutterCallback;
- raw_callback mRawPictureCallback;
- jpeg_callback mJpegPictureCallback;
- void *mPictureCallbackCookie;
-
// protected by mLock
sp<PreviewThread> mPreviewThread;
- preview_callback mPreviewCallback;
- void *mPreviewCallbackCookie;
- autofocus_callback mAutoFocusCallback;
- void *mAutoFocusCallbackCookie;
+ notify_callback mNotifyCb;
+ data_callback mDataCb;
+ data_callback_timestamp mDataCbTimestamp;
+ void *mCallbackCookie;
+
+ int32_t mMsgEnabled;
// only used from PreviewThread
int mCurrentPreviewFrame;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index e4b6791..e66b00f 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -20,12 +20,12 @@
#define LOG_TAG "CameraService"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/Errors.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/ICameraService.h>
#include <media/mediaplayer.h>
@@ -33,7 +33,6 @@
#include "CameraService.h"
#include <cutils/atomic.h>
-#include <cutils/properties.h>
namespace android {
@@ -60,6 +59,7 @@
#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
+#define DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE 0
#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
static int debug_frame_cnt;
@@ -199,13 +199,7 @@
{
sp<MediaPlayer> mp = new MediaPlayer();
if (mp->setDataSource(file) == NO_ERROR) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (atoi(value)) {
- mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
- } else {
- mp->setAudioStreamType(AudioSystem::SYSTEM);
- }
+ mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
mp->prepare();
} else {
mp.clear();
@@ -225,8 +219,20 @@
mHardware = openCameraHardware();
mUseOverlay = mHardware->useOverlay();
+ mHardware->setCallbacks(notifyCallback,
+ dataCallback,
+ dataCallbackTimestamp,
+ mCameraService.get());
+
+ // Enable zoom, error, and focus messages by default
+ mHardware->enableMsgType(CAMERA_MSG_ERROR |
+ CAMERA_MSG_ZOOM |
+ CAMERA_MSG_FOCUS);
+
mMediaPlayerClick = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
mMediaPlayerBeep = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+ mOverlayW = 0;
+ mOverlayH = 0;
// Callback is disabled by default
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
@@ -396,9 +402,20 @@
// idle state.
mHardware->stopPreview();
// Cancel all picture callbacks.
- mHardware->cancelPicture(true, true, true);
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+ mHardware->cancelPicture();
+ // Turn off remaining messages.
+ mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
// Release the hardware resources.
mHardware->release();
+ // Release the held overlay resources.
+ if (mUseOverlay)
+ {
+ mOverlayRef = 0;
+ }
mHardware.clear();
mCameraService->removeClient(mCameraClient);
@@ -420,11 +437,21 @@
result = NO_ERROR;
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() != mSurface->asBinder()) {
- if (mSurface != 0 && !mUseOverlay) {
+ if (mSurface != 0) {
LOGD("clearing old preview surface %p", mSurface.get());
- mSurface->unregisterBuffers();
+ if ( !mUseOverlay)
+ {
+ mSurface->unregisterBuffers();
+ }
+ else
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ }
}
mSurface = surface;
+ mOverlayRef = 0;
// If preview has been already started, set overlay or register preview
// buffers now.
if (mHardware->previewEnabled()) {
@@ -446,6 +473,13 @@
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
+
+ if(mUseOverlay) {
+ if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ else
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
}
// start preview mode
@@ -504,7 +538,7 @@
}
// start recording mode
- ret = mHardware->startRecording(recordingCallback, mCameraService.get());
+ ret = mHardware->startRecording();
if (ret != NO_ERROR) {
LOGE("mHardware->startRecording() failed with status %d", ret);
}
@@ -520,8 +554,8 @@
const char *format = params.getPreviewFormat();
int fmt;
- if (!strcmp(format, "yuv422i"))
- fmt = OVERLAY_FORMAT_YCbCr_422_I;
+ if (!strcmp(format, "yuv422i-yuyv"))
+ fmt = OVERLAY_FORMAT_YCbYCr_422_I;
else if (!strcmp(format, "rgb565"))
fmt = OVERLAY_FORMAT_RGB_565;
else {
@@ -529,16 +563,35 @@
return -EINVAL;
}
+ if ( w != mOverlayW || h != mOverlayH )
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ mOverlayRef = 0;
+ }
+
status_t ret = NO_ERROR;
if (mSurface != 0) {
- sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
- ret = mHardware->setOverlay(new Overlay(ref));
+ if (mOverlayRef.get() == NULL) {
+ mOverlayRef = mSurface->createOverlay(w, h, fmt);
+ if ( mOverlayRef.get() == NULL )
+ {
+ LOGE("Overlay Creation Failed!");
+ return -EINVAL;
+ }
+ ret = mHardware->setOverlay(new Overlay(mOverlayRef));
+ }
} else {
ret = mHardware->setOverlay(NULL);
}
if (ret != NO_ERROR) {
LOGE("mHardware->setOverlay() failed with status %d\n", ret);
}
+
+ mOverlayW = w;
+ mOverlayH = h;
+
return ret;
}
@@ -588,10 +641,10 @@
ret = setOverlay();
}
if (ret != NO_ERROR) return ret;
- ret = mHardware->startPreview(NULL, mCameraService.get());
+ ret = mHardware->startPreview();
} else {
- ret = mHardware->startPreview(previewCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ ret = mHardware->startPreview();
if (ret != NO_ERROR) return ret;
// If preview display has been set, register preview buffers now.
if (mSurface != 0) {
@@ -618,6 +671,9 @@
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
}
+
+ mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+
return startCameraMode(CAMERA_RECORDING_MODE);
}
@@ -635,6 +691,7 @@
}
mHardware->stopPreview();
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
LOGD("stopPreview(), hardware stopped OK");
if (mSurface != 0 && !mUseOverlay) {
@@ -660,8 +717,11 @@
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
}
+
mHardware->stopRecording();
+ mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
LOGD("stopRecording(), hardware stopped OK");
+
mPreviewBuffer.clear();
}
@@ -749,65 +809,6 @@
}
#endif
-// preview callback - frame buffer update
-void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
-{
- LOGV("previewCallback()");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
-#if DEBUG_HEAP_LEAKS && 0 // debugging
- if (gWeakHeap == NULL) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (gWeakHeap != heap) {
- LOGD("SETTING PREVIEW HEAP");
- heap->trackMe(true, true);
- gWeakHeap = heap;
- }
- }
-#endif
-
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
- {
- if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- dump_to_file("/data/preview.yuv",
- (uint8_t *)heap->base() + offset, size);
- }
- }
-#endif
-
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postPreviewFrame(mem);
-
-#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
- if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
- client->printRefs();
- }
-#endif
-}
-
-// recording callback
-void CameraService::Client::recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user)
-{
- LOGV("recordingCallback");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postRecordingFrame(timestamp, mem);
-}
-
// take a picture - image is returned in callback
status_t CameraService::Client::autoFocus()
{
@@ -822,8 +823,7 @@
return INVALID_OPERATION;
}
- return mHardware->autoFocus(autoFocusCallback,
- mCameraService.get());
+ return mHardware->autoFocus();
}
// take a picture - image is returned in callback
@@ -840,38 +840,36 @@
return INVALID_OPERATION;
}
- return mHardware->takePicture(shutterCallback,
- yuvPictureCallback,
- jpegPictureCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+
+ return mHardware->takePicture();
}
-// picture callback - snapshot taken
-void CameraService::Client::shutterCallback(void *user)
+// snapshot taken
+void CameraService::Client::handleShutter()
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
// Play shutter sound.
- if (client->mMediaPlayerClick.get() != NULL) {
- client->mMediaPlayerClick->seekTo(0);
- client->mMediaPlayerClick->start();
+ if (mMediaPlayerClick.get() != NULL) {
+ mMediaPlayerClick->seekTo(0);
+ mMediaPlayerClick->start();
}
// Screen goes black after the buffer is unregistered.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->unregisterBuffers();
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->unregisterBuffers();
}
- client->postShutter();
+ mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
// It takes some time before yuvPicture callback to be called.
// Register the buffer for raw image here to reduce latency.
- if (client->mSurface != 0 && !client->mUseOverlay) {
+ if (mSurface != 0 && !mUseOverlay) {
int w, h;
- CameraParameters params(client->mHardware->getParameters());
+ CameraParameters params(mHardware->getParameters());
params.getPictureSize(&w, &h);
uint32_t transform = 0;
if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
@@ -879,26 +877,92 @@
transform = ISurface::BufferHeap::ROT_90;
}
ISurface::BufferHeap buffers(w, h, w, h,
- PIXEL_FORMAT_YCbCr_420_SP, transform, 0, client->mHardware->getRawHeap());
+ PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap());
- client->mSurface->registerBuffers(buffers);
+ mSurface->registerBuffers(buffers);
}
}
-// picture callback - raw image ready
-void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
- void *user)
+// preview callback - frame buffer update
+void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+ if (gWeakHeap == NULL) {
+ if (gWeakHeap != heap) {
+ LOGD("SETTING PREVIEW HEAP");
+ heap->trackMe(true, true);
+ gWeakHeap = heap;
+ }
}
- if (mem == NULL) {
- client->postRaw(NULL);
- client->postError(UNKNOWN_ERROR);
+#endif
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+ {
+ if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
+ dump_to_file("/data/preview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+ }
+#endif
+
+ if (!mUseOverlay)
+ {
+ Mutex::Autolock surfaceLock(mSurfaceLock);
+ if (mSurface != NULL) {
+ mSurface->postBuffer(offset);
+ }
+ }
+
+ // Is the callback enabled or not?
+ if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ // If the enable bit is off, the copy-out and one-shot bits are ignored
+ LOGV("frame callback is diabled");
return;
}
+ // Is the received frame copied out or not?
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ LOGV("frame is copied out");
+ copyFrameAndPostCopiedFrame(heap, offset, size);
+ } else {
+ LOGV("frame is directly sent out without copying");
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
+ }
+
+ // Is this is one-shot only?
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+ LOGV("One-shot only, thus clear the bits and disable frame callback");
+ mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ if (mUseOverlay)
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
+}
+
+// picture callback - postview image ready
+void CameraService::Client::handlePostview(const sp<IMemory>& mem)
+{
+#if DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/postview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+#endif
+
+ mCameraClient->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
+ mHardware->disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+}
+
+// picture callback - raw image ready
+void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)
+{
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -906,44 +970,24 @@
gWeakHeap = heap; // debugging
#endif
- //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
+ //LOGV("handleRawPicture(%d, %d)", offset, size);
#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
dump_to_file("/data/photo.yuv",
(uint8_t *)heap->base() + offset, size);
#endif
// Put the YUV version of the snapshot in the preview display.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->postBuffer(offset);
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->postBuffer(offset);
}
- client->postRaw(mem);
-
-#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
- if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
- client->printRefs();
- }
-#endif
+ mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
+ mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);
}
-// picture callback - jpeg ready
-void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
+// picture callback - compressed picture ready
+void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem)
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
- if (mem == NULL) {
- client->postJpeg(NULL);
- client->postError(UNKNOWN_ERROR);
- return;
- }
-
- /** We absolutely CANNOT call into user code with a lock held **/
-
#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
{
ssize_t offset;
@@ -954,32 +998,100 @@
}
#endif
- client->postJpeg(mem);
-
-#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
- if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
- client->printRefs();
- }
-#endif
+ mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
+ mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
}
-void CameraService::Client::autoFocusCallback(bool focused, void *user)
+void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user)
{
- LOGV("autoFocusCallback");
+ LOGV("notifyCallback(%d)", msgType);
sp<Client> client = getClientFromCookie(user);
if (client == 0) {
return;
}
- client->postAutoFocus(focused);
+ switch (msgType) {
+ case CAMERA_MSG_SHUTTER:
+ client->handleShutter();
+ break;
+ default:
+ client->mCameraClient->notifyCallback(msgType, ext1, ext2);
+ break;
+ }
#if DEBUG_CLIENT_REFERENCES
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (NOTIFY CALLBACK) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user)
+{
+ LOGV("dataCallback(%d)", msgType);
+
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data callback");
+ client->mCameraClient->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ client->mCameraClient->dataCallback(msgType, NULL);
+ return;
+ }
+
+ switch (msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ client->handlePreviewData(dataPtr);
+ break;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ client->handlePostview(dataPtr);
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ client->handleRawPicture(dataPtr);
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ client->handleCompressedPicture(dataPtr);
+ break;
+ default:
+ client->mCameraClient->dataCallback(msgType, dataPtr);
+ break;
+ }
+
+#if DEBUG_CLIENT_REFERENCES
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");
+ client->printRefs();
+ }
+#endif
+}
+
+void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user)
+{
+ LOGV("dataCallbackTimestamp(%d)", msgType);
+
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data with timestamp callback");
+ client->mCameraClient->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ client->mCameraClient->dataCallbackTimestamp(0, msgType, NULL);
+ return;
+ }
+
+ client->mCameraClient->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+
+#if DEBUG_CLIENT_REFERENCES
+ if (client->getStrongCount() == 1) {
+ LOGE("++++++++++++++++ (DATA CALLBACK TIMESTAMP) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
@@ -1019,30 +1131,6 @@
return params;
}
-void CameraService::Client::postAutoFocus(bool focused)
-{
- LOGV("postAutoFocus");
- mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0);
-}
-
-void CameraService::Client::postShutter()
-{
- LOGD("postShutter");
- mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
-}
-
-void CameraService::Client::postRaw(const sp<IMemory>& mem)
-{
- LOGD("postRaw");
- mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
-}
-
-void CameraService::Client::postJpeg(const sp<IMemory>& mem)
-{
- LOGD("postJpeg");
- mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
-}
-
void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
{
LOGV("copyFrameAndPostCopiedFrame");
@@ -1071,64 +1159,6 @@
mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
}
-void CameraService::Client::postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame)
-{
- LOGV("postRecordingFrame");
- if (frame == 0) {
- LOGW("frame is a null pointer");
- return;
- }
- mCameraClient->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, frame);
-}
-
-void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
-{
- LOGV("postPreviewFrame");
- if (mem == 0) {
- LOGW("mem is a null pointer");
- return;
- }
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- {
- Mutex::Autolock surfaceLock(mSurfaceLock);
- if (mSurface != NULL) {
- mSurface->postBuffer(offset);
- }
- }
-
- // Is the callback enabled or not?
- if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
- // If the enable bit is off, the copy-out and one-shot bits are ignored
- LOGV("frame callback is diabled");
- return;
- }
-
- // Is the received frame copied out or not?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
- LOGV("frame is copied out");
- copyFrameAndPostCopiedFrame(heap, offset, size);
- } else {
- LOGV("frame is directly sent out without copying");
- mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
- }
-
- // Is this is one-shot only?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
- LOGV("One-shot only, thus clear the bits and disable frame callback");
- mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- FRAME_CALLBACK_FLAG_ENABLE_MASK);
- }
-}
-
-void CameraService::Client::postError(status_t error)
-{
- mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0);
-}
-
status_t CameraService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -1160,12 +1190,6 @@
}
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t CameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index ea93789..f8c7216 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -132,22 +132,20 @@
status_t checkPid();
- static void recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
- static void previewCallback(const sp<IMemory>& mem, void* user);
- static void shutterCallback(void *user);
- static void yuvPictureCallback(const sp<IMemory>& mem, void* user);
- static void jpegPictureCallback(const sp<IMemory>& mem, void* user);
- static void autoFocusCallback(bool focused, void* user);
+ static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+ static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+ static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user);
+
static sp<Client> getClientFromCookie(void* user);
- void postShutter();
- void postRaw(const sp<IMemory>& mem);
- void postJpeg(const sp<IMemory>& mem);
- void postPreviewFrame(const sp<IMemory>& mem);
- void postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame);
+ void handlePreviewData(const sp<IMemory>&);
+ void handleShutter();
+ void handlePostview(const sp<IMemory>&);
+ void handleRawPicture(const sp<IMemory>&);
+ void handleCompressedPicture(const sp<IMemory>&);
+
void copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
- void postError(status_t error);
- void postAutoFocus(bool focused);
// camera operation mode
enum camera_mode {
@@ -189,6 +187,10 @@
sp<CameraHardwareInterface> mHardware;
pid_t mClientPid;
bool mUseOverlay;
+
+ sp<OverlayRef> mOverlayRef;
+ int mOverlayW;
+ int mOverlayH;
};
// ----------------------------------------------------------------------------
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3782136..0b4f25e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -23,16 +23,19 @@
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.AndroidException;
import android.view.IWindowManager;
import java.io.File;
import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Set;
@@ -45,16 +48,29 @@
private boolean mDebugOption = false;
+ // These are magic strings understood by the Eclipse plugin.
+ private static final String FATAL_ERROR_CODE = "Error type 1";
+ private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
+ private static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
/**
* Command-line entry point.
*
* @param args The command-line arguments
*/
public static void main(String[] args) {
- (new Am()).run(args);
+ try {
+ (new Am()).run(args);
+ } catch (IllegalArgumentException e) {
+ showUsage();
+ System.err.println("Error: " + e.getMessage());
+ } catch (Exception e) {
+ System.err.println(e.toString());
+ System.exit(1);
+ }
}
- private void run(String[] args) {
+ private void run(String[] args) throws Exception {
if (args.length < 1) {
showUsage();
return;
@@ -62,16 +78,14 @@
mAm = ActivityManagerNative.getDefault();
if (mAm == null) {
- System.err.println("Error type 2");
- System.err.println("Error: Unable to connect to activity manager; is the system running?");
- showUsage();
- return;
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to activity manager; is the system running?");
}
mArgs = args;
-
String op = args[0];
mNextArg = 1;
+
if (op.equals("start")) {
runStart();
} else if (op.equals("instrument")) {
@@ -81,13 +95,11 @@
} else if (op.equals("profile")) {
runProfile();
} else {
- System.err.println("Error: Unknown command: " + op);
- showUsage();
- return;
+ throw new IllegalArgumentException("Unknown command: " + op);
}
}
- private Intent makeIntent() {
+ private Intent makeIntent() throws URISyntaxException {
Intent intent = new Intent();
boolean hasIntentInfo = false;
@@ -95,186 +107,146 @@
Uri data = null;
String type = null;
- try {
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-a")) {
- intent.setAction(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-d")) {
- data = Uri.parse(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-t")) {
- type = nextOptionData();
- hasIntentInfo = true;
- } else if (opt.equals("-c")) {
- intent.addCategory(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-e") || opt.equals("--es")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, value);
- hasIntentInfo = true;
- } else if (opt.equals("--ei")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, Integer.valueOf(value));
- hasIntentInfo = true;
- } else if (opt.equals("--ez")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, Boolean.valueOf(value));
- hasIntentInfo = true;
- } else if (opt.equals("-n")) {
- String str = nextOptionData();
- ComponentName cn = ComponentName.unflattenFromString(str);
- if (cn == null) {
- System.err.println("Error: Bad component name: " + str);
- showUsage();
- return null;
- }
- intent.setComponent(cn);
- hasIntentInfo = true;
- } else if (opt.equals("-f")) {
- String str = nextOptionData();
- intent.setFlags(Integer.decode(str).intValue());
- } else if (opt.equals("-D")) {
- mDebugOption = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- showUsage();
- return null;
- }
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-a")) {
+ intent.setAction(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-d")) {
+ data = Uri.parse(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-t")) {
+ type = nextArgRequired();
+ hasIntentInfo = true;
+ } else if (opt.equals("-c")) {
+ intent.addCategory(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-e") || opt.equals("--es")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, value);
+ hasIntentInfo = true;
+ } else if (opt.equals("--ei")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Integer.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("--ez")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Boolean.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("-n")) {
+ String str = nextArgRequired();
+ ComponentName cn = ComponentName.unflattenFromString(str);
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
+ intent.setComponent(cn);
+ hasIntentInfo = true;
+ } else if (opt.equals("-f")) {
+ String str = nextArgRequired();
+ intent.setFlags(Integer.decode(str).intValue());
+ } else if (opt.equals("-D")) {
+ mDebugOption = true;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ showUsage();
+ return null;
}
- } catch (RuntimeException ex) {
- System.err.println("Error: " + ex.toString());
- showUsage();
- return null;
}
intent.setDataAndType(data, type);
String uri = nextArg();
if (uri != null) {
- try {
- Intent oldIntent = intent;
- try {
- intent = Intent.getIntent(uri);
- } catch (java.net.URISyntaxException ex) {
- System.err.println("Bad URI: " + uri);
- showUsage();
- return null;
- }
- if (oldIntent.getAction() != null) {
- intent.setAction(oldIntent.getAction());
- }
- if (oldIntent.getData() != null || oldIntent.getType() != null) {
- intent.setDataAndType(oldIntent.getData(), oldIntent.getType());
- }
- Set cats = oldIntent.getCategories();
- if (cats != null) {
- Iterator it = cats.iterator();
- while (it.hasNext()) {
- intent.addCategory((String)it.next());
- }
- }
- } catch (RuntimeException ex) {
- System.err.println("Error creating from URI: " + ex.toString());
- showUsage();
- return null;
+ Intent oldIntent = intent;
+ intent = Intent.getIntent(uri);
+ if (oldIntent.getAction() != null) {
+ intent.setAction(oldIntent.getAction());
}
- } else if (!hasIntentInfo) {
- System.err.println("Error: No intent supplied");
- showUsage();
- return null;
+ if (oldIntent.getData() != null || oldIntent.getType() != null) {
+ intent.setDataAndType(oldIntent.getData(), oldIntent.getType());
+ }
+ Set cats = oldIntent.getCategories();
+ if (cats != null) {
+ Iterator it = cats.iterator();
+ while (it.hasNext()) {
+ intent.addCategory((String)it.next());
+ }
+ }
+ hasIntentInfo = true;
}
+ if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
return intent;
}
- private void runStart() {
+ private void runStart() throws Exception {
Intent intent = makeIntent();
-
- if (intent != null) {
- System.out.println("Starting: " + intent);
- try {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // XXX should do something to determine the MIME type.
- int res = mAm.startActivity(null, intent, intent.getType(),
- null, 0, null, null, 0, false, mDebugOption);
- switch (res) {
- case IActivityManager.START_SUCCESS:
- break;
- case IActivityManager.START_SWITCHES_CANCELED:
- System.err.println(
- "Warning: Activity not started because the "
- + " current activity is being kept for the user.");
- break;
- case IActivityManager.START_DELIVERED_TO_TOP:
- System.err.println(
- "Warning: Activity not started, intent has "
- + "been delivered to currently running "
- + "top-most instance.");
- break;
- case IActivityManager.START_RETURN_INTENT_TO_CALLER:
- System.err.println(
- "Warning: Activity not started because intent "
- + "should be handled by the caller");
- break;
- case IActivityManager.START_TASK_TO_FRONT:
- System.err.println(
- "Warning: Activity not started, its current "
- + "task has been brought to the front");
- break;
- case IActivityManager.START_INTENT_NOT_RESOLVED:
- System.err.println(
- "Error: Activity not started, unable to "
- + "resolve " + intent.toString());
- break;
- case IActivityManager.START_CLASS_NOT_FOUND:
- System.err.println("Error type 3");
- System.err.println("Error: Activity class " +
- intent.getComponent().toShortString()
- + " does not exist.");
- break;
- case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
- System.err.println(
- "Error: Activity not started, you requested to "
- + "both forward and receive its result");
- break;
- case IActivityManager.START_PERMISSION_DENIED:
- System.err.println(
- "Error: Activity not started, you do not "
- + "have permission to access it.");
- break;
- default:
- System.err.println(
- "Error: Activity not started, unknown error "
- + "code " + res);
- break;
- }
- } catch (RemoteException e) {
- System.err.println("Error type 1");
+ System.out.println("Starting: " + intent);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // XXX should do something to determine the MIME type.
+ int res = mAm.startActivity(null, intent, intent.getType(),
+ null, 0, null, null, 0, false, mDebugOption);
+ switch (res) {
+ case IActivityManager.START_SUCCESS:
+ break;
+ case IActivityManager.START_SWITCHES_CANCELED:
+ System.err.println(
+ "Warning: Activity not started because the "
+ + " current activity is being kept for the user.");
+ break;
+ case IActivityManager.START_DELIVERED_TO_TOP:
+ System.err.println(
+ "Warning: Activity not started, intent has "
+ + "been delivered to currently running "
+ + "top-most instance.");
+ break;
+ case IActivityManager.START_RETURN_INTENT_TO_CALLER:
+ System.err.println(
+ "Warning: Activity not started because intent "
+ + "should be handled by the caller");
+ break;
+ case IActivityManager.START_TASK_TO_FRONT:
+ System.err.println(
+ "Warning: Activity not started, its current "
+ + "task has been brought to the front");
+ break;
+ case IActivityManager.START_INTENT_NOT_RESOLVED:
System.err.println(
"Error: Activity not started, unable to "
- + "call on to activity manager service");
- }
+ + "resolve " + intent.toString());
+ break;
+ case IActivityManager.START_CLASS_NOT_FOUND:
+ System.err.println(NO_CLASS_ERROR_CODE);
+ System.err.println("Error: Activity class " +
+ intent.getComponent().toShortString()
+ + " does not exist.");
+ break;
+ case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
+ System.err.println(
+ "Error: Activity not started, you requested to "
+ + "both forward and receive its result");
+ break;
+ case IActivityManager.START_PERMISSION_DENIED:
+ System.err.println(
+ "Error: Activity not started, you do not "
+ + "have permission to access it.");
+ break;
+ default:
+ System.err.println(
+ "Error: Activity not started, unknown error code " + res);
+ break;
}
}
- private void sendBroadcast() {
+ private void sendBroadcast() throws Exception {
Intent intent = makeIntent();
-
- if (intent != null) {
- System.out.println("Broadcasting: " + intent);
- try {
- mAm.broadcastIntent(null, intent, null, null, 0, null, null,
- null, true, false);
- } catch (RemoteException e) {
- }
- }
+ IntentReceiver receiver = new IntentReceiver();
+ System.out.println("Broadcasting: " + intent);
+ mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false);
+ receiver.waitForFinish();
}
- private void runInstrument() {
+ private void runInstrument() throws Exception {
String profileFile = null;
boolean wait = false;
boolean rawMode = false;
@@ -283,46 +255,30 @@
String argKey = null, argValue = null;
IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
- try {
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-p")) {
- profileFile = nextOptionData();
- } else if (opt.equals("-w")) {
- wait = true;
- } else if (opt.equals("-r")) {
- rawMode = true;
- } else if (opt.equals("-e")) {
- argKey = nextOptionData();
- argValue = nextOptionData();
- args.putString(argKey, argValue);
- } else if (opt.equals("--no_window_animation")) {
- no_window_animation = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- showUsage();
- return;
- }
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-p")) {
+ profileFile = nextArgRequired();
+ } else if (opt.equals("-w")) {
+ wait = true;
+ } else if (opt.equals("-r")) {
+ rawMode = true;
+ } else if (opt.equals("-e")) {
+ argKey = nextArgRequired();
+ argValue = nextArgRequired();
+ args.putString(argKey, argValue);
+ } else if (opt.equals("--no_window_animation")) {
+ no_window_animation = true;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ showUsage();
+ return;
}
- } catch (RuntimeException ex) {
- System.err.println("Error: " + ex.toString());
- showUsage();
- return;
}
- String cnArg = nextArg();
- if (cnArg == null) {
- System.err.println("Error: No instrumentation component supplied");
- showUsage();
- return;
- }
-
+ String cnArg = nextArgRequired();
ComponentName cn = ComponentName.unflattenFromString(cnArg);
- if (cn == null) {
- System.err.println("Error: Bad component name: " + cnArg);
- showUsage();
- return;
- }
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
InstrumentationWatcher watcher = null;
if (wait) {
@@ -331,22 +287,13 @@
}
float[] oldAnims = null;
if (no_window_animation) {
- try {
- oldAnims = wm.getAnimationScales();
- wm.setAnimationScale(0, 0.0f);
- wm.setAnimationScale(1, 0.0f);
- } catch (RemoteException e) {
- }
+ oldAnims = wm.getAnimationScales();
+ wm.setAnimationScale(0, 0.0f);
+ wm.setAnimationScale(1, 0.0f);
}
- try {
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
- System.out.println("INSTRUMENTATION_FAILED: " +
- cn.flattenToString());
- showUsage();
- return;
- }
- } catch (RemoteException e) {
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
+ throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
if (watcher != null) {
@@ -356,9 +303,57 @@
}
if (oldAnims != null) {
+ wm.setAnimationScales(oldAnims);
+ }
+ }
+
+ private void runProfile() throws Exception {
+ String profileFile = null;
+ boolean start = false;
+ String process = nextArgRequired();
+ ParcelFileDescriptor fd = null;
+
+ String cmd = nextArgRequired();
+ if ("start".equals(cmd)) {
+ start = true;
+ profileFile = nextArgRequired();
try {
- wm.setAnimationScales(oldAnims);
- } catch (RemoteException e) {
+ fd = ParcelFileDescriptor.open(
+ new File(profileFile),
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ System.err.println("Error: Unable to open file: " + profileFile);
+ return;
+ }
+ } else if (!"stop".equals(cmd)) {
+ throw new IllegalArgumentException("Profile command " + cmd + " not valid");
+ }
+
+ if (!mAm.profileControl(process, start, profileFile, fd)) {
+ throw new AndroidException("PROFILE FAILED on process " + process);
+ }
+ }
+
+ private class IntentReceiver extends IIntentReceiver.Stub {
+ private boolean mFinished = false;
+
+ public synchronized void performReceive(
+ Intent intent, int rc, String data, Bundle ext, boolean ord) {
+ String line = "Broadcast completed: result=" + rc;
+ if (data != null) line = line + ", data=\"" + data + "\"";
+ if (ext != null) line = line + ", extras: " + ext;
+ System.out.println(line);
+ mFinished = true;
+ notifyAll();
+ }
+
+ public synchronized void waitForFinish() {
+ try {
+ while (!mFinished) wait();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -366,7 +361,7 @@
private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
private boolean mFinished = false;
private boolean mRawMode = false;
-
+
/**
* Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode",
* if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
@@ -375,7 +370,7 @@
public void setRawOutput(boolean rawMode) {
mRawMode = rawMode;
}
-
+
public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
synchronized (this) {
// pretty printer mode?
@@ -431,6 +426,7 @@
}
wait(1000);
} catch (InterruptedException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -438,62 +434,11 @@
}
}
- private void runProfile() {
- String profileFile = null;
- boolean start = false;
-
- String process = nextArg();
- if (process == null) {
- System.err.println("Error: No profile process supplied");
- showUsage();
- return;
- }
-
- ParcelFileDescriptor fd = null;
-
- String cmd = nextArg();
- if ("start".equals(cmd)) {
- start = true;
- profileFile = nextArg();
- if (profileFile == null) {
- System.err.println("Error: No profile file path supplied");
- showUsage();
- return;
- }
- try {
- fd = ParcelFileDescriptor.open(
- new File(profileFile),
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
- } catch (FileNotFoundException e) {
- System.err.println("Error: Unable to open file: " + profileFile);
- return;
- }
- } else if (!"stop".equals(cmd)) {
- System.err.println("Error: Profile command " + cmd + " not valid");
- showUsage();
- return;
- }
-
- try {
- if (!mAm.profileControl(process, start, profileFile, fd)) {
- System.err.println("PROFILE FAILED on process " + process);
- return;
- }
- } catch (IllegalArgumentException e) {
- System.out.println("PROFILE FAILED: " + e.getMessage());
- return;
- } catch (IllegalStateException e) {
- System.out.println("PROFILE FAILED: " + e.getMessage());
- return;
- } catch (RemoteException e) {
- System.out.println("PROFILE FAILED: activity manager gone");
- return;
- }
- }
-
private String nextOption() {
+ if (mCurArgData != null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+ }
if (mNextArg >= mArgs.length) {
return null;
}
@@ -518,41 +463,52 @@
return arg;
}
- private String nextOptionData() {
+ private String nextArg() {
if (mCurArgData != null) {
- return mCurArgData;
- }
- if (mNextArg >= mArgs.length) {
+ String arg = mCurArgData;
+ mCurArgData = null;
+ return arg;
+ } else if (mNextArg < mArgs.length) {
+ return mArgs[mNextArg++];
+ } else {
return null;
}
- String data = mArgs[mNextArg];
- mNextArg++;
- return data;
}
- private String nextArg() {
- if (mNextArg >= mArgs.length) {
- return null;
+ private String nextArgRequired() {
+ String arg = nextArg();
+ if (arg == null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
}
- String arg = mArgs[mNextArg];
- mNextArg++;
return arg;
}
- private void showUsage() {
- System.err.println("usage: am [start|broadcast|instrument|profile]");
- System.err.println(" am start [-D] INTENT");
- System.err.println(" am broadcast INTENT");
- System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
- System.err.println(" [-w] <COMPONENT> ");
- System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]");
- System.err.println("");
- System.err.println(" INTENT is described with:");
- System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
- System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]");
- System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]");
- System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]");
- System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]");
- System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]");
+ private static void showUsage() {
+ System.err.println(
+ "usage: am [subcommand] [options]\n" +
+ "\n" +
+ " start an Activity: am start [-D] <INTENT>\n" +
+ " -D: enable debugging\n" +
+ "\n" +
+ " send a broadcast Intent: am broadcast <INTENT>\n" +
+ "\n" +
+ " start an Instrumentation: am instrument [flags] <COMPONENT>\n" +
+ " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)\n" +
+ " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>\n" +
+ " -p <FILE>: write profiling data to <FILE>\n" +
+ " -w: wait for instrumentation to finish before returning\n" +
+ "\n" +
+ " start profiling: am profile <PROCESS> start <FILE>\n" +
+ " stop profiling: am profile <PROCESS> stop\n" +
+ "\n" +
+ " <INTENT> specifications include these flags:\n" +
+ " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
+ " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
+ " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
+ " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
+ " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
+ " [-n <COMPONENT>] [-f <FLAGS>] [<URI>]\n"
+ );
}
}
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index d825d5a..7decf9a 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -7,8 +7,8 @@
#define LOG_TAG "appproc"
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/process_name.h>
#include <cutils/memory.h>
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ee3ec1a..8c15d0b 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -268,7 +268,7 @@
private void printRestoreSets(RestoreSet[] sets) {
for (RestoreSet s : sets) {
- System.out.println(" " + s.token + " : " + s.name);
+ System.out.println(" " + Long.toHexString(s.token) + " : " + s.name);
}
}
@@ -294,7 +294,7 @@
private void doRestore() {
long token;
try {
- token = Long.parseLong(nextArg());
+ token = Long.parseLong(nextArg(), 16);
} catch (NumberFormatException e) {
showUsage();
return;
@@ -311,12 +311,13 @@
return;
}
RestoreSet[] sets = mRestore.getAvailableRestoreSets();
- for (RestoreSet s : sets) {
- if (s.token == token) {
- System.out.println("Scheduling restore: " + s.name);
- mRestore.performRestore(token, observer);
- didRestore = true;
- break;
+ if (sets != null) {
+ for (RestoreSet s : sets) {
+ if (s.token == token) {
+ System.out.println("Scheduling restore: " + s.name);
+ didRestore = (mRestore.performRestore(token, observer) == 0);
+ break;
+ }
}
}
if (!didRestore) {
@@ -327,21 +328,27 @@
printRestoreSets(sets);
}
}
+
+ // if we kicked off a restore successfully, we have to wait for it
+ // to complete before we can shut down the restore session safely
+ if (didRestore) {
+ synchronized (observer) {
+ while (!observer.done) {
+ try {
+ observer.wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ }
+
+ // once the restore has finished, close down the session and we're done
mRestore.endRestoreSession();
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
- // now wait for it to be done
- synchronized (observer) {
- while (!observer.done) {
- try {
- observer.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
System.out.println("done");
}
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 9c94c2e..3449de1 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -12,12 +12,13 @@
endif
endif
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
- libcorecg \
- libsgl \
+ libskia \
libEGL \
libGLESv1_CM
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 2fb3f79..99e513c 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-#define LOG_TAG "BootAnimation"
-
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#include <fcntl.h>
#include <utils/misc.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
@@ -35,7 +33,8 @@
#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
-#include <ui/EGLNativeWindowSurface.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <core/SkBitmap.h>
#include <images/SkImageDecoder.h>
@@ -130,15 +129,19 @@
return -1;
// create the native surface
- sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
- PIXEL_FORMAT_RGB_565, ISurfaceComposer::eGPU);
+ sp<SurfaceControl> control = session()->createSurface(
+ getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
session()->openTransaction();
- s->setLayer(0x40000000);
+ control->setLayer(0x40000000);
session()->closeTransaction();
+ sp<Surface> s = control->getSurface();
+
// initialize opengl and egl
- const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
+ const EGLint attribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
@@ -148,21 +151,21 @@
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-
- mNativeWindowSurface = new EGLNativeWindowSurface(s);
- surface = eglCreateWindowSurface(display, config,
- mNativeWindowSurface.get(), NULL);
-
+ EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
+ surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- eglMakeCurrent(display, surface, surface, context);
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+ return NO_INIT;
+
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
+ mFlingerSurfaceControl = control;
mFlingerSurface = s;
// initialize GL
@@ -178,8 +181,8 @@
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
- mNativeWindowSurface.clear();
mFlingerSurface.clear();
+ mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
@@ -200,8 +203,7 @@
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
// draw and update only what we need
- mNativeWindowSurface->setSwapRectangle(updateRect.left,
- updateRect.top, updateRect.width(), updateRect.height());
+ mFlingerSurface->setSwapRectangle(updateRect);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 42e9eed..796077d 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -34,7 +34,6 @@
namespace android {
class AssetManager;
-class EGLNativeWindowSurface;
// ---------------------------------------------------------------------------
@@ -68,8 +67,8 @@
EGLDisplay mDisplay;
EGLDisplay mContext;
EGLDisplay mSurface;
+ sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
- sp<EGLNativeWindowSurface> mNativeWindowSurface;
};
// ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index a8359c4..3c82fe5 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -18,9 +18,10 @@
#include <cutils/properties.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
#include <utils/Log.h>
#include <utils/threads.h>
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
index 0c623cc..42b1b73 100644
--- a/cmds/dumpsys/Android.mk
+++ b/cmds/dumpsys/Android.mk
@@ -5,7 +5,9 @@
dumpsys.cpp
LOCAL_SHARED_LIBRARIES := \
- libutils
+ libutils \
+ libbinder
+
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a62fe55..945a690 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -6,9 +6,9 @@
#define LOG_TAG "dumpsys"
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <utils/Vector.h>
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 637e0d8..bdd5960 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -242,6 +242,7 @@
{
struct timeval tv;
tv.tv_sec = READ_TIMEOUT;
+ tv.tv_usec = 0;
if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
{
LOGE("setsockopt failed");
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
index a87a667..d80ddae 100644
--- a/cmds/keystore/netkeystore.h
+++ b/cmds/keystore/netkeystore.h
@@ -19,6 +19,7 @@
#define __NETKEYSTORE_H__
#include <stdio.h>
+#include <arpa/inet.h>
#include <cutils/sockets.h>
#include <cutils/log.h>
@@ -68,6 +69,8 @@
LOGE("failed to read header\n");
return -1;
}
+ cmd->len = ntohl(cmd->len);
+ cmd->opcode = ntohl(cmd->opcode);
if (cmd->len > BUFFER_MAX) {
LOGE("invalid size %d\n", cmd->len);
return -1;
@@ -82,11 +85,14 @@
static inline int write_marshal(int s, LPC_MARSHAL *cmd)
{
+ int len = cmd->len;
+ cmd->len = htonl(cmd->len);
+ cmd->opcode = htonl(cmd->opcode);
if (writex(s, cmd, 2 * sizeof(uint32_t))) {
LOGE("failed to write marshal header\n");
return -1;
}
- if (writex(s, cmd->data, cmd->len)) {
+ if (writex(s, cmd->data, len)) {
LOGE("failed to write marshal data\n");
return -1;
}
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
index 521eb2b..6a72d10 100644
--- a/cmds/runtime/Android.mk
+++ b/cmds/runtime/Android.mk
@@ -10,6 +10,7 @@
LOCAL_SHARED_LIBRARIES := \
libutils \
+ libbinder \
libandroid_runtime \
libcutils \
libui \
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
index 758a95c..b2bef07 100644
--- a/cmds/runtime/ServiceManager.cpp
+++ b/cmds/runtime/ServiceManager.cpp
@@ -9,9 +9,9 @@
#include <utils/Debug.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <private/utils/Static.h>
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
index d09cec8..090ca6d 100644
--- a/cmds/runtime/ServiceManager.h
+++ b/cmds/runtime/ServiceManager.h
@@ -4,7 +4,7 @@
#ifndef ANDROID_SERVICE_MANAGER_H
#define ANDROID_SERVICE_MANAGER_H
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 476f38a..21e0e4d 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -7,9 +7,11 @@
#include "ServiceManager.h"
#include "SignalHandler.h"
-#include <utils.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/zygote.h>
diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk
index 8c5005c..275bbb2 100644
--- a/cmds/service/Android.mk
+++ b/cmds/service/Android.mk
@@ -4,8 +4,7 @@
LOCAL_SRC_FILES:= \
service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libutils
+LOCAL_SHARED_LIBRARIES := libutils libbinder
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 859a9bf..32db83b 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -3,9 +3,9 @@
*
*/
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <getopt.h>
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index e4aa8b5..f3a4713 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -30,6 +30,7 @@
{ AID_MEDIA, "media.audio_flinger" },
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
+ { AID_MEDIA, "media.audio_policy" },
{ AID_RADIO, "radio.phone" },
{ AID_RADIO, "radio.sms" },
{ AID_RADIO, "radio.phonesubinfo" },
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
new file mode 100644
index 0000000..4576b8e
--- /dev/null
+++ b/cmds/stagefright/Android.mk
@@ -0,0 +1,59 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ stagefright.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright
+
+LOCAL_C_INCLUDES:= \
+ frameworks/base/media/libstagefright \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= stagefright
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ record.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright
+
+LOCAL_C_INCLUDES:= \
+ frameworks/base/media/libstagefright \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= record
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+# include $(CLEAR_VARS)
+#
+# LOCAL_SRC_FILES:= \
+# play.cpp
+#
+# LOCAL_SHARED_LIBRARIES := \
+# libstagefright
+#
+# LOCAL_C_INCLUDES:= \
+# frameworks/base/media/libstagefright \
+# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+#
+# LOCAL_CFLAGS += -Wno-multichar
+#
+# LOCAL_MODULE:= play
+#
+# include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/WaveWriter.h b/cmds/stagefright/WaveWriter.h
new file mode 100644
index 0000000..a0eb66e
--- /dev/null
+++ b/cmds/stagefright/WaveWriter.h
@@ -0,0 +1,71 @@
+/*
+ * 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 ANDROID_WAVEWRITER_H_
+
+#define ANDROID_WAVEWRITER_H_
+
+namespace android {
+
+class WaveWriter {
+public:
+ WaveWriter(const char *filename,
+ uint16_t num_channels, uint32_t sampling_rate)
+ : mFile(fopen(filename, "wb")),
+ mTotalBytes(0) {
+ fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile);
+ write_u16(num_channels);
+ write_u32(sampling_rate);
+ write_u32(sampling_rate * num_channels * 2);
+ write_u16(num_channels * 2);
+ write_u16(16);
+ fwrite("dataxxxx", 1, 8, mFile);
+ }
+
+ ~WaveWriter() {
+ fseek(mFile, 40, SEEK_SET);
+ write_u32(mTotalBytes);
+
+ fseek(mFile, 4, SEEK_SET);
+ write_u32(36 + mTotalBytes);
+
+ fclose(mFile);
+ mFile = NULL;
+ }
+
+ void Append(const void *data, size_t size) {
+ fwrite(data, 1, size, mFile);
+ mTotalBytes += size;
+ }
+
+private:
+ void write_u16(uint16_t x) {
+ fputc(x & 0xff, mFile);
+ fputc(x >> 8, mFile);
+ }
+
+ void write_u32(uint32_t x) {
+ write_u16(x & 0xffff);
+ write_u16(x >> 16);
+ }
+
+ FILE *mFile;
+ size_t mTotalBytes;
+};
+
+} // namespace android
+
+#endif // ANDROID_WAVEWRITER_H_
diff --git a/cmds/stagefright/play.cpp b/cmds/stagefright/play.cpp
new file mode 100644
index 0000000..c6e778e
--- /dev/null
+++ b/cmds/stagefright/play.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/TimedEventQueue.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXDecoder.h>
+
+using namespace android;
+
+struct NewPlayer {
+ NewPlayer();
+ ~NewPlayer();
+
+ void setSource(const char *uri);
+ void start();
+ void pause();
+ void stop();
+
+private:
+ struct PlayerEvent : public TimedEventQueue::Event {
+ PlayerEvent(NewPlayer *player,
+ void (NewPlayer::*method)(int64_t realtime_us))
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+ virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
+ (mPlayer->*mMethod)(realtime_us);
+ }
+
+ private:
+ NewPlayer *mPlayer;
+ void (NewPlayer::*mMethod)(int64_t realtime_us);
+
+ PlayerEvent(const PlayerEvent &);
+ PlayerEvent &operator=(const PlayerEvent &);
+ };
+
+ struct PlayVideoFrameEvent : public TimedEventQueue::Event {
+ PlayVideoFrameEvent(NewPlayer *player, MediaBuffer *buffer)
+ : mPlayer(player),
+ mBuffer(buffer) {
+ }
+
+ virtual ~PlayVideoFrameEvent() {
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+ }
+
+ virtual void fire(TimedEventQueue *queue, int64_t realtime_us) {
+ mPlayer->onPlayVideoFrame(realtime_us, mBuffer);
+ mBuffer = NULL;
+ }
+
+ private:
+ NewPlayer *mPlayer;
+ MediaBuffer *mBuffer;
+
+ PlayVideoFrameEvent(const PlayVideoFrameEvent &);
+ PlayVideoFrameEvent &operator=(const PlayVideoFrameEvent &);
+ };
+
+ OMXClient mClient;
+
+ MPEG4Extractor *mExtractor;
+ MediaSource *mAudioSource;
+ OMXDecoder *mAudioDecoder;
+ MediaSource *mVideoSource;
+ OMXDecoder *mVideoDecoder;
+
+ int32_t mVideoWidth, mVideoHeight;
+
+ TimedEventQueue mQueue;
+ wp<TimedEventQueue::Event> mPlayVideoFrameEvent;
+
+ int64_t mMediaTimeUsStart;
+ int64_t mRealTimeUsStart;
+
+ void setAudioSource(MediaSource *source);
+ void setVideoSource(MediaSource *source);
+
+ int64_t approxRealTime(int64_t mediatime_us) const;
+
+ void onStart(int64_t realtime_us);
+ void onPause(int64_t realtime_us);
+ void onFetchVideoFrame(int64_t realtime_us);
+ void onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer);
+
+ static int64_t getMediaBufferTimeUs(MediaBuffer *buffer);
+
+ NewPlayer(const NewPlayer &);
+ NewPlayer &operator=(const NewPlayer &);
+};
+
+NewPlayer::NewPlayer()
+ : mExtractor(NULL),
+ mAudioSource(NULL),
+ mAudioDecoder(NULL),
+ mVideoSource(NULL),
+ mVideoDecoder(NULL),
+ mVideoWidth(0),
+ mVideoHeight(0) {
+ status_t err = mClient.connect();
+ assert(err == OK);
+}
+
+NewPlayer::~NewPlayer() {
+ stop();
+
+ mClient.disconnect();
+}
+
+void NewPlayer::setSource(const char *uri) {
+ stop();
+
+ mExtractor = new MPEG4Extractor(new MmapSource(uri));
+
+ int num_tracks;
+ status_t err = mExtractor->countTracks(&num_tracks);
+ assert(err == OK);
+
+ for (int i = 0; i < num_tracks; ++i) {
+ const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ assert(meta != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ bool is_audio = false;
+ bool is_acceptable = false;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ is_audio = true;
+ is_acceptable = (mAudioSource == NULL);
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ is_acceptable = (mVideoSource == NULL);
+ }
+
+ if (!is_acceptable) {
+ continue;
+ }
+
+ MediaSource *source;
+ if (mExtractor->getTrack(i, &source) != OK) {
+ continue;
+ }
+
+ if (is_audio) {
+ setAudioSource(source);
+ } else {
+ setVideoSource(source);
+ }
+ }
+}
+
+void NewPlayer::setAudioSource(MediaSource *source) {
+ mAudioSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+ mAudioDecoder = OMXDecoder::Create(&mClient, meta);
+ mAudioDecoder->setSource(source);
+}
+
+void NewPlayer::setVideoSource(MediaSource *source) {
+ mVideoSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+ bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
+ assert(success);
+
+ success = meta->findInt32(kKeyHeight, &mVideoHeight);
+ assert(success);
+
+ mVideoDecoder = OMXDecoder::Create(&mClient, meta);
+ mVideoDecoder->setSource(source);
+}
+
+void NewPlayer::start() {
+ mQueue.start();
+ mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onStart));
+}
+
+void NewPlayer::pause() {
+ mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onPause));
+}
+
+void NewPlayer::stop() {
+ mQueue.stop();
+
+ delete mVideoDecoder;
+ mVideoDecoder = NULL;
+ delete mVideoSource;
+ mVideoSource = NULL;
+ mVideoWidth = mVideoHeight = 0;
+
+ delete mAudioDecoder;
+ mAudioDecoder = NULL;
+ delete mAudioSource;
+ mAudioSource = NULL;
+
+ delete mExtractor;
+ mExtractor = NULL;
+}
+
+int64_t NewPlayer::approxRealTime(int64_t mediatime_us) const {
+ return mRealTimeUsStart + (mediatime_us - mMediaTimeUsStart);
+}
+
+void NewPlayer::onStart(int64_t realtime_us) {
+ mRealTimeUsStart = TimedEventQueue::getRealTimeUs();
+
+ if (mVideoDecoder != NULL) {
+ mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
+ }
+}
+
+void NewPlayer::onFetchVideoFrame(int64_t realtime_us) {
+ MediaBuffer *buffer;
+ status_t err = mVideoDecoder->read(&buffer);
+ assert(err == OK);
+
+ int64_t mediatime_us = getMediaBufferTimeUs(buffer);
+
+ sp<TimedEventQueue::Event> event = new PlayVideoFrameEvent(this, buffer);
+ mPlayVideoFrameEvent = event;
+
+ mQueue.postTimedEvent(event, approxRealTime(mediatime_us));
+}
+
+// static
+int64_t NewPlayer::getMediaBufferTimeUs(MediaBuffer *buffer) {
+ int32_t units, scale;
+ bool success =
+ buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ assert(success);
+ success =
+ buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ assert(success);
+
+ return (int64_t)units * 1000000 / scale;
+}
+
+void NewPlayer::onPlayVideoFrame(int64_t realtime_us, MediaBuffer *buffer) {
+ LOGI("playing video frame (mediatime: %.2f sec)\n",
+ getMediaBufferTimeUs(buffer) / 1E6);
+ fflush(stdout);
+
+ buffer->release();
+ buffer = NULL;
+
+ mQueue.postEvent(new PlayerEvent(this, &NewPlayer::onFetchVideoFrame));
+}
+
+void NewPlayer::onPause(int64_t realtime_us) {
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ NewPlayer player;
+ player.setSource(argv[1]);
+ player.start();
+ sleep(10);
+ player.stop();
+
+ return 0;
+}
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
new file mode 100644
index 0000000..cf2962b
--- /dev/null
+++ b/cmds/stagefright/record.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#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;
+
+class DummySource : public MediaSource {
+public:
+ DummySource(int width, int height)
+ : mWidth(width),
+ mHeight(height),
+ mSize((width * height * 3) / 2) {
+ mGroup.add_buffer(new MediaBuffer(mSize));
+ }
+
+ 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 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;
+ }
+
+ char x = (char)((double)rand() / RAND_MAX * 255);
+ memset((*buffer)->data(), x, mSize);
+ (*buffer)->set_range(0, mSize);
+
+ return OK;
+ }
+
+protected:
+ virtual ~DummySource() {}
+
+private:
+ MediaBufferGroup mGroup;
+ int mWidth, mHeight;
+ size_t mSize;
+
+ DummySource(const DummySource &);
+ DummySource &operator=(const DummySource &);
+};
+
+#define USE_OMX_CODEC 1
+
+sp<MediaSource> createSource(const char *filename) {
+ sp<MediaSource> source;
+
+ sp<MPEG4Extractor> extractor =
+ new MPEG4Extractor(new MmapSource(filename));
+
+ size_t num_tracks = extractor->countTracks();
+
+ sp<MetaData> meta;
+ for (size_t i = 0; i < num_tracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
+ assert(meta.get() != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ if (strncasecmp(mime, "video/", 6)) {
+ continue;
+ }
+
+ source = extractor->getTrack(i);
+ break;
+ }
+
+ return source;
+}
+
+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);
+
+#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->setInt32(kKeyWidth, width);
+ enc_meta->setInt32(kKeyHeight, 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
+ sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
+ writer->addSource(enc_meta, encoder);
+ writer->start();
+ sleep(20);
+ printf("stopping now.\n");
+ writer->stop();
+#else
+ encoder->start();
+
+ MediaBuffer *buffer;
+ while (encoder->read(&buffer) == ::OK) {
+ printf("got an output frame of size %d\n", buffer->range_length());
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ encoder->stop();
+#endif
+
+ client.disconnect();
+#endif
+
+#if 0
+ CameraSource *source = CameraSource::Create();
+ printf("source = %p\n", source);
+
+ for (int i = 0; i < 100; ++i) {
+ MediaBuffer *buffer;
+ status_t err = source->read(&buffer);
+ assert(err == OK);
+
+ printf("got a frame, data=%p, size=%d\n",
+ buffer->data(), buffer->range_length());
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ delete source;
+ source = NULL;
+#endif
+
+ return 0;
+}
+
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
new file mode 100644
index 0000000..b2de67a
--- /dev/null
+++ b/cmds/stagefright/stagefright.cpp
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+
+#include <sys/time.h>
+
+#include <pthread.h>
+#include <stdlib.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/MediaBufferGroup.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"
+
+using namespace android;
+
+////////////////////////////////////////////////////////////////////////////////
+
+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 &);
+};
+
+JPEGSource::JPEGSource(const sp<DataSource> &source)
+ : mSource(source),
+ mGroup(NULL),
+ mStarted(false),
+ mSize(0),
+ mWidth(0),
+ mHeight(0),
+ mOffset(0) {
+ CHECK_EQ(parseJPEG(), OK);
+}
+
+JPEGSource::~JPEGSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t JPEGSource::start(MetaData *) {
+ if (mStarted) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mSource->getSize(&mSize) != OK) {
+ 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);
+
+ 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;
+}
+
+#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
+
+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;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static int64_t getNowUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ 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();
+
+ int64_t startTime = getNowUs();
+
+ int n = 0;
+ MediaBuffer *buffer;
+ status_t err;
+ while ((err = decoder->read(&buffer)) == OK) {
+ if ((++n % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+ 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);
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ bool audioOnly = false;
+ if (argc > 1 && !strcmp(argv[1], "--list")) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ sp<IOMX> omx = service->createOMX();
+ CHECK(omx.get() != NULL);
+
+ List<String8> list;
+ omx->list_nodes(&list);
+
+ for (List<String8>::iterator it = list.begin();
+ it != list.end(); ++it) {
+ printf("%s\n", (*it).string());
+ }
+
+ return 0;
+ } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+ audioOnly = true;
+ ++argv;
+ --argc;
+ }
+
+ DataSource::RegisterDefaultSniffers();
+
+ OMXClient client;
+ status_t err = client.connect();
+
+ sp<MmapSource> dataSource = new MmapSource(argv[1]);
+
+ bool isJPEG = false;
+
+ size_t len = strlen(argv[1]);
+ if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) {
+ isJPEG = true;
+ }
+
+ sp<MediaSource> mediaSource;
+
+ if (isJPEG) {
+ mediaSource = new JPEGSource(dataSource);
+ } else {
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ size_t numTracks = extractor->countTracks();
+
+ sp<MetaData> meta;
+ size_t 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;
+ }
+
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
+ break;
+ }
+ }
+
+ mediaSource = extractor->getTrack(i);
+ }
+
+ playSource(&client, mediaSource);
+
+ client.disconnect();
+
+ return 0;
+}
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
index 37c3d94..bfa58a1 100644
--- a/cmds/surfaceflinger/Android.mk
+++ b/cmds/surfaceflinger/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SHARED_LIBRARIES := \
libsurfaceflinger \
+ libbinder \
libutils
LOCAL_C_INCLUDES := \
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 7c89578..d650721 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -1,6 +1,6 @@
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <SurfaceFlinger.h>
diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk
index 0a684e8..ad537977 100644
--- a/cmds/system_server/Android.mk
+++ b/cmds/system_server/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SHARED_LIBRARIES := \
libutils \
+ libbinder \
libsystem_server
LOCAL_C_INCLUDES := \
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 580331a..1813d3e 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -20,6 +20,7 @@
libcameraservice \
libmediaplayerservice \
libutils \
+ libbinder \
libcutils
LOCAL_MODULE:= libsystem_server
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index 73b23e2..1d57fdc 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -8,15 +8,16 @@
#define LOG_TAG "sysproc"
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <utils/Log.h>
#include <SurfaceFlinger.h>
#include <AudioFlinger.h>
#include <CameraService.h>
+#include <AudioPolicyService.h>
#include <MediaPlayerService.h>
#include <android_runtime/AndroidRuntime.h>
@@ -80,6 +81,9 @@
// Start the camera service
CameraService::instantiate();
+
+ // Start the audio policy service
+ AudioPolicyService::instantiate();
}
// And now start the Android runtime. We have to do this bit
diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp
index ca16e57..543f650 100644
--- a/cmds/system_server/system_main.cpp
+++ b/cmds/system_server/system_main.cpp
@@ -9,7 +9,7 @@
#define LOG_TAG "sysproc"
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
new file mode 100644
index 0000000..38ae962
--- /dev/null
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -0,0 +1,266 @@
+/*
+ * 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 android.os.RemoteException;
+import android.os.Binder;
+import android.util.Log;
+import android.content.pm.PackageManager;
+import android.content.Context;
+import android.Manifest;
+
+/**
+ * Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator
+ * binder interface and also provides helper libraries to simplify the creation of
+ * AccountAuthenticators.
+ */
+public abstract class AbstractAccountAuthenticator {
+ private final Context mContext;
+
+ public AbstractAccountAuthenticator(Context context) {
+ mContext = context;
+ }
+
+ class Transport extends IAccountAuthenticator.Stub {
+ public void addAccount(IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws RemoteException {
+ checkBinderPermission();
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.addAccount(
+ new AccountAuthenticatorResponse(response),
+ accountType, authTokenType, requiredFeatures, options);
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "addAccount not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void confirmPassword(IAccountAuthenticatorResponse response,
+ Account account, String password) throws RemoteException {
+ checkBinderPermission();
+ boolean result;
+ try {
+ result = AbstractAccountAuthenticator.this.confirmPassword(
+ new AccountAuthenticatorResponse(response),
+ account, password);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "confirmPassword not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result);
+ response.onResult(bundle);
+ }
+
+ public void confirmCredentials(IAccountAuthenticatorResponse response,
+ Account account) throws RemoteException {
+ checkBinderPermission();
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.confirmCredentials(
+ new AccountAuthenticatorResponse(response), account);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "confirmCredentials not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
+ String authTokenType)
+ throws RemoteException {
+ checkBinderPermission();
+ try {
+ Bundle result = new Bundle();
+ result.putString(Constants.AUTH_TOKEN_LABEL_KEY,
+ AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
+ response.onResult(result);
+ } catch (IllegalArgumentException e) {
+ response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS,
+ "unknown authTokenType");
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAuthTokenTypeLabel not supported");
+ }
+ }
+
+ public void getAuthToken(IAccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions)
+ throws RemoteException {
+ checkBinderPermission();
+ try {
+ final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
+ new AccountAuthenticatorResponse(response), account,
+ authTokenType, loginOptions);
+ if (result != null) {
+ response.onResult(result);
+ }
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAuthToken not supported");
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ }
+ }
+
+ public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle loginOptions) throws RemoteException {
+ checkBinderPermission();
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.updateCredentials(
+ new AccountAuthenticatorResponse(response), account,
+ authTokenType, loginOptions);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "updateCredentials not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void editProperties(IAccountAuthenticatorResponse response,
+ String accountType) throws RemoteException {
+ checkBinderPermission();
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.editProperties(
+ new AccountAuthenticatorResponse(response), accountType);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "editProperties not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void hasFeatures(IAccountAuthenticatorResponse response,
+ Account account, String[] features) throws RemoteException {
+ checkBinderPermission();
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.hasFeatures(
+ new AccountAuthenticatorResponse(response), account, features);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "hasFeatures not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ if (result != null) {
+ 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() {
+ final int uid = Binder.getCallingUid();
+ final String perm = Manifest.permission.ACCOUNT_MANAGER_SERVICE;
+ if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("caller uid " + uid + " lacks " + perm);
+ }
+ }
+
+ Transport mTransport = new Transport();
+
+ /**
+ * @return the IAccountAuthenticator binder transport object
+ */
+ public final IAccountAuthenticator getIAccountAuthenticator()
+ {
+ return mTransport;
+ }
+
+ /**
+ * Returns a Bundle that contains the Intent of the activity that can be used to edit the
+ * properties. In order to indicate success the activity should call response.setResult()
+ * with a non-null Bundle.
+ * @param response used to set the result for the request. If the Constants.INTENT_KEY
+ * is set in the bundle then this response field is to be used for sending future
+ * results if and when the Intent is started.
+ * @param accountType the AccountType whose properties are to be edited.
+ * @return a Bundle containing the result or the Intent to start to continue the request.
+ * If this is null then the request is considered to still be active and the result should
+ * sent later using response.
+ */
+ public abstract Bundle editProperties(AccountAuthenticatorResponse response,
+ String accountType);
+ public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws NetworkErrorException;
+ /* @deprecated */
+ public abstract boolean confirmPassword(AccountAuthenticatorResponse response,
+ Account account, String password) throws NetworkErrorException;
+ public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
+ Account account);
+ public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions)
+ throws NetworkErrorException;
+ public abstract String getAuthTokenLabel(String authTokenType);
+ public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
+ 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.aidl b/core/java/android/accounts/Account.aidl
new file mode 100644
index 0000000..8752d99
--- /dev/null
+++ b/core/java/android/accounts/Account.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+parcelable Account;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
new file mode 100644
index 0000000..7b83a30
--- /dev/null
+++ b/core/java/android/accounts/Account.java
@@ -0,0 +1,84 @@
+/*
+ * 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.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+
+/**
+ * Value type that represents an Account in the {@link AccountManager}. This object is
+ * {@link Parcelable} and also overrides {@link #equals} and {@link #hashCode}, making it
+ * suitable for use as the key of a {@link java.util.Map}
+ */
+public class Account implements Parcelable {
+ 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 name.equals(other.name) && type.equals(other.type);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + name.hashCode();
+ result = 31 * result + type.hashCode();
+ return result;
+ }
+
+ public Account(String name, String type) {
+ if (TextUtils.isEmpty(name)) {
+ throw new IllegalArgumentException("the name must not be empty: " + name);
+ }
+ if (TextUtils.isEmpty(type)) {
+ throw new IllegalArgumentException("the type must not be empty: " + type);
+ }
+ this.name = name;
+ this.type = type;
+ }
+
+ public Account(Parcel in) {
+ this.name = in.readString();
+ this.type = in.readString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(name);
+ dest.writeString(type);
+ }
+
+ public static final Creator<Account> CREATOR = new Creator<Account>() {
+ public Account createFromParcel(Parcel source) {
+ return new Account(source);
+ }
+
+ public Account[] newArray(int size) {
+ return new Account[size];
+ }
+ };
+
+ public String toString() {
+ return "Account {name=" + name + ", type=" + type + "}";
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
new file mode 100644
index 0000000..0319ab9
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Base class for implementing an Activity that is used to help implement an
+ * AbstractAccountAuthenticator. If the AbstractAccountAuthenticator needs to return an Intent
+ * that is to be used to launch an Activity that needs to return results to satisfy an
+ * AbstractAccountAuthenticator request, it should store the AccountAuthenticatorResponse
+ * inside of the Intent as follows:
+ * <p>
+ * intent.putExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY, response);
+ * <p>
+ * The activity that it launches should extend the AccountAuthenticatorActivity. If this
+ * activity has a result that satisfies the original request it sets it via:
+ * <p>
+ * setAccountAuthenticatorResult(result)
+ * <p>
+ * This result will be sent as the result of the request when the activity finishes. If this
+ * is never set or if it is set to null then the request will be canceled when the activity
+ * finishes.
+ */
+public class AccountAuthenticatorActivity extends Activity {
+ private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
+ private Bundle mResultBundle = null;
+
+ /**
+ * Set the result that is to be sent as the result of the request that caused this
+ * Activity to be launched. If result is null or this method is never called then
+ * the request will be canceled.
+ * @param result this is returned as the result of the AbstractAccountAuthenticator request
+ */
+ public final void setAccountAuthenticatorResult(Bundle result) {
+ mResultBundle = result;
+ }
+
+ /**
+ * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
+ * icicle is non-zero.
+ * @param icicle the save instance data of this Activity, may be null
+ */
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ if (icicle == null) {
+ Intent intent = getIntent();
+ mAccountAuthenticatorResponse =
+ intent.getParcelableExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+ } else {
+ mAccountAuthenticatorResponse =
+ icicle.getParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+ }
+
+ if (mAccountAuthenticatorResponse != null) {
+ mAccountAuthenticatorResponse.onRequestContinued();
+ }
+ }
+
+ /**
+ * Saves the AccountAuthenticatorResponse in the instance state.
+ * @param outState where to store any instance data
+ */
+ protected void onSaveInstanceState(Bundle outState) {
+ outState.putParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY,
+ mAccountAuthenticatorResponse);
+ super.onSaveInstanceState(outState);
+ }
+
+ /**
+ * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
+ */
+ public void finish() {
+ if (mAccountAuthenticatorResponse != null) {
+ // send the result bundle back if set, otherwise send an error.
+ if (mResultBundle != null) {
+ mAccountAuthenticatorResponse.onResult(mResultBundle);
+ } else {
+ mAccountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ mAccountAuthenticatorResponse = null;
+ }
+ super.finish();
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
new file mode 100644
index 0000000..2f52f40
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -0,0 +1,56 @@
+/*
+ * 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.content.pm.PackageManager;
+import android.content.pm.RegisteredServicesCache;
+import android.content.res.TypedArray;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * A cache of services that export the {@link IAccountAuthenticator} interface. This cache
+ * is built by interrogating the {@link PackageManager} and is updated as packages are added,
+ * removed and changed. The authenticators are referred to by their account type and
+ * are made available via the {@link RegisteredServicesCache#getServiceInfo} method.
+ * @hide
+ */
+/* package private */ class AccountAuthenticatorCache
+ extends RegisteredServicesCache<AuthenticatorDescription> {
+ private static final String TAG = "Account";
+
+ public AccountAuthenticatorCache(Context context) {
+ super(context, Constants.AUTHENTICATOR_INTENT_ACTION,
+ Constants.AUTHENTICATOR_META_DATA_NAME, Constants.AUTHENTICATOR_ATTRIBUTES_NAME);
+ }
+
+ public AuthenticatorDescription parseServiceAttributes(String packageName, AttributeSet attrs) {
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.AccountAuthenticator);
+ try {
+ final String accountType =
+ sa.getString(com.android.internal.R.styleable.AccountAuthenticator_accountType);
+ final int labelId = sa.getResourceId(
+ com.android.internal.R.styleable.AccountAuthenticator_label, 0);
+ final int iconId = sa.getResourceId(
+ com.android.internal.R.styleable.AccountAuthenticator_icon, 0);
+ return new AuthenticatorDescription(accountType, packageName, labelId, iconId);
+ } finally {
+ sa.recycle();
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
new file mode 100644
index 0000000..7198046
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.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.accounts;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link IAccountAuthenticatorResponse} object.
+ * TODO: this interface is still in flux
+ */
+public class AccountAuthenticatorResponse implements Parcelable {
+ private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
+
+ public AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
+ mAccountAuthenticatorResponse = response;
+ }
+
+ public AccountAuthenticatorResponse(Parcel parcel) {
+ mAccountAuthenticatorResponse =
+ IAccountAuthenticatorResponse.Stub.asInterface(parcel.readStrongBinder());
+ }
+
+ public void onResult(Bundle result) {
+ try {
+ mAccountAuthenticatorResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onRequestContinued() {
+ try {
+ mAccountAuthenticatorResponse.onRequestContinued();
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ try {
+ mAccountAuthenticatorResponse.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mAccountAuthenticatorResponse.asBinder());
+ }
+
+ public static final Creator<AccountAuthenticatorResponse> CREATOR =
+ new Creator<AccountAuthenticatorResponse>() {
+ public AccountAuthenticatorResponse createFromParcel(Parcel source) {
+ return new AccountAuthenticatorResponse(source);
+ }
+
+ public AccountAuthenticatorResponse[] newArray(int size) {
+ return new AccountAuthenticatorResponse[size];
+ }
+ };
+}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
new file mode 100644
index 0000000..9f70534
--- /dev/null
+++ b/core/java/android/accounts/AccountManager.java
@@ -0,0 +1,855 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+
+/**
+ * A class that helps with interactions with the AccountManagerService. It provides
+ * methods to allow for account, password, and authtoken management for all accounts on the
+ * device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. One accesses the {@link AccountManager} by calling:
+ * AccountManager accountManager = AccountManager.get(context);
+ *
+ * <p>
+ * TODO(fredq) this interface is still in flux
+ */
+public class AccountManager {
+ private static final String TAG = "AccountManager";
+
+ private final Context mContext;
+ private final IAccountManager mService;
+ private final Handler mMainHandler;
+
+ /**
+ * @hide
+ */
+ public AccountManager(Context context, IAccountManager service) {
+ mContext = context;
+ mService = service;
+ mMainHandler = new Handler(mContext.getMainLooper());
+ }
+
+ /**
+ * @hide used for testing only
+ */
+ public AccountManager(Context context, IAccountManager service, Handler handler) {
+ mContext = context;
+ mService = service;
+ mMainHandler = handler;
+ }
+
+ public static AccountManager get(Context context) {
+ return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+ }
+
+ public String getPassword(final Account account) {
+ try {
+ return mService.getPassword(account);
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getUserData(final Account account, final String key) {
+ try {
+ return mService.getUserData(account, key);
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public AuthenticatorDescription[] getAuthenticatorTypes() {
+ try {
+ return mService.getAuthenticatorTypes();
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Account[] getAccounts() {
+ try {
+ return mService.getAccounts(null);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Account[] getAccountsByType(String type) {
+ try {
+ return mService.getAccounts(type);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
+ try {
+ return mService.addAccount(account, password, extras);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ 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 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 invalidateAuthToken(final String accountType, final String authToken) {
+ try {
+ mService.invalidateAuthToken(accountType, authToken);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ 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 setPassword(final Account account, final String password) {
+ try {
+ mService.setPassword(account, password);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void clearPassword(final Account account) {
+ try {
+ mService.clearPassword(account);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setUserData(final Account account, final String key, final String value) {
+ try {
+ mService.setUserData(account, key, value);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setAuthToken(Account account, final String authTokenType, final String authToken) {
+ try {
+ mService.setAuthToken(account, authTokenType, authToken);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String blockingGetAuthToken(Account account, String authTokenType,
+ boolean notifyAuthFailure)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
+ null /* handler */).getResult();
+ return bundle.getString(Constants.AUTHTOKEN_KEY);
+ }
+
+ /**
+ * Request the auth token for this account/authTokenType. If this succeeds then the
+ * auth token will then be passed to the activity. If this results in an authentication
+ * failure then a login intent will be returned that can be invoked to prompt the user to
+ * update their credentials. This login activity will return the auth token to the calling
+ * activity. If activity is null then the login intent will not be invoked.
+ *
+ * @param account the account whose auth token should be retrieved
+ * @param authTokenType the auth token type that should be retrieved
+ * @param loginOptions
+ * @param activity the activity to launch the login intent, if necessary, and to which
+ */
+ public AccountManagerFuture<Bundle> getAuthToken(
+ final Account account, final String authTokenType, final Bundle loginOptions,
+ 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) {
+ public void doWork() throws RemoteException {
+ mService.getAuthToken(mResponse, account, authTokenType,
+ false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
+ loginOptions);
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> getAuthToken(
+ final Account account, final String authTokenType, final boolean notifyAuthFailure,
+ 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) {
+ public void doWork() throws RemoteException {
+ mService.getAuthToken(mResponse, account, authTokenType,
+ notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> addAccount(final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final Bundle addAccountOptions,
+ final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.addAcount(mResponse, accountType, authTokenType,
+ requiredFeatures, activity != null, addAccountOptions);
+ }
+ }.start();
+ }
+
+ /** @deprecated use {@link #confirmCredentials} instead */
+ 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(mResponse, account, password);
+ }
+ 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 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 {
+ mService.confirmCredentials(mResponse, account, activity != null);
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType,
+ final Bundle loginOptions, final Activity activity,
+ final AccountManagerCallback<Bundle> callback,
+ final Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.updateCredentials(mResponse, account, authTokenType, activity != null,
+ loginOptions);
+ }
+ }.start();
+ }
+
+ 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 {
+ mService.editProperties(mResponse, accountType, activity != null);
+ }
+ }.start();
+ }
+
+ private void ensureNotOnMainThread() {
+ final Looper looper = Looper.myLooper();
+ if (looper != null && looper == mContext.getMainLooper()) {
+ // We really want to throw an exception here, but GTalkService exercises this
+ // path quite a bit and needs some serious rewrite in order to work properly.
+ //noinspection ThrowableInstanceNeverThrow
+// Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
+// new Exception());
+ // TODO(fredq) remove the log and throw this exception when the callers are fixed
+// throw new IllegalStateException(
+// "calling this from your main thread can lead to deadlock");
+ }
+ }
+
+ 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() {
+ callback.run(future);
+ }
+ });
+ }
+
+ private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
+ final Account[] accounts) {
+ 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(accountsCopy);
+ }
+ });
+ }
+
+ private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
+ final IAccountManagerResponse mResponse;
+ final Handler mHandler;
+ final AccountManagerCallback<Bundle> mCallback;
+ final Activity mActivity;
+ 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");
+ }
+ });
+
+ mHandler = handler;
+ mCallback = callback;
+ mActivity = activity;
+ mResponse = new Response();
+ }
+
+ public final AccountManagerFuture<Bundle> start() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
+ }
+ return this;
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+ private Bundle internalGetResult(Long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
+ try {
+ if (timeout == null) {
+ return get();
+ } else {
+ return get(timeout, unit);
+ }
+ } catch (CancellationException e) {
+ throw new OperationCanceledException();
+ } catch (TimeoutException e) {
+ // fall through and cancel
+ } catch (InterruptedException 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 Bundle getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(null, null);
+ }
+
+ public Bundle getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(timeout, unit);
+ }
+
+ protected void done() {
+ if (mCallback != null) {
+ postToHandler(mHandler, mCallback, this);
+ }
+ }
+
+ /** Handles the responses from the AccountManager */
+ private class Response extends IAccountManagerResponse.Stub {
+ public void onResult(Bundle bundle) {
+ Intent intent = bundle.getParcelable("intent");
+ if (intent != null && mActivity != null) {
+ // since the user provided an Activity we will silently start intents
+ // that we see
+ mActivity.startActivity(intent);
+ // leave the Future running to wait for the real response to this request
+ } else if (bundle.getBoolean("retry")) {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ // this will only happen if the system process is dead, which means
+ // we will be dying ourselves
+ }
+ } else {
+ set(bundle);
+ }
+ }
+
+ public void onError(int code, String message) {
+ if (code == Constants.ERROR_CODE_CANCELED) {
+ // the authenticator indicated that this request was canceled, do so now
+ cancel(true /* mayInterruptIfRunning */);
+ return;
+ }
+ setException(convertErrorToException(code, message));
+ }
+ }
+
+ }
+
+ private abstract class BaseFutureTask<T> extends FutureTask<T> {
+ final public IAccountManagerResponse mResponse;
+ final Handler mHandler;
+
+ public BaseFutureTask(Handler handler) {
+ super(new Callable<T>() {
+ public T call() throws Exception {
+ throw new IllegalStateException("this should never be called");
+ }
+ });
+ mHandler = handler;
+ mResponse = new Response();
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+ public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
+
+ protected void postRunnableToHandler(Runnable runnable) {
+ Handler handler = (mHandler == null) ? mMainHandler : mHandler;
+ handler.post(runnable);
+ }
+
+ protected void startTask() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
+ }
+ }
+
+ protected class Response extends IAccountManagerResponse.Stub {
+ public void onResult(Bundle bundle) {
+ try {
+ 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");
+ }
+
+ public void onError(int code, String message) {
+ if (code == Constants.ERROR_CODE_CANCELED) {
+ cancel(true /* mayInterruptIfRunning */);
+ return;
+ }
+ 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);
+ }
+
+ }
+
+ private Exception convertErrorToException(int code, String message) {
+ if (code == Constants.ERROR_CODE_NETWORK_ERROR) {
+ return new IOException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_UNSUPPORTED_OPERATION) {
+ return new UnsupportedOperationException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_INVALID_RESPONSE) {
+ return new AuthenticatorException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_BAD_ARGUMENTS) {
+ return new IllegalArgumentException(message);
+ }
+
+ return new AuthenticatorException(message);
+ }
+
+ 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,
+ AccountManagerCallback<Bundle> callback, Handler handler) {
+ super(activityForPrompting, handler, callback);
+ if (accountType == null) throw new IllegalArgumentException("account type is null");
+ mAccountType = accountType;
+ mAuthTokenType = authTokenType;
+ mFeatures = features;
+ mAddAccountOptions = addAccountOptions;
+ mLoginOptions = loginOptions;
+ mMyCallback = this;
+ }
+ volatile AccountManagerFuture<Bundle> mFuture = null;
+ final String mAccountType;
+ final String mAuthTokenType;
+ final String[] mFeatures;
+ final Bundle mAddAccountOptions;
+ final Bundle mLoginOptions;
+ final AccountManagerCallback<Bundle> mMyCallback;
+
+ public void doWork() throws RemoteException {
+ getAccountsByTypeAndFeatures(mAccountType, mFeatures,
+ new AccountManagerCallback<Account[]>() {
+ public void run(AccountManagerFuture<Account[]> future) {
+ Account[] accounts;
+ try {
+ accounts = future.getResult();
+ } catch (OperationCanceledException e) {
+ setException(e);
+ return;
+ } catch (IOException e) {
+ setException(e);
+ return;
+ } catch (AuthenticatorException e) {
+ setException(e);
+ return;
+ }
+
+ 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);
+ }
+ };
+ // 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);
+ }
+
+
+
+ // TODO(fredq) pass through the calls to our implemention of Future2 to the underlying
+ // future that we create. We need to do things like have cancel cancel the mFuture, if set
+ // 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(AccountManagerFuture<Bundle> future) {
+ try {
+ set(future.get());
+ } catch (InterruptedException e) {
+ cancel(true);
+ } catch (CancellationException e) {
+ cancel(true);
+ } catch (ExecutionException e) {
+ setException(e.getCause());
+ }
+ }
+ }
+
+ public void getAuthTokenByFeatures(
+ final String accountType, final String authTokenType, final String[] features,
+ final Activity activityForPrompting, final Bundle addAccountOptions,
+ final Bundle loginOptions,
+ 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,
+ activityForPrompting, addAccountOptions, loginOptions, callback, handler).start();
+ }
+
+ private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
+ Maps.newHashMap();
+
+ /**
+ * 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
+ * in mAccountsUpdatedListeners.
+ */
+ private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(final Context context, final Intent intent) {
+ 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);
+ }
+ }
+ }
+ };
+
+ /**
+ * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
+ * The listener is guaranteed to be invoked on the thread of the Handler that is passed
+ * in or the main thread's Handler if handler is null.
+ * @param listener the listener to add
+ * @param handler the Handler whose thread will be used to invoke the listener. If null
+ * the AccountManager context's main thread will be used.
+ * @param updateImmediately if true then the listener will be invoked as a result of this
+ * call.
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was already added
+ */
+ public void addOnAccountsUpdatedListener(final OnAccountsUpdatedListener listener,
+ Handler handler, boolean updateImmediately) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.containsKey(listener)) {
+ throw new IllegalStateException("this listener is already added");
+ }
+ final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
+
+ mAccountsUpdatedListeners.put(listener, handler);
+
+ if (wasEmpty) {
+ // Register a broadcast receiver to monitor account changes
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
+ }
+ }
+
+ if (updateImmediately) {
+ postToHandler(handler, listener, getAccounts());
+ }
+ }
+
+ /**
+ * Remove an {@link OnAccountsUpdatedListener} that was previously registered with
+ * {@link #addOnAccountsUpdatedListener}.
+ * @param listener the listener to remove
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was not already added
+ */
+ public void removeOnAccountsUpdatedListener(OnAccountsUpdatedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.remove(listener) == null) {
+ throw new IllegalStateException("this listener was not previously added");
+ }
+ if (mAccountsUpdatedListeners.isEmpty()) {
+ mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
+ }
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountManagerCallback.java b/core/java/android/accounts/AccountManagerCallback.java
new file mode 100644
index 0000000..4aa7169
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerCallback.java
@@ -0,0 +1,20 @@
+/*
+ * 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 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..9939398
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerFuture.java
@@ -0,0 +1,65 @@
+/*
+ * 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
+ V get() throws InterruptedException, ExecutionException;
+
+ @Deprecated
+ V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException;
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerResponse.java b/core/java/android/accounts/AccountManagerResponse.java
new file mode 100644
index 0000000..25371fd
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerResponse.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link android.accounts.IAccountManagerResponse} object.
+ * @hide
+ */
+public class AccountManagerResponse implements Parcelable {
+ private IAccountManagerResponse mResponse;
+
+ public AccountManagerResponse(IAccountManagerResponse response) {
+ mResponse = response;
+ }
+
+ public AccountManagerResponse(Parcel parcel) {
+ mResponse =
+ IAccountManagerResponse.Stub.asInterface(parcel.readStrongBinder());
+ }
+
+ public void onResult(Bundle result) {
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ try {
+ mResponse.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mResponse.asBinder());
+ }
+
+ public static final Creator<AccountManagerResponse> CREATOR =
+ new Creator<AccountManagerResponse>() {
+ public AccountManagerResponse createFromParcel(Parcel source) {
+ return new AccountManagerResponse(source);
+ }
+
+ public AccountManagerResponse[] newArray(int size) {
+ return new AccountManagerResponse[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
new file mode 100644
index 0000000..140c814
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -0,0 +1,1598 @@
+/*
+ * 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.content.BroadcastReceiver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.RegisteredServicesCache;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Binder;
+import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.app.PendingIntent;
+import android.app.NotificationManager;
+import android.app.Notification;
+import android.Manifest;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.R;
+
+/**
+ * A system service that provides account, password, and authtoken management for all
+ * accounts on the device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
+ * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
+ * AccountManager accountManager =
+ * (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
+ * @hide
+ */
+public class AccountManagerService extends IAccountManager.Stub {
+ private static final String TAG = "AccountManagerService";
+
+ private static final int TIMEOUT_DELAY_MS = 1000 * 60;
+ private static final String DATABASE_NAME = "accounts.db";
+ private static final int DATABASE_VERSION = 3;
+
+ private final Context mContext;
+
+ private HandlerThread mMessageThread;
+ private final MessageHandler mMessageHandler;
+
+ // Messages that can be sent on mHandler
+ private static final int MESSAGE_TIMED_OUT = 3;
+ private static final int MESSAGE_CONNECTED = 7;
+ private static final int MESSAGE_DISCONNECTED = 8;
+
+ private final AccountAuthenticatorCache mAuthenticatorCache;
+ private final AuthenticatorBindHelper mBindHelper;
+ private final DatabaseHelper mOpenHelper;
+ private final SimWatcher mSimWatcher;
+
+ private static final String TABLE_ACCOUNTS = "accounts";
+ private static final String ACCOUNTS_ID = "_id";
+ private static final String ACCOUNTS_NAME = "name";
+ private static final String ACCOUNTS_TYPE = "type";
+ private static final String ACCOUNTS_PASSWORD = "password";
+
+ private static final String TABLE_AUTHTOKENS = "authtokens";
+ private static final String AUTHTOKENS_ID = "_id";
+ private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
+ private static final String AUTHTOKENS_TYPE = "type";
+ private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
+
+ private static final String TABLE_GRANTS = "grants";
+ private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+ private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
+ private static final String GRANTS_GRANTEE_UID = "uid";
+
+ private static final String TABLE_EXTRAS = "extras";
+ private static final String EXTRAS_ID = "_id";
+ private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
+ private static final String EXTRAS_KEY = "key";
+ private static final String EXTRAS_VALUE = "value";
+
+ private static final String TABLE_META = "meta";
+ private static final String META_KEY = "key";
+ private static final String META_VALUE = "value";
+
+ 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 String COUNT_OF_MATCHING_GRANTS = ""
+ + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+ + " AND " + GRANTS_GRANTEE_UID + "=?"
+ + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
+ + " AND " + ACCOUNTS_NAME + "=?"
+ + " AND " + ACCOUNTS_TYPE + "=?";
+
+ private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
+ private final AtomicInteger mNotificationIds = new AtomicInteger(1);
+
+ private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
+ mCredentialsPermissionNotificationIds =
+ new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
+ private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
+ new HashMap<Account, Integer>();
+ private static AtomicReference<AccountManagerService> sThis =
+ new AtomicReference<AccountManagerService>();
+
+ private static final boolean isDebuggableMonkeyBuild =
+ SystemProperties.getBoolean("ro.monkey", false)
+ && SystemProperties.getBoolean("ro.debuggable", false);
+ /**
+ * This should only be called by system code. One should only call this after the service
+ * has started.
+ * @return a reference to the AccountManagerService instance
+ * @hide
+ */
+ public static AccountManagerService getSingleton() {
+ return sThis.get();
+ }
+
+ public class AuthTokenKey {
+ public final Account mAccount;
+ public final String mAuthTokenType;
+ private final int mHashCode;
+
+ public AuthTokenKey(Account account, String authTokenType) {
+ mAccount = account;
+ mAuthTokenType = authTokenType;
+ mHashCode = computeHashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof AuthTokenKey)) {
+ return false;
+ }
+ AuthTokenKey other = (AuthTokenKey)o;
+ if (!mAccount.equals(other.mAccount)) {
+ return false;
+ }
+ return (mAuthTokenType == null)
+ ? other.mAuthTokenType == null
+ : mAuthTokenType.equals(other.mAuthTokenType);
+ }
+
+ private int computeHashCode() {
+ int result = 17;
+ result = 31 * result + mAccount.hashCode();
+ result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
+ return result;
+ }
+
+ public int hashCode() {
+ return mHashCode;
+ }
+ }
+
+ public AccountManagerService(Context context) {
+ mContext = context;
+
+ mOpenHelper = new DatabaseHelper(mContext);
+
+ mMessageThread = new HandlerThread("AccountManagerService");
+ mMessageThread.start();
+ mMessageHandler = new MessageHandler(mMessageThread.getLooper());
+
+ mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
+ mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
+ MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
+
+ mSimWatcher = new SimWatcher(mContext);
+ sThis.set(this);
+ }
+
+ public String getPassword(Account account) {
+ checkAuthenticateAccountsPermission(account);
+
+ long identityToken = clearCallingIdentity();
+ try {
+ 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);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public AuthenticatorDescription[] getAuthenticatorTypes() {
+ long identityToken = clearCallingIdentity();
+ try {
+ Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
+ authenticatorCollection = mAuthenticatorCache.getAllServices();
+ AuthenticatorDescription[] types =
+ new AuthenticatorDescription[authenticatorCollection.size()];
+ int i = 0;
+ for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
+ : authenticatorCollection) {
+ types[i] = authenticator.type;
+ i++;
+ }
+ return types;
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public Account[] getAccountsByType(String accountType) {
+ 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();
+ }
+ }
+
+ public boolean addAccount(Account account, String password, Bundle extras) {
+ checkAuthenticateAccountsPermission(account);
+
+ // fails if the account already exists
+ long identityToken = clearCallingIdentity();
+ try {
+ 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);
+ values.put(EXTRAS_ACCOUNTS_ID, accountId);
+ values.put(EXTRAS_VALUE, value);
+ return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+ }
+
+ public void removeAccount(IAccountManagerResponse response, Account account) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ 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();
+ try {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ invalidateAuthToken(db, accountType, authToken);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ 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
+ + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + TABLE_ACCOUNTS
+ + " JOIN " + TABLE_AUTHTOKENS
+ + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
+ + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ new String[]{authToken, accountType});
+ try {
+ while (cursor.moveToNext()) {
+ long authTokenId = cursor.getLong(0);
+ String accountName = cursor.getString(1);
+ String authTokenType = cursor.getString(2);
+ db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return false;
+ }
+ db.delete(TABLE_AUTHTOKENS,
+ AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{type});
+ ContentValues values = new ContentValues();
+ values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+ values.put(AUTHTOKENS_TYPE, type);
+ values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+ if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+ db.setTransactionSuccessful();
+ return true;
+ }
+ return false;
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public String readAuthTokenFromDatabase(Account account, String authTokenType) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return null;
+ }
+ return getAuthToken(db, accountId, authTokenType);
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public String peekAuthToken(Account account, String authTokenType) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ return readAuthTokenFromDatabase(account, authTokenType);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setAuthToken(Account account, String authTokenType, String authToken) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ cacheAuthToken(account, authTokenType, authToken);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setPassword(Account account, String password) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ sendAccountsChangedBroadcast();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void sendAccountsChangedBroadcast() {
+ mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
+ }
+
+ public void clearPassword(Account account) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ setPassword(account, null);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ 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 {
+ 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);
+ } 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 getAuthToken(IAccountManagerResponse response, final Account account,
+ final String authTokenType, final boolean notifyOnAuthFailure,
+ final boolean expectActivityLaunch, final Bundle loginOptions) {
+ checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
+ final int callerUid = Binder.getCallingUid();
+ final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
+
+ long identityToken = clearCallingIdentity();
+ try {
+ // if the caller has permission, do the peek. otherwise go the more expensive
+ // route of starting a Session
+ if (permissionGranted) {
+ String authToken = readAuthTokenFromDatabase(account, authTokenType);
+ if (authToken != null) {
+ Bundle result = new Bundle();
+ result.putString(Constants.AUTHTOKEN_KEY, authToken);
+ result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
+ onResult(response, result);
+ return;
+ }
+ }
+
+ new Session(response, account.type, expectActivityLaunch) {
+ protected String toDebugString(long now) {
+ if (loginOptions != null) loginOptions.keySet();
+ return super.toDebugString(now) + ", getAuthToken"
+ + ", " + account
+ + ", authTokenType " + authTokenType
+ + ", loginOptions " + loginOptions
+ + ", notifyOnAuthFailure " + notifyOnAuthFailure;
+ }
+
+ public void run() throws RemoteException {
+ // If the caller doesn't have permission then create and return the
+ // "grant permission" intent instead of the "getAuthToken" intent.
+ if (!permissionGranted) {
+ mAuthenticator.getAuthTokenLabel(this, authTokenType);
+ } else {
+ mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
+ }
+ }
+
+ public void onResult(Bundle result) {
+ if (result != null) {
+ if (result.containsKey(Constants.AUTH_TOKEN_LABEL_KEY)) {
+ Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
+ new AccountAuthenticatorResponse(this),
+ authTokenType,
+ result.getString(Constants.AUTH_TOKEN_LABEL_KEY));
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Constants.INTENT_KEY, intent);
+ onResult(bundle);
+ return;
+ }
+ String authToken = result.getString(Constants.AUTHTOKEN_KEY);
+ if (authToken != null) {
+ String name = result.getString(Constants.ACCOUNT_NAME_KEY);
+ String type = result.getString(Constants.ACCOUNT_TYPE_KEY);
+ if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
+ onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+ "the type and name should not be empty");
+ return;
+ }
+ cacheAuthToken(new Account(name, type), authTokenType, authToken);
+ }
+
+ Intent intent = result.getParcelable(Constants.INTENT_KEY);
+ if (intent != null && notifyOnAuthFailure) {
+ doNotification(
+ account, result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
+ intent);
+ }
+ }
+ super.onResult(result);
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
+ int uid = intent.getIntExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
+ String authTokenType = intent.getStringExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
+ String authTokenLabel = intent.getStringExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
+
+ Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
+ 0 /* when */);
+ final CharSequence subtitleFormatString =
+ mContext.getText(R.string.permission_request_notification_subtitle);
+ n.setLatestEventInfo(mContext,
+ mContext.getText(R.string.permission_request_notification_title),
+ 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);
+ }
+
+ private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
+ AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
+ RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
+ mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(account.type));
+ if (serviceInfo == null) {
+ throw new IllegalArgumentException("unknown account type: " + account.type);
+ }
+
+ final Context authContext;
+ try {
+ authContext = mContext.createPackageContext(
+ serviceInfo.type.packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("unknown account type: " + account.type);
+ }
+
+ Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(
+ String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
+ authContext.getString(serviceInfo.type.labelId));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
+ mContext.getPackageManager().getPackagesForUid(uid));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
+ return intent;
+ }
+
+ private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
+ int uid) {
+ Integer id;
+ synchronized(mCredentialsPermissionNotificationIds) {
+ final Pair<Pair<Account, String>, Integer> key =
+ new Pair<Pair<Account, String>, Integer>(
+ new Pair<Account, String>(account, authTokenType), uid);
+ id = mCredentialsPermissionNotificationIds.get(key);
+ if (id == null) {
+ id = mNotificationIds.incrementAndGet();
+ mCredentialsPermissionNotificationIds.put(key, id);
+ }
+ }
+ return id;
+ }
+
+ private Integer getSigninRequiredNotificationId(Account account) {
+ Integer id;
+ synchronized(mSigninRequiredNotificationIds) {
+ id = mSigninRequiredNotificationIds.get(account);
+ if (id == null) {
+ id = mNotificationIds.incrementAndGet();
+ mSigninRequiredNotificationIds.put(account, id);
+ }
+ }
+ return id;
+ }
+
+
+ public void addAcount(final IAccountManagerResponse response, final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final boolean expectActivityLaunch, final Bundle options) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, accountType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
+ options);
+ }
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", addAccount"
+ + ", accountType " + accountType
+ + ", requiredFeatures "
+ + (requiredFeatures != null
+ ? TextUtils.join(",", requiredFeatures)
+ : null);
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void confirmCredentials(IAccountManagerResponse response,
+ final Account account, final boolean expectActivityLaunch) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.confirmCredentials(this, account);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", confirmCredentials"
+ + ", " + account;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void confirmPassword(IAccountManagerResponse response, final Account account,
+ final String password) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, false /* expectActivityLaunch */) {
+ public void run() throws RemoteException {
+ mAuthenticator.confirmPassword(this, account, password);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", confirmPassword"
+ + ", " + account;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void updateCredentials(IAccountManagerResponse response, final Account account,
+ final String authTokenType, final boolean expectActivityLaunch,
+ final Bundle loginOptions) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
+ }
+ protected String toDebugString(long now) {
+ if (loginOptions != null) loginOptions.keySet();
+ return super.toDebugString(now) + ", updateCredentials"
+ + ", " + account
+ + ", authTokenType " + authTokenType
+ + ", loginOptions " + loginOptions;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void editProperties(IAccountManagerResponse response, final String accountType,
+ final boolean expectActivityLaunch) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, accountType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.editProperties(this, mAccountType);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", editProperties"
+ + ", accountType " + accountType;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private class GetAccountsByTypeAndFeatureSession extends Session {
+ private final String[] mFeatures;
+ private volatile Account[] mAccountsOfType = null;
+ private volatile ArrayList<Account> mAccountsWithFeatures = null;
+ private volatile int mCurrentAccount = 0;
+
+ public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
+ String type, String[] features) {
+ super(response, type, false /* expectActivityLaunch */);
+ mFeatures = features;
+ }
+
+ public void run() throws RemoteException {
+ mAccountsOfType = getAccountsByType(mAccountType);
+ // check whether each account matches the requested features
+ mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
+ mCurrentAccount = 0;
+
+ checkAccount();
+ }
+
+ public void checkAccount() {
+ if (mCurrentAccount >= mAccountsOfType.length) {
+ sendResult();
+ return;
+ }
+
+ try {
+ mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
+ } catch (RemoteException e) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
+ }
+ }
+
+ public void onResult(Bundle result) {
+ mNumResults++;
+ if (result == null) {
+ onError(Constants.ERROR_CODE_INVALID_RESPONSE, "null bundle");
+ return;
+ }
+ if (result.getBoolean(Constants.BOOLEAN_RESULT_KEY, false)) {
+ mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
+ }
+ mCurrentAccount++;
+ checkAccount();
+ }
+
+ public void sendResult() {
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ try {
+ Account[] accounts = new Account[mAccountsWithFeatures.size()];
+ for (int i = 0; i < accounts.length; i++) {
+ accounts[i] = mAccountsWithFeatures.get(i);
+ }
+ Bundle result = new Bundle();
+ result.putParcelableArray(Constants.ACCOUNTS_KEY, accounts);
+ response.onResult(result);
+ } 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);
+ }
+ }
+ }
+ }
+
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
+ + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
+ }
+ }
+
+ 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 (features != null && type == null) {
+ if (response != null) {
+ try {
+ response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
+ } catch (RemoteException e) {
+ // ignore this
+ }
+ }
+ return;
+ }
+ long identityToken = clearCallingIdentity();
+ try {
+ if (features == null || features.length == 0) {
+ getAccountsByType(type);
+ return;
+ }
+ new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
+ return saveAuthTokenToDatabase(account, authTokenType, authToken);
+ }
+
+ private long getAccountId(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
+ Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
+ Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
+ AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{authTokenType},
+ null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private abstract class Session extends IAccountAuthenticatorResponse.Stub
+ implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
+ IAccountManagerResponse mResponse;
+ final String mAccountType;
+ final boolean mExpectActivityLaunch;
+ final long mCreationTime;
+
+ public int mNumResults = 0;
+ private int mNumRequestContinued = 0;
+ private int mNumErrors = 0;
+
+
+ IAccountAuthenticator mAuthenticator = null;
+
+ public Session(IAccountManagerResponse response, String accountType,
+ boolean expectActivityLaunch) {
+ super();
+ if (response == null) throw new IllegalArgumentException("response is null");
+ if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ mResponse = response;
+ mAccountType = accountType;
+ mExpectActivityLaunch = expectActivityLaunch;
+ mCreationTime = SystemClock.elapsedRealtime();
+ synchronized (mSessions) {
+ mSessions.put(toString(), this);
+ }
+ try {
+ response.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ mResponse = null;
+ binderDied();
+ }
+ }
+
+ IAccountManagerResponse getResponseAndClose() {
+ if (mResponse == null) {
+ // this session has already been closed
+ return null;
+ }
+ IAccountManagerResponse response = mResponse;
+ close(); // this clears mResponse so we need to save the response before this call
+ return response;
+ }
+
+ private void close() {
+ synchronized (mSessions) {
+ if (mSessions.remove(toString()) == null) {
+ // the session was already closed, so bail out now
+ return;
+ }
+ }
+ if (mResponse != null) {
+ // stop listening for response deaths
+ mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
+
+ // clear this so that we don't accidentally send any further results
+ mResponse = null;
+ }
+ cancelTimeout();
+ unbind();
+ }
+
+ public void binderDied() {
+ mResponse = null;
+ close();
+ }
+
+ protected String toDebugString() {
+ return toDebugString(SystemClock.elapsedRealtime());
+ }
+
+ protected String toDebugString(long now) {
+ return "Session: expectLaunch " + mExpectActivityLaunch
+ + ", connected " + (mAuthenticator != null)
+ + ", stats (" + mNumResults + "/" + mNumRequestContinued
+ + "/" + mNumErrors + ")"
+ + ", lifetime " + ((now - mCreationTime) / 1000.0);
+ }
+
+ void bind() {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
+ }
+ if (!mBindHelper.bind(mAccountType, this)) {
+ Log.d(TAG, "bind attempt failed for " + toDebugString());
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
+ }
+ }
+
+ private void unbind() {
+ if (mAuthenticator != null) {
+ mAuthenticator = null;
+ mBindHelper.unbind(this);
+ }
+ }
+
+ public void scheduleTimeout() {
+ mMessageHandler.sendMessageDelayed(
+ mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
+ }
+
+ public void cancelTimeout() {
+ mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
+ }
+
+ public void onConnected(IBinder service) {
+ mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
+ try {
+ run();
+ } catch (RemoteException e) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "remote exception");
+ }
+ }
+
+ public abstract void run() throws RemoteException;
+
+ public void onDisconnected() {
+ mAuthenticator = null;
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "disconnected");
+ }
+ }
+
+ public void onTimedOut() {
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "timeout");
+ }
+ }
+
+ public void onResult(Bundle result) {
+ mNumResults++;
+ if (result != null && !TextUtils.isEmpty(result.getString(Constants.AUTHTOKEN_KEY))) {
+ String accountName = result.getString(Constants.ACCOUNT_NAME_KEY);
+ String accountType = result.getString(Constants.ACCOUNT_TYPE_KEY);
+ if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
+ Account account = new Account(accountName, accountType);
+ cancelNotification(getSigninRequiredNotificationId(account));
+ }
+ }
+ IAccountManagerResponse response;
+ if (mExpectActivityLaunch && result != null
+ && result.containsKey(Constants.INTENT_KEY)) {
+ response = mResponse;
+ } else {
+ response = getResponseAndClose();
+ }
+ if (response != null) {
+ try {
+ if (result == null) {
+ response.onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+ "null bundle returned");
+ } else {
+ response.onResult(result);
+ }
+ } 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 onRequestContinued() {
+ mNumRequestContinued++;
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ mNumErrors++;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
+ }
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: responding");
+ }
+ try {
+ response.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
+ }
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: already closed");
+ }
+ }
+ }
+ }
+
+ private class MessageHandler extends Handler {
+ MessageHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ if (mBindHelper.handleMessage(msg)) {
+ return;
+ }
+ switch (msg.what) {
+ case MESSAGE_TIMED_OUT:
+ Session session = (Session)msg.obj;
+ session.onTimedOut();
+ break;
+
+ default:
+ throw new IllegalStateException("unhandled message: " + msg.what);
+ }
+ }
+ }
+
+ private class DatabaseHelper extends SQLiteOpenHelper {
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PASSWORD + " TEXT, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
+ + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
+ + AUTHTOKENS_AUTHTOKEN + " TEXT, "
+ + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+ createGrantsTable(db);
+
+ db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+ + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+ + EXTRAS_KEY + " TEXT NOT NULL, "
+ + EXTRAS_VALUE + " TEXT, "
+ + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+ + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+ + META_VALUE + " TEXT)");
+
+ createAccountsDeletionTrigger(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 1) {
+ // no longer need to do anything since the work is done
+ // when upgrading from version 2
+ oldVersion++;
+ }
+
+ if (oldVersion == 2) {
+ createGrantsTable(db);
+ db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ oldVersion++;
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
+ }
+ }
+
+ private void setMetaValue(String key, String value) {
+ ContentValues values = new ContentValues();
+ values.put(META_KEY, key);
+ values.put(META_VALUE, value);
+ mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
+ }
+
+ private String getMetaValue(String key) {
+ Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
+ new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
+ try {
+ if (c.moveToNext()) {
+ return c.getString(0);
+ }
+ return null;
+ } finally {
+ c.close();
+ }
+ }
+
+ private class SimWatcher extends BroadcastReceiver {
+ public SimWatcher(Context context) {
+ // Re-scan the SIM card when the SIM state changes, and also if
+ // the disk recovers from a full state (we may have failed to handle
+ // things properly while the disk was full).
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
+ context.registerReceiver(this, filter);
+ }
+
+ /**
+ * Compare the IMSI to the one stored in the login service's
+ * database. If they differ, erase all passwords and
+ * authtokens (and store the new IMSI).
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
+ String imsi = ((TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE)).getSubscriberId();
+ if (TextUtils.isEmpty(imsi)) return;
+
+ String storedImsi = getMetaValue("imsi");
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
+ }
+
+ if (!imsi.equals(storedImsi) && !"initial".equals(storedImsi)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "wiping all passwords and authtokens");
+ }
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
+ db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
+ sendAccountsChangedBroadcast();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+ setMetaValue("imsi", imsi);
+ }
+ }
+
+ public IBinder onBind(Intent intent) {
+ return asBinder();
+ }
+
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ synchronized (mSessions) {
+ final long now = SystemClock.elapsedRealtime();
+ fout.println("AccountManagerService: " + mSessions.size() + " sessions");
+ for (Session session : mSessions.values()) {
+ fout.println(" " + session.toDebugString(now));
+ }
+ }
+
+ fout.println();
+
+ mAuthenticatorCache.dump(fd, fout, args);
+ }
+
+ private void doNotification(Account account, CharSequence message, Intent intent) {
+ long identityToken = clearCallingIdentity();
+ try {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "doNotification: " + message + " intent:" + intent);
+ }
+
+ if (intent.getComponent() != null &&
+ GrantCredentialsPermissionActivity.class.getName().equals(
+ intent.getComponent().getClassName())) {
+ createNoCredentialsPermissionNotification(account, intent);
+ } else {
+ Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
+ 0 /* when */);
+ n.setLatestEventInfo(mContext, mContext.getText(R.string.notification_title),
+ message, PendingIntent.getActivity(
+ mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .notify(getSigninRequiredNotificationId(account), n);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void cancelNotification(int id) {
+ long identityToken = clearCallingIdentity();
+ try {
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .cancel(id);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void checkBinderPermission(String permission) {
+ final int uid = Binder.getCallingUid();
+ if (mContext.checkCallingOrSelfPermission(permission) !=
+ PackageManager.PERMISSION_GRANTED) {
+ String msg = "caller uid " + uid + " lacks " + permission;
+ Log.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + uid + " has " + permission);
+ }
+ }
+
+ private boolean permissionIsGranted(Account account, String authTokenType, int 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 "
+ + callerUid + ", account " + account
+ + ": is authenticator? " + fromAuthenticator
+ + ", has explicit permission? " + hasExplicitGrants);
+ }
+ return fromAuthenticator || hasExplicitGrants;
+ }
+
+ private boolean hasAuthenticatorUid(String accountType, int callingUid) {
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
+ mAuthenticatorCache.getAllServices()) {
+ if (serviceInfo.type.type.equals(accountType)) {
+ return (serviceInfo.uid == callingUid) ||
+ (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
+ == PackageManager.SIGNATURE_MATCH);
+ }
+ }
+ return false;
+ }
+
+ private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
+ if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
+ return true;
+ }
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
+ account.name, account.type};
+ final boolean permissionGranted =
+ DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
+ if (!permissionGranted && isDebuggableMonkeyBuild) {
+ // TODO: Skip this check when running automated tests. Replace this
+ // with a more general solution.
+ Log.w(TAG, "no credentials permission for usage of " + account + ", "
+ + authTokenType + " by uid " + Binder.getCallingUid()
+ + " but ignoring since this is a monkey build");
+ return true;
+ }
+ return permissionGranted;
+ }
+
+ private void checkCallingUidAgainstAuthenticator(Account account) {
+ final int uid = Binder.getCallingUid();
+ 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);
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
+ }
+ }
+
+ private void checkAuthenticateAccountsPermission(Account account) {
+ checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
+ checkCallingUidAgainstAuthenticator(account);
+ }
+
+ private void checkReadAccountsPermission() {
+ checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
+ }
+
+ private void checkManageAccountsPermission() {
+ checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
+ }
+
+ /**
+ * Allow callers with the given uid permission to get credentials for account/authTokenType.
+ * <p>
+ * Although this is public it can only be accessed via the AccountManagerService object
+ * which is in the system. This means we don't need to protect it with permissions.
+ * @hide
+ */
+ public void grantAppPermission(Account account, String authTokenType, int uid) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId >= 0) {
+ ContentValues values = new ContentValues();
+ values.put(GRANTS_ACCOUNTS_ID, accountId);
+ values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+ values.put(GRANTS_GRANTEE_UID, uid);
+ db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
+ }
+
+ /**
+ * Don't allow callers with the given uid permission to get credentials for
+ * account/authTokenType.
+ * <p>
+ * Although this is public it can only be accessed via the AccountManagerService object
+ * which is in the system. This means we don't need to protect it with permissions.
+ * @hide
+ */
+ public void revokeAppPermission(Account account, String authTokenType, int uid) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId >= 0) {
+ db.delete(TABLE_GRANTS,
+ GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+ + GRANTS_GRANTEE_UID + "=?",
+ new String[]{String.valueOf(accountId), authTokenType,
+ String.valueOf(uid)});
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
+ }
+}
diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java
deleted file mode 100644
index f21385e..0000000
--- a/core/java/android/accounts/AccountMonitor.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.database.SQLException;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * A helper class that calls back on the provided
- * AccountMonitorListener with the set of current accounts both when
- * it gets created and whenever the set changes. It does this by
- * binding to the AccountsService and registering to receive the
- * intent broadcast when the set of accounts is changed. The
- * connection to the accounts service is only made when it needs to
- * fetch the current list of accounts (that is, when the
- * AccountMonitor is first created, and when the intent is received).
- */
-public class AccountMonitor extends BroadcastReceiver implements ServiceConnection {
- private final Context mContext;
- private final AccountMonitorListener mListener;
- private boolean mClosed = false;
- private int pending = 0;
-
- // This thread runs in the background and runs the code to update accounts
- // in the listener.
- private class AccountUpdater extends Thread {
- private IBinder mService;
-
- public AccountUpdater(IBinder service) {
- mService = service;
- }
-
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- IAccountsService accountsService = IAccountsService.Stub.asInterface(mService);
- String[] accounts = null;
- do {
- try {
- accounts = accountsService.getAccounts();
- } catch (RemoteException e) {
- // if the service was killed then the system will restart it and when it does we
- // will get another onServiceConnected, at which point we will do a notify.
- Log.w("AccountMonitor", "Remote exception when getting accounts", e);
- return;
- }
-
- synchronized (AccountMonitor.this) {
- --pending;
- if (pending == 0) {
- break;
- }
- }
- } while (true);
-
- mContext.unbindService(AccountMonitor.this);
-
- try {
- mListener.onAccountsUpdated(accounts);
- } catch (SQLException e) {
- // Better luck next time. If the problem was disk-full,
- // the STORAGE_OK intent will re-trigger the update.
- Log.e("AccountMonitor", "Can't update accounts", e);
- }
- }
- }
-
- /**
- * Initializes the AccountMonitor and initiates a bind to the
- * AccountsService to get the initial account list. For 1.0,
- * the "list" is always a single account.
- *
- * @param context the context we are running in
- * @param listener the user to notify when the account set changes
- */
- public AccountMonitor(Context context, AccountMonitorListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener is null");
- }
-
- mContext = context;
- mListener = listener;
-
- // Register a broadcast receiver to monitor account changes
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION);
- intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // To recover from disk-full.
- mContext.registerReceiver(this, intentFilter);
-
- // Send the listener the initial state now.
- notifyListener();
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- notifyListener();
- }
-
- public void onServiceConnected(ComponentName className, IBinder service) {
- // Create a background thread to update the accounts.
- new AccountUpdater(service).start();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- }
-
- private synchronized void notifyListener() {
- if (pending == 0) {
- // initiate the bind
- if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
- this, Context.BIND_AUTO_CREATE)) {
- // This is normal if GLS isn't part of this build.
- Log.w("AccountMonitor",
- "Couldn't connect to " +
- AccountsServiceConstants.SERVICE_INTENT +
- " (Missing service?)");
- }
- } else {
- // already bound. bindService will not trigger another
- // call to onServiceConnected, so instead we make sure
- // that the existing background thread will call
- // getAccounts() after this function returns, by
- // incrementing pending.
- //
- // Yes, this else clause contains only a comment.
- }
- ++pending;
- }
-
- /**
- * calls close()
- * @throws Throwable
- */
- @Override
- protected void finalize() throws Throwable {
- close();
- super.finalize();
- }
-
- /**
- * Unregisters the account receiver. Consecutive calls to this
- * method are harmless, but also do nothing. Once this call is
- * made no more notifications will occur.
- */
- public synchronized void close() {
- if (!mClosed) {
- mContext.unregisterReceiver(this);
- mClosed = true;
- }
- }
-}
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/AccountMonitorListener.java
deleted file mode 100644
index d0bd9a9..0000000
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-/**
- * An interface that contains the callback used by the AccountMonitor
- */
-public interface AccountMonitorListener {
- /**
- * This invoked when the AccountMonitor starts up and whenever the account
- * set changes.
- * @param currentAccounts the current accounts
- */
- void onAccountsUpdated(String[] currentAccounts);
-}
diff --git a/core/java/android/accounts/AccountsServiceConstants.java b/core/java/android/accounts/AccountsServiceConstants.java
deleted file mode 100644
index b882e7b..0000000
--- a/core/java/android/accounts/AccountsServiceConstants.java
+++ /dev/null
@@ -1,78 +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.accounts;
-
-import android.content.Intent;
-
-/**
- * Miscellaneous constants used by the AccountsService and its
- * clients.
- */
-// TODO: These constants *could* come directly from the
-// IAccountsService interface, but that's not possible since the
-// aidl compiler doesn't let you define constants (yet.)
-public class AccountsServiceConstants {
- /** This class is never instantiated. */
- private AccountsServiceConstants() {
- }
-
- /**
- * Action sent as a broadcast Intent by the AccountsService
- * when accounts are added to and/or removed from the device's
- * database, or when the primary account is changed.
- */
- public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
- "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-
- /**
- * Action sent as a broadcast Intent by the AccountsService
- * when it starts up and no accounts are available (so some should be added).
- */
- public static final String LOGIN_ACCOUNTS_MISSING_ACTION =
- "android.accounts.LOGIN_ACCOUNTS_MISSING";
-
- /**
- * Action on the intent used to bind to the IAccountsService interface. This
- * is used for services that have multiple interfaces (allowing
- * them to differentiate the interface intended, and return the proper
- * Binder.)
- */
- private static final String ACCOUNTS_SERVICE_ACTION = "android.accounts.IAccountsService";
-
- /*
- * The intent uses a component in addition to the action to ensure the actual
- * accounts service is bound to (a malicious third-party app could
- * theoretically have a service with the same action).
- */
- /** The intent used to bind to the accounts service. */
- public static final Intent SERVICE_INTENT =
- new Intent()
- .setClassName("com.google.android.googleapps",
- "com.google.android.googleapps.GoogleLoginService")
- .setAction(ACCOUNTS_SERVICE_ACTION);
-
- /**
- * Checks whether the intent is to bind to the accounts service.
- *
- * @param bindIntent The Intent used to bind to the service.
- * @return Whether the intent is to bind to the accounts service.
- */
- public static final boolean isForAccountsService(Intent bindIntent) {
- String otherAction = bindIntent.getAction();
- return otherAction != null && otherAction.equals(ACCOUNTS_SERVICE_ACTION);
- }
-}
diff --git a/core/java/android/accounts/AuthenticatorBindHelper.java b/core/java/android/accounts/AuthenticatorBindHelper.java
new file mode 100644
index 0000000..91e23ab
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorBindHelper.java
@@ -0,0 +1,252 @@
+/*
+ * 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.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+/**
+ * A helper object that simplifies binding to Account Authenticators. It uses the
+ * {@link AccountAuthenticatorCache} to find the component name of the authenticators,
+ * allowing the user to bind by account name. It also allows multiple, simultaneous binds
+ * to the same authenticator, with each bind call guaranteed to return either
+ * {@link Callback#onConnected} or {@link Callback#onDisconnected} if the bind() call
+ * itself succeeds, even if the authenticator is already bound internally.
+ * @hide
+ */
+public class AuthenticatorBindHelper {
+ private static final String TAG = "Accounts";
+ private final Handler mHandler;
+ private final Context mContext;
+ private final int mMessageWhatConnected;
+ private final int mMessageWhatDisconnected;
+ private final Map<String, MyServiceConnection> mServiceConnections = Maps.newHashMap();
+ private final Map<String, ArrayList<Callback>> mServiceUsers = Maps.newHashMap();
+ private final AccountAuthenticatorCache mAuthenticatorCache;
+
+ public AuthenticatorBindHelper(Context context,
+ AccountAuthenticatorCache authenticatorCache, Handler handler,
+ int messageWhatConnected, int messageWhatDisconnected) {
+ mContext = context;
+ mHandler = handler;
+ mAuthenticatorCache = authenticatorCache;
+ mMessageWhatConnected = messageWhatConnected;
+ mMessageWhatDisconnected = messageWhatDisconnected;
+ }
+
+ public interface Callback {
+ void onConnected(IBinder service);
+ void onDisconnected();
+ }
+
+ public boolean bind(String authenticatorType, Callback callback) {
+ // if the authenticator is connecting or connected then return true
+ synchronized (mServiceConnections) {
+ if (mServiceConnections.containsKey(authenticatorType)) {
+ MyServiceConnection connection = mServiceConnections.get(authenticatorType);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "service connection already exists for " + authenticatorType);
+ }
+ mServiceUsers.get(authenticatorType).add(callback);
+ if (connection.mService != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service is connected, scheduling a connected message for "
+ + authenticatorType);
+ }
+ connection.scheduleCallbackConnectedMessage(callback);
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service is *not* connected, waiting for for "
+ + authenticatorType);
+ }
+ }
+ return true;
+ }
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there is no service connection for " + authenticatorType);
+ }
+
+ // otherwise find the component name for the authenticator and initiate a bind
+ // if no authenticator or the bind fails then return false, otherwise return true
+ AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
+ mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(authenticatorType));
+ if (authenticatorInfo == null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there is no authenticator for " + authenticatorType
+ + ", bailing out");
+ }
+ return false;
+ }
+
+ MyServiceConnection connection = new MyServiceConnection(authenticatorType);
+
+ Intent intent = new Intent();
+ intent.setAction("android.accounts.AccountAuthenticator");
+ intent.setComponent(authenticatorInfo.componentName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
+ }
+ if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
+ }
+ return false;
+ }
+
+ mServiceConnections.put(authenticatorType, connection);
+ mServiceUsers.put(authenticatorType, Lists.newArrayList(callback));
+ return true;
+ }
+ }
+
+ public void unbind(Callback callbackToUnbind) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "unbinding callback " + callbackToUnbind);
+ }
+ synchronized (mServiceConnections) {
+ for (Map.Entry<String, ArrayList<Callback>> entry : mServiceUsers.entrySet()) {
+ final String authenticatorType = entry.getKey();
+ final ArrayList<Callback> serviceUsers = entry.getValue();
+ for (Callback callback : serviceUsers) {
+ if (callback == callbackToUnbind) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "found callback in service" + authenticatorType);
+ }
+ serviceUsers.remove(callbackToUnbind);
+ if (serviceUsers.isEmpty()) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there are no more callbacks for service "
+ + authenticatorType + ", unbinding service");
+ }
+ unbindFromService(authenticatorType);
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "leaving service " + authenticatorType
+ + " around since there are still callbacks using it");
+ }
+ }
+ return;
+ }
+ }
+ }
+ Log.e(TAG, "did not find callback " + callbackToUnbind + " in any of the services");
+ }
+ }
+
+ private void unbindFromService(String authenticatorType) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "unbindService from " + authenticatorType);
+ }
+ mContext.unbindService(mServiceConnections.get(authenticatorType));
+ mServiceUsers.remove(authenticatorType);
+ mServiceConnections.remove(authenticatorType);
+ }
+
+ private class ConnectedMessagePayload {
+ public final IBinder mService;
+ public final Callback mCallback;
+ public ConnectedMessagePayload(IBinder service, Callback callback) {
+ mService = service;
+ mCallback = callback;
+ }
+ }
+
+ private class MyServiceConnection implements ServiceConnection {
+ private final String mAuthenticatorType;
+ private IBinder mService = null;
+
+ public MyServiceConnection(String authenticatorType) {
+ mAuthenticatorType = authenticatorType;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onServiceConnected for account type " + mAuthenticatorType);
+ }
+ // post a message for each service user to tell them that the service is connected
+ synchronized (mServiceConnections) {
+ mService = service;
+ for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service became connected, scheduling a connected "
+ + "message for " + mAuthenticatorType);
+ }
+ scheduleCallbackConnectedMessage(callback);
+ }
+ }
+ }
+
+ private void scheduleCallbackConnectedMessage(Callback callback) {
+ final ConnectedMessagePayload payload =
+ new ConnectedMessagePayload(mService, callback);
+ mHandler.obtainMessage(mMessageWhatConnected, payload).sendToTarget();
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onServiceDisconnected for account type " + mAuthenticatorType);
+ }
+ // post a message for each service user to tell them that the service is disconnected,
+ // and unbind from the service.
+ synchronized (mServiceConnections) {
+ for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service became disconnected, scheduling a "
+ + "disconnected message for "
+ + mAuthenticatorType);
+ }
+ mHandler.obtainMessage(mMessageWhatDisconnected, callback).sendToTarget();
+ }
+ unbindFromService(mAuthenticatorType);
+ }
+ }
+ }
+
+ boolean handleMessage(Message message) {
+ if (message.what == mMessageWhatConnected) {
+ ConnectedMessagePayload payload = (ConnectedMessagePayload)message.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "notifying callback " + payload.mCallback + " that it is connected");
+ }
+ payload.mCallback.onConnected(payload.mService);
+ return true;
+ } else if (message.what == mMessageWhatDisconnected) {
+ Callback callback = (Callback)message.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "notifying callback " + callback + " that it is disconnected");
+ }
+ callback.onDisconnected();
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/accounts/AuthenticatorDescription.aidl b/core/java/android/accounts/AuthenticatorDescription.aidl
new file mode 100644
index 0000000..136361c
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorDescription.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+parcelable AuthenticatorDescription;
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
new file mode 100644
index 0000000..f896bf8
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -0,0 +1,69 @@
+package android.accounts;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class AuthenticatorDescription implements Parcelable {
+ final public String type;
+ final public int labelId;
+ final public int iconId;
+ final public String packageName;
+
+ public AuthenticatorDescription(String type, String packageName, int labelId, int iconId) {
+ this.type = type;
+ this.packageName = packageName;
+ this.labelId = labelId;
+ this.iconId = iconId;
+ }
+
+ public static AuthenticatorDescription newKey(String type) {
+ return new AuthenticatorDescription(type);
+ }
+
+ private AuthenticatorDescription(String type) {
+ this.type = type;
+ this.packageName = null;
+ this.labelId = 0;
+ this.iconId = 0;
+ }
+
+ private AuthenticatorDescription(Parcel source) {
+ this.type = source.readString();
+ this.packageName = source.readString();
+ this.labelId = source.readInt();
+ this.iconId = source.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof AuthenticatorDescription)) return false;
+ final AuthenticatorDescription other = (AuthenticatorDescription) o;
+ return type.equals(other.type);
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(type);
+ dest.writeString(packageName);
+ dest.writeInt(labelId);
+ dest.writeInt(iconId);
+ }
+
+ public static final Creator<AuthenticatorDescription> CREATOR =
+ new Creator<AuthenticatorDescription>() {
+ public AuthenticatorDescription createFromParcel(Parcel source) {
+ return new AuthenticatorDescription(source);
+ }
+
+ public AuthenticatorDescription[] newArray(int size) {
+ return new AuthenticatorDescription[size];
+ }
+ };
+}
diff --git a/core/java/android/accounts/AuthenticatorException.java b/core/java/android/accounts/AuthenticatorException.java
new file mode 100644
index 0000000..4023494
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorException.java
@@ -0,0 +1,32 @@
+/*
+ * 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 class AuthenticatorException extends Exception {
+ public AuthenticatorException() {
+ super();
+ }
+ public AuthenticatorException(String message) {
+ super(message);
+ }
+ public AuthenticatorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public AuthenticatorException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
new file mode 100644
index 0000000..bd6f205
--- /dev/null
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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.app.ListActivity;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.view.View;
+import android.util.Log;
+
+public class ChooseAccountActivity extends ListActivity {
+ private static final String TAG = "AccountManager";
+ private Parcelable[] mAccounts = null;
+ private AccountManagerResponse mAccountManagerResponse = null;
+ private Bundle mResult;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ mAccounts = getIntent().getParcelableArrayExtra(Constants.ACCOUNTS_KEY);
+ mAccountManagerResponse =
+ getIntent().getParcelableExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+ } else {
+ mAccounts = savedInstanceState.getParcelableArray(Constants.ACCOUNTS_KEY);
+ mAccountManagerResponse =
+ savedInstanceState.getParcelable(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+ }
+
+ String[] mAccountNames = new String[mAccounts.length];
+ for (int i = 0; i < mAccounts.length; i++) {
+ mAccountNames[i] = ((Account) mAccounts[i]).name;
+ }
+
+ // Use an existing ListAdapter that will map an array
+ // of strings to TextViews
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, mAccountNames));
+ getListView().setTextFilterEnabled(true);
+ }
+
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ Account account = (Account) mAccounts[position];
+ Log.d(TAG, "selected account " + account);
+ Bundle bundle = new Bundle();
+ bundle.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+ bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
+ mResult = bundle;
+ finish();
+ }
+
+ public void finish() {
+ if (mAccountManagerResponse != null) {
+ if (mResult != null) {
+ mAccountManagerResponse.onResult(mResult);
+ } else {
+ mAccountManagerResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ }
+ super.finish();
+ }
+}
diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java
new file mode 100644
index 0000000..8736f41
--- /dev/null
+++ b/core/java/android/accounts/Constants.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.accounts;
+
+public class Constants {
+ // this should never be instantiated
+ private Constants() {}
+
+ public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
+ public static final int ERROR_CODE_NETWORK_ERROR = 3;
+ public static final int ERROR_CODE_CANCELED = 4;
+ public static final int ERROR_CODE_INVALID_RESPONSE = 5;
+ public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
+ public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
+ public static final int ERROR_CODE_BAD_REQUEST = 8;
+
+ public static final String ACCOUNTS_KEY = "accounts";
+ 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";
+ public static final String ERROR_MESSAGE_KEY = "errorMessage";
+ public static final String INTENT_KEY = "intent";
+ public static final String BOOLEAN_RESULT_KEY = "booleanResult";
+ public static final String ACCOUNT_AUTHENTICATOR_RESPONSE_KEY = "accountAuthenticatorResponse";
+ public static final String ACCOUNT_MANAGER_RESPONSE_KEY = "accountManagerResponse";
+ public static final String AUTH_FAILED_MESSAGE_KEY = "authFailedMessage";
+ public static final String AUTH_TOKEN_LABEL_KEY = "authTokenLabelKey";
+
+ public static final String AUTHENTICATOR_INTENT_ACTION =
+ "android.accounts.AccountAuthenticator";
+ public static final String AUTHENTICATOR_META_DATA_NAME =
+ "android.accounts.AccountAuthenticator";
+ public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
+
+ /**
+ * Action sent as a broadcast Intent by the AccountsService
+ * when accounts are added to and/or removed from the device's
+ * database, or when the primary account is changed.
+ */
+ public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
+ "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
new file mode 100644
index 0000000..e06afb4
--- /dev/null
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -0,0 +1,172 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
+ public static final String EXTRAS_ACCOUNT = "account";
+ public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
+ public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
+ public static final String EXTRAS_RESPONSE = "response";
+ public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
+ public static final String EXTRAS_PACKAGES = "application";
+ public static final String EXTRAS_REQUESTING_UID = "uid";
+ private Account mAccount;
+ private String mAuthTokenType;
+ private int mUid;
+ private Bundle mResultBundle = null;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setContentView(R.layout.grant_credentials_permission);
+ mAccount = getIntent().getExtras().getParcelable(EXTRAS_ACCOUNT);
+ mAuthTokenType = getIntent().getExtras().getString(EXTRAS_AUTH_TOKEN_TYPE);
+ mUid = getIntent().getExtras().getInt(EXTRAS_REQUESTING_UID);
+ final String accountTypeLabel =
+ getIntent().getExtras().getString(EXTRAS_ACCOUNT_TYPE_LABEL);
+ final String[] packages = getIntent().getExtras().getStringArray(EXTRAS_PACKAGES);
+
+ findViewById(R.id.allow).setOnClickListener(this);
+ findViewById(R.id.deny).setOnClickListener(this);
+
+ TextView messageView = (TextView) getWindow().findViewById(R.id.message);
+ String authTokenLabel = getIntent().getExtras().getString(EXTRAS_AUTH_TOKEN_LABEL);
+ if (authTokenLabel.length() == 0) {
+ CharSequence grantCredentialsPermissionFormat = getResources().getText(
+ R.string.grant_credentials_permission_message_desc);
+ messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
+ 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.name, accountTypeLabel));
+ }
+
+ String[] packageLabels = new String[packages.length];
+ final PackageManager pm = getPackageManager();
+ for (int i = 0; i < packages.length; i++) {
+ try {
+ packageLabels[i] =
+ pm.getApplicationLabel(pm.getApplicationInfo(packages[i], 0)).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ packageLabels[i] = packages[i];
+ }
+ }
+ ((ListView) findViewById(R.id.packages_list)).setAdapter(
+ new PackagesArrayAdapter(this, packageLabels));
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.allow:
+ AccountManagerService.getSingleton().grantAppPermission(mAccount, mAuthTokenType,
+ mUid);
+ Intent result = new Intent();
+ result.putExtra("retry", true);
+ setResult(RESULT_OK, result);
+ setAccountAuthenticatorResult(result.getExtras());
+ break;
+
+ case R.id.deny:
+ AccountManagerService.getSingleton().revokeAppPermission(mAccount, mAuthTokenType,
+ mUid);
+ setResult(RESULT_CANCELED);
+ break;
+ }
+ finish();
+ }
+
+ public final void setAccountAuthenticatorResult(Bundle result) {
+ mResultBundle = result;
+ }
+
+ /**
+ * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
+ */
+ public void finish() {
+ Intent intent = getIntent();
+ AccountAuthenticatorResponse accountAuthenticatorResponse =
+ intent.getParcelableExtra(EXTRAS_RESPONSE);
+ if (accountAuthenticatorResponse != null) {
+ // send the result bundle back if set, otherwise send an error.
+ if (mResultBundle != null) {
+ accountAuthenticatorResponse.onResult(mResultBundle);
+ } else {
+ accountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ }
+ super.finish();
+ }
+
+ private static class PackagesArrayAdapter extends ArrayAdapter<String> {
+ protected LayoutInflater mInflater;
+ private static final int mResource = R.layout.simple_list_item_1;
+
+ public PackagesArrayAdapter(Context context, String[] items) {
+ super(context, mResource, items);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ static class ViewHolder {
+ TextView label;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // A ViewHolder keeps references to children views to avoid unneccessary calls
+ // to findViewById() on each row.
+ ViewHolder holder;
+
+ // When convertView is not null, we can reuse it directly, there is no need
+ // to reinflate it. We only inflate a new View when the convertView supplied
+ // by ListView is null.
+ if (convertView == null) {
+ convertView = mInflater.inflate(mResource, null);
+
+ // Creates a ViewHolder and store references to the two children views
+ // we want to bind data to.
+ holder = new ViewHolder();
+ holder.label = (TextView) convertView.findViewById(R.id.text1);
+
+ convertView.setTag(holder);
+ } else {
+ // Get the ViewHolder back to get fast access to the TextView
+ // and the ImageView.
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ holder.label.setText(getItem(position));
+
+ return convertView;
+ }
+ }
+}
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
new file mode 100644
index 0000000..48f053c
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -0,0 +1,78 @@
+/*
+ * 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.accounts.IAccountAuthenticatorResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Service that allows the interaction with an authentication server.
+ */
+oneway interface IAccountAuthenticator {
+ /**
+ * prompts the user for account information and adds the result to the IAccountManager
+ */
+ void addAccount(in IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, in String[] requiredFeatures, in Bundle options);
+
+ /**
+ * Checks that the account/password combination is valid.
+ * @deprecated
+ */
+ void confirmPassword(in IAccountAuthenticatorResponse response,
+ in Account account, String password);
+
+ /**
+ * prompts the user for the credentials of the account
+ */
+ void confirmCredentials(in IAccountAuthenticatorResponse response, in Account account);
+
+ /**
+ * gets the password by either prompting the user or querying the IAccountManager
+ */
+ void getAuthToken(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * Gets the user-visible label of the given authtoken type.
+ */
+ void getAuthTokenLabel(in IAccountAuthenticatorResponse response, String authTokenType);
+
+ /**
+ * prompts the user for a new password and writes it to the IAccountManager
+ */
+ void updateCredentials(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * launches an activity that lets the user edit and set the properties for an authenticator
+ */
+ void editProperties(in IAccountAuthenticatorResponse response, String accountType);
+
+ /**
+ * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
+ * specified features
+ */
+ 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/IAccountAuthenticatorResponse.aidl b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
new file mode 100644
index 0000000..a9ac2f1
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * The interface used to return responses from an {@link IAccountAuthenticator}
+ */
+oneway interface IAccountAuthenticatorResponse {
+ void onResult(in Bundle value);
+ void onRequestContinued();
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
new file mode 100644
index 0000000..411952b
--- /dev/null
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -0,0 +1,62 @@
+/*
+ * 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.accounts.IAccountManagerResponse;
+import android.accounts.Account;
+import android.accounts.AuthenticatorDescription;
+import android.os.Bundle;
+
+
+/**
+ * Central application service that provides account management.
+ * @hide
+ */
+interface IAccountManager {
+ String getPassword(in Account account);
+ String getUserData(in Account account, String key);
+ AuthenticatorDescription[] getAuthenticatorTypes();
+ 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 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);
+ void setPassword(in Account account, String password);
+ void clearPassword(in Account account);
+ void setUserData(in Account account, String key, String value);
+
+ void getAuthToken(in IAccountManagerResponse response, in Account account,
+ String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
+ in Bundle options);
+ void addAcount(in IAccountManagerResponse response, String accountType,
+ String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
+ in Bundle options);
+ void updateCredentials(in IAccountManagerResponse response, in Account account,
+ String authTokenType, boolean expectActivityLaunch, in Bundle options);
+ void editProperties(in IAccountManagerResponse response, String accountType,
+ boolean expectActivityLaunch);
+ void confirmCredentials(in IAccountManagerResponse response, in Account account,
+ boolean expectActivityLaunch);
+
+ /*
+ * @deprecated
+ */
+ void confirmPassword(in IAccountManagerResponse response, in Account account,
+ String password);
+}
diff --git a/core/java/android/accounts/IAccountManagerResponse.aidl b/core/java/android/accounts/IAccountManagerResponse.aidl
new file mode 100644
index 0000000..ca1203d
--- /dev/null
+++ b/core/java/android/accounts/IAccountManagerResponse.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * The interface used to return responses for asynchronous calls to the {@link IAccountManager}
+ * @hide
+ */
+oneway interface IAccountManagerResponse {
+ void onResult(in Bundle value);
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/core/java/android/accounts/IAccountsService.aidl b/core/java/android/accounts/IAccountsService.aidl
deleted file mode 100644
index dda513c..0000000
--- a/core/java/android/accounts/IAccountsService.aidl
+++ /dev/null
@@ -1,54 +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.accounts;
-
-/**
- * Central application service that allows querying the list of accounts.
- */
-interface IAccountsService {
- /**
- * Gets the list of Accounts the user has previously logged
- * in to. Accounts are of the form "username@domain".
- * <p>
- * This method will return an empty array if the device doesn't
- * know about any accounts (yet).
- *
- * @return The accounts. The array will be zero-length if the
- * AccountsService doesn't know about any accounts yet.
- */
- String[] getAccounts();
-
- /**
- * This is an interim solution for bypassing a forgotten gesture on the
- * unlock screen (it is hidden, please make sure it stays this way!). This
- * will be *removed* when the unlock screen design supports additional
- * authenticators.
- * <p>
- * The user will be presented with username and password fields that are
- * called as parameters to this method. If true is returned, the user is
- * able to define a new gesture and get back into the system. If false, the
- * user can try again.
- *
- * @param username The username entered.
- * @param password The password entered.
- * @return Whether to allow the user to bypass the lock screen and define a
- * new gesture.
- * @hide (The package is already hidden, but just in case someone
- * unhides that, this should not be revealed.)
- */
- boolean shouldUnlock(String username, String password);
-}
diff --git a/core/java/android/accounts/NetworkErrorException.java b/core/java/android/accounts/NetworkErrorException.java
new file mode 100644
index 0000000..f855cc8
--- /dev/null
+++ b/core/java/android/accounts/NetworkErrorException.java
@@ -0,0 +1,31 @@
+/*
+ * 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 class NetworkErrorException extends Exception {
+ public NetworkErrorException() {
+ super();
+ }
+ public NetworkErrorException(String message) {
+ super(message);
+ }
+ public NetworkErrorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public NetworkErrorException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/OnAccountsUpdatedListener.java b/core/java/android/accounts/OnAccountsUpdatedListener.java
new file mode 100644
index 0000000..bd249d0
--- /dev/null
+++ b/core/java/android/accounts/OnAccountsUpdatedListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+/**
+ * An interface that contains the callback used by the AccountMonitor
+ */
+public interface OnAccountsUpdatedListener {
+ /**
+ * This invoked when the AccountMonitor starts up and whenever the account
+ * set changes.
+ * @param accounts the current accounts
+ */
+ void onAccountsUpdated(Account[] accounts);
+}
diff --git a/core/java/android/accounts/OperationCanceledException.java b/core/java/android/accounts/OperationCanceledException.java
new file mode 100644
index 0000000..2f2c164
--- /dev/null
+++ b/core/java/android/accounts/OperationCanceledException.java
@@ -0,0 +1,31 @@
+/*
+ * 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 class OperationCanceledException extends Exception {
+ public OperationCanceledException() {
+ super();
+ }
+ public OperationCanceledException(String message) {
+ super(message);
+ }
+ public OperationCanceledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public OperationCanceledException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/accounts/package.html b/core/java/android/accounts/package.html
deleted file mode 100755
index c9f96a6..0000000
--- a/core/java/android/accounts/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4ac3b9e..2f79fe9 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2394,6 +2394,7 @@
*
* @param id The id of the managed dialog.
*
+ * @see Dialog
* @see #onCreateDialog(int)
* @see #onPrepareDialog(int, Dialog)
* @see #dismissDialog(int)
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 92929ea..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;
@@ -59,8 +59,6 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.location.ILocationManager;
@@ -78,7 +76,6 @@
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.Looper;
-import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -88,14 +85,14 @@
import android.telephony.TelephonyManager;
import android.text.ClipboardManager;
import android.util.AndroidRuntimeException;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ContextThemeWrapper;
-import android.view.Display;
import android.view.LayoutInflater;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
import java.io.File;
import java.io.FileInputStream;
@@ -155,14 +152,12 @@
private final static boolean DEBUG_ICONS = false;
private static final Object sSync = new Object();
+ private static AccountManager sAccountManager;
private static AlarmManager sAlarmManager;
private static PowerManager sPowerManager;
private static ConnectivityManager sConnectivityManager;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
- private static boolean sIsBluetoothDeviceCached = false;
- private static BluetoothDevice sBluetoothDevice;
- private static IWallpaperService sWallpaperService;
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
new HashMap<File, SharedPreferencesImpl>();
@@ -177,8 +172,8 @@
private Resources.Theme mTheme = null;
private PackageManager mPackageManager;
private NotificationManager mNotificationManager = null;
- private AccessibilityManager mAccessibilityManager = null;
private ActivityManager mActivityManager = null;
+ private WallpaperManager mWallpaperManager = null;
private Context mReceiverRestrictedContext = null;
private SearchManager mSearchManager = null;
private SensorManager mSensorManager = null;
@@ -187,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();
@@ -198,9 +195,6 @@
private File mCacheDir;
- private Drawable mWallpaper;
- private IWallpaperServiceCallback mWallpaperCallback = null;
-
private static long sInstanceCount = 0;
private static final String[] EMPTY_FILE_LIST = {};
@@ -520,127 +514,37 @@
@Override
public Drawable getWallpaper() {
- Drawable dr = peekWallpaper();
- return dr != null ? dr : getResources().getDrawable(
- com.android.internal.R.drawable.default_wallpaper);
+ return getWallpaperManager().getDrawable();
}
@Override
- public synchronized Drawable peekWallpaper() {
- if (mWallpaper != null) {
- return mWallpaper;
- }
- mWallpaperCallback = new WallpaperCallback(this);
- mWallpaper = getCurrentWallpaperLocked();
- return mWallpaper;
- }
-
- private Drawable getCurrentWallpaperLocked() {
- try {
- ParcelFileDescriptor fd = getWallpaperService().getWallpaper(mWallpaperCallback);
- if (fd != null) {
- Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
- if (bm != null) {
- // For now clear the density until we figure out how
- // to deal with it for wallpapers.
- bm.setDensity(0);
- return new BitmapDrawable(getResources(), bm);
- }
- }
- } catch (RemoteException e) {
- }
- return null;
+ public Drawable peekWallpaper() {
+ return getWallpaperManager().peekDrawable();
}
@Override
public int getWallpaperDesiredMinimumWidth() {
- try {
- return getWallpaperService().getWidthHint();
- } catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
- }
+ return getWallpaperManager().getDesiredMinimumWidth();
}
@Override
public int getWallpaperDesiredMinimumHeight() {
- try {
- return getWallpaperService().getHeightHint();
- } catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
- }
+ return getWallpaperManager().getDesiredMinimumHeight();
}
@Override
public void setWallpaper(Bitmap bitmap) throws IOException {
- try {
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd == null) {
- return;
- }
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- } catch (RemoteException e) {
- }
+ getWallpaperManager().setBitmap(bitmap);
}
@Override
public void setWallpaper(InputStream data) throws IOException {
- try {
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd == null) {
- return;
- }
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(data, fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- } catch (RemoteException e) {
- }
- }
-
- private void setWallpaper(InputStream data, FileOutputStream fos)
- throws IOException {
- byte[] buffer = new byte[32768];
- int amt;
- while ((amt=data.read(buffer)) > 0) {
- fos.write(buffer, 0, amt);
- }
+ getWallpaperManager().setStream(data);
}
@Override
public void clearWallpaper() throws IOException {
- try {
- /* Set the wallpaper to the default values */
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd != null) {
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(getResources().openRawResource(
- com.android.internal.R.drawable.default_wallpaper),
- fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- }
- } catch (RemoteException e) {
- }
+ getWallpaperManager().clear();
}
@Override
@@ -901,8 +805,12 @@
}
} else if (ACTIVITY_SERVICE.equals(name)) {
return getActivityManager();
+ } else if (INPUT_METHOD_SERVICE.equals(name)) {
+ return InputMethodManager.getInstance(this);
} else if (ALARM_SERVICE.equals(name)) {
return getAlarmManager();
+ } else if (ACCOUNT_SERVICE.equals(name)) {
+ return getAccountManager();
} else if (POWER_SERVICE.equals(name)) {
return getPowerManager();
} else if (CONNECTIVITY_SERVICE.equals(name)) {
@@ -919,10 +827,10 @@
return getLocationManager();
} else if (SEARCH_SERVICE.equals(name)) {
return getSearchManager();
- } else if ( SENSOR_SERVICE.equals(name)) {
+ } 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)) {
@@ -938,13 +846,24 @@
return getTelephonyManager();
} else if (CLIPBOARD_SERVICE.equals(name)) {
return getClipboardManager();
- } else if (INPUT_METHOD_SERVICE.equals(name)) {
- return InputMethodManager.getInstance(this);
+ } else if (WALLPAPER_SERVICE.equals(name)) {
+ return getWallpaperManager();
}
return null;
}
+ private AccountManager getAccountManager() {
+ synchronized (sSync) {
+ if (sAccountManager == null) {
+ IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+ IAccountManager service = IAccountManager.Stub.asInterface(b);
+ sAccountManager = new AccountManager(this, service);
+ }
+ }
+ return sAccountManager;
+ }
+
private ActivityManager getActivityManager() {
synchronized (mSync) {
if (mActivityManager == null) {
@@ -1001,8 +920,7 @@
return sWifiManager;
}
- private NotificationManager getNotificationManager()
- {
+ private NotificationManager getNotificationManager() {
synchronized (mSync) {
if (mNotificationManager == null) {
mNotificationManager = new NotificationManager(
@@ -1013,6 +931,16 @@
return mNotificationManager;
}
+ private WallpaperManager getWallpaperManager() {
+ synchronized (mSync) {
+ if (mWallpaperManager == null) {
+ mWallpaperManager = new WallpaperManager(getOuterContext(),
+ mMainThread.getHandler());
+ }
+ }
+ return mWallpaperManager;
+ }
+
private TelephonyManager getTelephonyManager() {
synchronized (mSync) {
if (mTelephonyManager == null) {
@@ -1052,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() {
@@ -1087,16 +1010,6 @@
return mVibrator;
}
- private IWallpaperService getWallpaperService() {
- synchronized (sSync) {
- if (sWallpaperService == null) {
- IBinder b = ServiceManager.getService(WALLPAPER_SERVICE);
- sWallpaperService = IWallpaperService.Stub.asInterface(b);
- }
- }
- return sWallpaperService;
- }
-
private AudioManager getAudioManager()
{
if (mAudioManager == null) {
@@ -1746,6 +1659,15 @@
}
@Override
+ public int checkSignatures(int uid1, int uid2) {
+ try {
+ return mPM.checkUidSignatures(uid1, uid2);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
try {
return mPM.getPackagesForUid(uid);
@@ -2801,25 +2723,4 @@
return false;
}
}
-
- private static class WallpaperCallback extends IWallpaperServiceCallback.Stub {
- private WeakReference<ApplicationContext> mContext;
-
- public WallpaperCallback(ApplicationContext context) {
- mContext = new WeakReference<ApplicationContext>(context);
- }
-
- public synchronized void onWallpaperChanged() {
-
- /* The wallpaper has changed but we shouldn't eagerly load the
- * wallpaper as that would be inefficient. Reset the cached wallpaper
- * to null so if the user requests the wallpaper again then we'll
- * fetch it.
- */
- final ApplicationContext applicationContext = mContext.get();
- if (applicationContext != null) {
- applicationContext.mWallpaper = null;
- }
- }
- }
}
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 6b17236..aeae5f9 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -171,6 +171,11 @@
public String throwMethodName;
/**
+ * Line number the exception was thrown from.
+ */
+ public int throwLineNumber;
+
+ /**
* Stack trace.
*/
public String stackTrace;
@@ -190,6 +195,7 @@
throwFileName = in.readString();
throwClassName = in.readString();
throwMethodName = in.readString();
+ throwLineNumber = in.readInt();
stackTrace = in.readString();
}
@@ -202,6 +208,7 @@
dest.writeString(throwFileName);
dest.writeString(throwClassName);
dest.writeString(throwMethodName);
+ dest.writeInt(throwLineNumber);
dest.writeString(stackTrace);
}
@@ -214,6 +221,7 @@
pw.println(prefix + "throwFileName: " + throwFileName);
pw.println(prefix + "throwClassName: " + throwClassName);
pw.println(prefix + "throwMethodName: " + throwMethodName);
+ pw.println(prefix + "throwLineNumber: " + throwLineNumber);
pw.println(prefix + "stackTrace: " + stackTrace);
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index a3c6325..5335239 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -524,7 +524,8 @@
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
data.writeInt(backupMode);
- mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null, 0);
+ mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
data.recycle();
}
@@ -532,7 +533,8 @@
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
- mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null, 0);
+ mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
data.recycle();
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
new file mode 100644
index 0000000..7741668
--- /dev/null
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -0,0 +1,61 @@
+/**
+ * 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.app;
+
+import android.os.ParcelFileDescriptor;
+import android.app.IWallpaperManagerCallback;
+import android.content.ComponentName;
+
+/** @hide */
+interface IWallpaperManager {
+
+ /**
+ * Set the wallpaper.
+ */
+ ParcelFileDescriptor setWallpaper(String name);
+
+ /**
+ * Set the live wallpaper.
+ */
+ void setWallpaperComponent(in ComponentName name);
+
+ /**
+ * Get the wallpaper.
+ */
+ ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb);
+
+ /**
+ * Clear the wallpaper.
+ */
+ void clearWallpaper();
+
+ /**
+ * Sets the dimension hint for the wallpaper. These hints indicate the desired
+ * minimum width and height for the wallpaper.
+ */
+ void setDimensionHints(in int width, in int height);
+
+ /**
+ * Returns the desired minimum width for the wallpaper.
+ */
+ int getWidthHint();
+
+ /**
+ * Returns the desired minimum height for the wallpaper.
+ */
+ int getHeightHint();
+}
diff --git a/core/java/android/app/IWallpaperManagerCallback.aidl b/core/java/android/app/IWallpaperManagerCallback.aidl
new file mode 100644
index 0000000..991b2bc
--- /dev/null
+++ b/core/java/android/app/IWallpaperManagerCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.app;
+
+/**
+ * Callback interface used by IWallpaperManager to send asynchronous
+ * notifications back to its clients. Note that this is a
+ * one-way interface so the server does not block waiting for the client.
+ *
+ * @hide
+ */
+oneway interface IWallpaperManagerCallback {
+ /**
+ * Called when the wallpaper has changed
+ */
+ void onWallpaperChanged();
+}
diff --git a/core/java/android/app/IWallpaperService.aidl b/core/java/android/app/IWallpaperService.aidl
deleted file mode 100644
index a332b1a..0000000
--- a/core/java/android/app/IWallpaperService.aidl
+++ /dev/null
@@ -1,55 +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.app;
-
-import android.os.ParcelFileDescriptor;
-import android.app.IWallpaperServiceCallback;
-
-/** @hide */
-interface IWallpaperService {
-
- /**
- * Set the wallpaper.
- */
- ParcelFileDescriptor setWallpaper();
-
- /**
- * Get the wallpaper.
- */
- ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb);
-
- /**
- * Clear the wallpaper.
- */
- void clearWallpaper();
-
- /**
- * Sets the dimension hint for the wallpaper. These hints indicate the desired
- * minimum width and height for the wallpaper.
- */
- void setDimensionHints(in int width, in int height);
-
- /**
- * Returns the desired minimum width for the wallpaper.
- */
- int getWidthHint();
-
- /**
- * Returns the desired minimum height for the wallpaper.
- */
- int getHeightHint();
-}
diff --git a/core/java/android/app/IWallpaperServiceCallback.aidl b/core/java/android/app/IWallpaperServiceCallback.aidl
deleted file mode 100644
index 6086f40..0000000
--- a/core/java/android/app/IWallpaperServiceCallback.aidl
+++ /dev/null
@@ -1,31 +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.app;
-
-/**
- * Callback interface used by IWallpaperService to send asynchronous
- * notifications back to its clients. Note that this is a
- * one-way interface so the server does not block waiting for the client.
- *
- * @hide
- */
-oneway interface IWallpaperServiceCallback {
- /**
- * Called when the wallpaper has changed
- */
- void onWallpaperChanged();
-}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9834c75..a67e60b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -458,7 +458,9 @@
sb.append(this.vibrate[i]);
sb.append(',');
}
- sb.append(this.vibrate[N]);
+ if (N != -1) {
+ sb.append(this.vibrate[N]);
+ }
sb.append("]");
} else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
sb.append("default");
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
new file mode 100644
index 0000000..c5ca0a3
--- /dev/null
+++ b/core/java/android/app/WallpaperManager.java
@@ -0,0 +1,369 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.ViewRoot;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class WallpaperManager {
+ private static String TAG = "WallpaperManager";
+ private static boolean DEBUG = false;
+
+ /**
+ * Launch an activity for the user to pick the current global live
+ * wallpaper.
+ * @hide
+ */
+ public static final String ACTION_LIVE_WALLPAPER_CHOOSER
+ = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
+
+ private final Context mContext;
+
+ static class Globals extends IWallpaperManagerCallback.Stub {
+ private IWallpaperManager mService;
+ private Drawable mWallpaper;
+
+ Globals() {
+ IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+ mService = IWallpaperManager.Stub.asInterface(b);
+ }
+
+ public void onWallpaperChanged() {
+ /* The wallpaper has changed but we shouldn't eagerly load the
+ * wallpaper as that would be inefficient. Reset the cached wallpaper
+ * to null so if the user requests the wallpaper again then we'll
+ * fetch it.
+ */
+ synchronized (this) {
+ mWallpaper = null;
+ }
+ }
+
+ public Drawable peekWallpaper(Context context) {
+ synchronized (this) {
+ if (mWallpaper != null) {
+ return mWallpaper;
+ }
+ mWallpaper = getCurrentWallpaperLocked(context);
+ return mWallpaper;
+ }
+ }
+
+ private Drawable getCurrentWallpaperLocked(Context context) {
+ try {
+ ParcelFileDescriptor fd = mService.getWallpaper(this);
+ if (fd != null) {
+ 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.
+ bm.setDensity(0);
+ return new BitmapDrawable(context.getResources(), bm);
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+ }
+
+ private static Object mSync = new Object();
+ private static Globals sGlobals;
+
+ static Globals getGlobals() {
+ synchronized (mSync) {
+ if (sGlobals == null) {
+ sGlobals = new Globals();
+ }
+ return sGlobals;
+ }
+ }
+
+ /*package*/ WallpaperManager(Context context, Handler handler) {
+ mContext = context;
+ }
+
+ /**
+ * Retrieve a WallpaperManager associated with the given Context.
+ */
+ public static WallpaperManager getInstance(Context context) {
+ return (WallpaperManager)context.getSystemService(
+ Context.WALLPAPER_SERVICE);
+ }
+
+ /** @hide */
+ public IWallpaperManager getIWallpaperManager() {
+ return getGlobals().mService;
+ }
+
+ /**
+ * Like {@link #peekDrawable}, but always returns a valid Drawable. If
+ * no wallpaper is set, the system default wallpaper is returned.
+ *
+ * @return Returns a Drawable object that will draw the wallpaper.
+ */
+ public Drawable getDrawable() {
+ Drawable dr = peekDrawable();
+ return dr != null ? dr : Resources.getSystem().getDrawable(
+ com.android.internal.R.drawable.default_wallpaper);
+ }
+
+ /**
+ * Retrieve the current system wallpaper. This is returned as an
+ * abstract Drawable that you can install in a View to display whatever
+ * wallpaper the user has currently set. If there is no wallpaper set,
+ * a null pointer is returned.
+ *
+ * @return Returns a Drawable object that will draw the wallpaper or a
+ * null pointer if these is none.
+ */
+ public Drawable peekDrawable() {
+ return getGlobals().peekWallpaper(mContext);
+ }
+
+ /**
+ * Change the current system wallpaper to the bitmap in the given resource.
+ * The resource is opened as a raw data stream and copied into the
+ * wallpaper; it must be a valid PNG or JPEG image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * @param resid The bitmap to save.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setResource(int resid) throws IOException {
+ try {
+ Resources resources = mContext.getResources();
+ /* Set the wallpaper to the default values */
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(
+ "res:" + resources.getResourceName(resid));
+ if (fd != null) {
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(resources.openRawResource(resid), fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a bitmap. The given bitmap is
+ * converted to a PNG and stored as the wallpaper. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * @param bitmap The bitmap to save.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setBitmap(Bitmap bitmap) throws IOException {
+ try {
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a specific byte stream. The
+ * give InputStream is copied into persistent storage and will now be
+ * used as the wallpaper. Currently it must be either a JPEG or PNG
+ * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
+ * is broadcast.
+ *
+ * @param data A stream containing the raw data to install as a wallpaper.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setStream(InputStream data) throws IOException {
+ try {
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(data, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void setWallpaper(InputStream data, FileOutputStream fos)
+ throws IOException {
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=data.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ }
+
+ /**
+ * Returns the desired minimum width for the wallpaper. Callers of
+ * {@link #setBitmap(android.graphics.Bitmap)} or
+ * {@link #setStream(java.io.InputStream)} should check this value
+ * beforehand to make sure the supplied wallpaper respects the desired
+ * minimum width.
+ *
+ * If the returned value is <= 0, the caller should use the width of
+ * the default display instead.
+ *
+ * @return The desired minimum width for the wallpaper. This value should
+ * be honored by applications that set the wallpaper but it is not
+ * mandatory.
+ */
+ public int getDesiredMinimumWidth() {
+ try {
+ return getGlobals().mService.getWidthHint();
+ } catch (RemoteException e) {
+ // Shouldn't happen!
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the desired minimum height for the wallpaper. Callers of
+ * {@link #setBitmap(android.graphics.Bitmap)} or
+ * {@link #setStream(java.io.InputStream)} should check this value
+ * beforehand to make sure the supplied wallpaper respects the desired
+ * minimum height.
+ *
+ * If the returned value is <= 0, the caller should use the height of
+ * the default display instead.
+ *
+ * @return The desired minimum height for the wallpaper. This value should
+ * be honored by applications that set the wallpaper but it is not
+ * mandatory.
+ */
+ public int getDesiredMinimumHeight() {
+ try {
+ return getGlobals().mService.getHeightHint();
+ } catch (RemoteException e) {
+ // Shouldn't happen!
+ return 0;
+ }
+ }
+
+ /**
+ * For use only by the current home application, to specify the size of
+ * wallpaper it would like to use. This allows such applications to have
+ * a virtual wallpaper that is larger than the physical screen, matching
+ * the size of their workspace.
+ * @param minimumWidth Desired minimum width
+ * @param minimumHeight Desired minimum height
+ */
+ public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
+ try {
+ getGlobals().mService.setDimensionHints(minimumWidth, minimumHeight);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Set the position of the current wallpaper within any larger space, when
+ * that wallpaper is visible behind the given window. The X and Y offsets
+ * are floating point numbers ranging from 0 to 1, representing where the
+ * wallpaper should be positioned within the screen space. These only
+ * make sense when the wallpaper is larger than the screen.
+ *
+ * @param windowToken The window who these offsets should be associated
+ * with, as returned by {@link android.view.View#getWindowVisibility()
+ * View.getWindowToken()}.
+ * @param xOffset The offset olong the X dimension, from 0 to 1.
+ * @param yOffset The offset along the Y dimension, from 0 to 1.
+ */
+ public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
+ try {
+ ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ windowToken, xOffset, yOffset);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ /**
+ * Clear the offsets previously associated with this window through
+ * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
+ * the window to its default state, where it does not cause the wallpaper
+ * to scroll from whatever its last offsets were.
+ *
+ * @param windowToken The window who these offsets should be associated
+ * with, as returned by {@link android.view.View#getWindowVisibility()
+ * View.getWindowToken()}.
+ */
+ public void clearWallpaperOffsets(IBinder windowToken) {
+ try {
+ ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ windowToken, -1, -1);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ /**
+ * Remove any currently set wallpaper, reverting to the system's default
+ * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
+ * is broadcast.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void clear() throws IOException {
+ setResource(com.android.internal.R.drawable.default_wallpaper);
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 9799ac4..cced338 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -24,16 +24,17 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
+import android.os.Parcelable;
+import android.os.Parcel;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
-import android.widget.FrameLayout.LayoutParams;
/**
* Provides the glue to show AppWidget views. This class offers automatic animation
@@ -108,6 +109,24 @@
return mInfo;
}
+ @Override
+ protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
+ final ParcelableSparseArray jail = new ParcelableSparseArray();
+ super.dispatchSaveInstanceState(jail);
+ container.put(generateId(), jail);
+ }
+
+ private int generateId() {
+ final int id = getId();
+ return id == View.NO_ID ? mAppWidgetId : id;
+ }
+
+ @Override
+ protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+ final ParcelableSparseArray jail = (ParcelableSparseArray) container.get(generateId());
+ super.dispatchRestoreInstanceState(jail);
+ }
+
/** {@inheritDoc} */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
@@ -339,4 +358,36 @@
tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
return tv;
}
+
+ private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ final int count = size();
+ dest.writeInt(count);
+ for (int i = 0; i < count; i++) {
+ dest.writeInt(keyAt(i));
+ dest.writeParcelable(valueAt(i), 0);
+ }
+ }
+
+ public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
+ new Parcelable.Creator<ParcelableSparseArray>() {
+ public ParcelableSparseArray createFromParcel(Parcel source) {
+ final ParcelableSparseArray array = new ParcelableSparseArray();
+ final ClassLoader loader = array.getClass().getClassLoader();
+ final int count = source.readInt();
+ for (int i = 0; i < count; i++) {
+ array.put(source.readInt(), source.readParcelable(loader));
+ }
+ return array;
+ }
+
+ public ParcelableSparseArray[] newArray(int size) {
+ return new ParcelableSparseArray[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 69c206c..e67b0be 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -97,12 +97,7 @@
public void skipEntityData() throws IOException {
if (mHeaderReady) {
- int result = skipEntityData_native(mBackupReader);
- if (result >= 0) {
- return;
- } else {
- throw new IOException("result=0x" + Integer.toHexString(result));
- }
+ skipEntityData_native(mBackupReader);
} else {
throw new IllegalStateException("mHeaderReady=false");
}
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index c52fcd2d..da1647a 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -43,7 +43,7 @@
private static final String TAG = "BackupManager";
/** @hide TODO: REMOVE THIS */
- public static final boolean EVEN_THINK_ABOUT_DOING_RESTORE = false;
+ public static final boolean EVEN_THINK_ABOUT_DOING_RESTORE = true;
private Context mContext;
private static IBackupManager sService;
diff --git a/core/java/android/backup/IRestoreSession.aidl b/core/java/android/backup/IRestoreSession.aidl
index 2a1fbc1..fd40d98 100644
--- a/core/java/android/backup/IRestoreSession.aidl
+++ b/core/java/android/backup/IRestoreSession.aidl
@@ -40,6 +40,8 @@
* Restore the given set onto the device, replacing the current data of any app
* contained in the restore set with the data previously backed up.
*
+ * @return Zero on success; nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
* @param token The token from {@link getAvailableRestoreSets()} corresponding to
* the restore set that should be used.
* @param observer If non-null, this binder points to an object that will receive
@@ -50,6 +52,9 @@
/**
* End this restore session. After this method is called, the IRestoreSession binder
* is no longer valid.
+ *
+ * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
+ * even if {@link getAvailableRestoreSets} or {@link performRestore} failed.
*/
void endRestoreSession();
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 2ea45d5..6e48b66 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,13 +200,13 @@
/**
* 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;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
new file mode 100644
index 0000000..d207540
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ *
+ * @hide
+ */
+public final class BluetoothAdapter {
+ private static final String TAG = "BluetoothAdapter";
+
+ 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;
+
+ /* The user will be prompted to enter a pin */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /* The user will be prompted to enter a passkey */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /* The user will be prompted to confirm the passkey displayed on the screen */
+ 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 the remote BluetoothDevice associated with the given MAC address.
+ * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB".
+ * @param address valid Bluetooth MAC address
+ */
+ public BluetoothDevice getRemoteDevice(String address) {
+ return new BluetoothDevice(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);}
+ 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;
+ }
+
+ /**
+ * 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.
+ */
+ 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.
+ */
+ 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;
+ }
+
+ /**
+ * 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.
+ */
+ 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.
+ */
+ 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;
+ }
+
+ /**
+ * 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
+ */
+ public Set<BluetoothDevice> getBondedDevices() {
+ try {
+ return toDeviceSet(mService.listBonds());
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * 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 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 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;
+ }
+
+ 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/BluetoothDevice.aidl b/core/java/android/bluetooth/BluetoothDevice.aidl
new file mode 100644
index 0000000..daae74d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothDevice;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 951b4b0..27b2849 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,39 +16,25 @@
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.
- *
+ * TODO: unhide
* @hide
*/
-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 */
@@ -74,83 +60,88 @@
/** An existing bond was explicitly revoked */
public static final int UNBOND_REASON_REMOVED = 6;
- private static final String TAG = "BluetoothDevice";
-
- private final IBluetoothDevice mService;
- /**
- * @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.
- */
- public BluetoothDevice(IBluetoothDevice service) {
- mService = service;
- }
+ /* The user will be prompted to enter a pin */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /* The user will be prompted to enter a passkey */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /* The user will be prompted to confirm the passkey displayed on the screen */
+ public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+
+ private static final int ADDRESS_LENGTH = 17;
+
+ private static IBluetooth sService; /* Guarenteed constant after first object constructed */
+
+ private final String mAddress;
/**
- * Is Bluetooth currently turned on.
- *
- * @return true if Bluetooth enabled, false otherwise.
+ * 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 boolean isEnabled() {
- try {
- return mService.isEnabled();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ /*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;
+ }
+
+ @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.
- */
- public boolean enable() {
- try {
- return mService.enable();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ @Override
+ public String toString() {
+ return mAddress;
}
- /**
- * Disable the Bluetooth device.
- * This turns off the underlying hardware.
- *
- * @return true if successful, false otherwise.
- */
- public boolean disable() {
- try {
- return mService.disable(true);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ public int describeContents() {
+ return 0;
+ }
+
+ 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];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mAddress);
}
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 this remote device.
*
* This name is visible to remote Bluetooth devices. Currently it is only
* possible to retrieve the Bluetooth name when Bluetooth is enabled.
@@ -159,197 +150,12 @@
*/
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;
- }
-
- public String getVersion() {
- try {
- return mService.getVersion();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRevision() {
- try {
- return mService.getRevision();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getManufacturer() {
- try {
- return mService.getManufacturer();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getCompany() {
- try {
- return mService.getCompany();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
-
- /**
- * 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() {
- return startDiscovery(true);
- }
- public boolean startDiscovery(boolean resolveNames) {
- try {
- return mService.startDiscovery(resolveNames);
- } 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;
- }
-
- public boolean startPeriodicDiscovery() {
- try {
- return mService.startPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean stopPeriodicDiscovery() {
- try {
- return mService.stopPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean isPeriodicDiscovery() {
- try {
- return mService.isPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- public String[] listRemoteDevices() {
- try {
- return mService.listRemoteDevices();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
-
- /**
- * List remote devices that have a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
- *
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
- *
- * @return bluetooth hardware addresses of remote devices with a current
- * ACL connection. Array size is 0 if no devices have a
- * connection. Null on error.
- */
- public String[] listAclConnections() {
- try {
- return mService.listAclConnections();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
-
- /**
- * Check if a specified remote device has a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
- *
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
- *
- * @param address the Bluetooth hardware address you want to check.
- * @return true if there is an ACL connection, false otherwise and on
- * error.
- */
- public boolean isAclConnected(String address) {
- try {
- return mService.isAclConnected(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- /**
- * Perform a low level (ACL) disconnection of a remote device.
- *
- * This forcably disconnects the ACL layer connection to a remote device,
- * which will cause all RFCOMM, SDP and L2CAP connections to this remote
- * device to close.
- *
- * @param address the Bluetooth hardware address you want to disconnect.
- * @return true if the device was disconnected, false otherwise and on
- * error.
- */
- public boolean disconnectRemoteDeviceAcl(String address) {
- try {
- return mService.disconnectRemoteDeviceAcl(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
@@ -359,9 +165,9 @@
* @return false If there was an immediate problem creating the bonding,
* true otherwise.
*/
- 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;
}
@@ -369,54 +175,28 @@
/**
* Cancel an in-progress bonding request started with createBond.
*/
- 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;
}
/**
- * Remove an already exisiting bonding (delete the link key).
+ * Removes the remote device and the pairing information associated
+ * with it.
+ *
+ * @return true if the device was disconnected, false otherwise and on
+ * error.
*/
- public boolean removeBond(String address) {
+ public boolean removeBond() {
try {
- return mService.removeBond(address);
+ return sService.removeBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * List remote devices that are bonded (paired) to the local device.
- *
- * 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.
- */
- public String[] listBonds() {
- try {
- return mService.listBonds();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
-
- /**
* Get the bonding state of a remote device.
*
* Result is one of:
@@ -426,105 +206,100 @@
* @param address Bluetooth hardware address of the remote device to check.
* @return Result code
*/
- 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) {
+ public int getBluetoothClass() {
try {
- return mService.getRemoteName(address);
+ return sService.getRemoteClass(mAddress);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR_IPC;
+ }
+
+ public String[] getUuids() {
+ try {
+ return sService.getRemoteUuids(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
- public String getRemoteVersion(String address) {
- try {
- return mService.getRemoteVersion(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRemoteRevision(String address) {
- try {
- return mService.getRemoteRevision(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRemoteManufacturer(String address) {
- try {
- return mService.getRemoteManufacturer(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRemoteCompany(String address) {
- try {
- return mService.getRemoteCompany(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ public int getServiceChannel(String uuid) {
+ try {
+ return sService.getRemoteServiceChannel(mAddress, uuid);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR_IPC;
}
- /**
- * Returns the RFCOMM channel associated with the 16-byte UUID on
- * the remote Bluetooth address.
- *
- * Performs a SDP ServiceSearchAttributeRequest transaction. The provided
- * uuid is verified in the returned record. If there was a problem, or the
- * specified uuid does not exist, -1 is returned.
- */
- public boolean getRemoteServiceChannel(String address, short uuid16,
- IBluetoothDeviceCallback callback) {
+ public boolean setPin(byte[] pin) {
try {
- return mService.getRemoteServiceChannel(address, uuid16, callback);
+ return sService.setPin(mAddress, pin);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ public boolean setPasskey(int passkey) {
+ try {
+ return sService.setPasskey(mAddress, passkey);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ public boolean setPairingConfirmation(boolean confirm) {
+ try {
+ return sService.setPairingConfirmation(mAddress, confirm);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ public boolean cancelPairingUserInput() {
+ try {
+ return sService.cancelPairingUserInput(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Get the major, minor and servics classes of a remote device.
- * These classes are encoded as a 32-bit integer. See BluetoothClass.
- * @param address remote device
- * @return 32-bit class suitable for use with BluetoothClass, or
- * BluetoothClass.ERROR on error
+ * 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 port remote port
+ * @return an RFCOMM BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
*/
- public int getRemoteClass(String address) {
- try {
- return mService.getRemoteClass(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothClass.ERROR;
+ public BluetoothSocket createRfcommSocket(int port) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, port);
}
- public byte[] getRemoteFeatures(String address) {
- try {
- return mService.getRemoteFeatures(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastSeen(String address) {
- try {
- return mService.lastSeen(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastUsed(String address) {
- try {
- return mService.lastUsed(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ /**
+ * 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.
+ */
+ public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port);
}
- public boolean setPin(String address, byte[] pin) {
- try {
- return mService.setPin(address, pin);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean cancelPin(String address) {
- try {
- return mService.cancelPin(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ /**
+ * 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.
+ */
+ public BluetoothSocket createScoSocket() throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1);
}
/**
@@ -552,7 +327,6 @@
return pinBytes;
}
- private static final int ADDRESS_LENGTH = 17;
/** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
public static boolean checkBluetoothAddress(String address) {
if (address == null || address.length() != ADDRESS_LENGTH) {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index fe1e09a..0e3d2bb 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");
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
new file mode 100644
index 0000000..c060f32
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothInputStream.java
@@ -0,0 +1,98 @@
+/*
+ * 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 java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * BluetoothInputStream.
+ *
+ * Used to write to a Bluetooth socket.
+ *
+ * @hide
+ */
+/*package*/ final class BluetoothInputStream extends InputStream {
+ private BluetoothSocket mSocket;
+
+ /*package*/ BluetoothInputStream(BluetoothSocket s) {
+ mSocket = s;
+ }
+
+ /**
+ * Return number of bytes available before this stream will block.
+ */
+ public int available() throws IOException {
+ return mSocket.availableNative();
+ }
+
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ /**
+ * Reads a single byte from this stream and returns it as an integer in the
+ * range from 0 to 255. Returns -1 if the end of the stream has been
+ * reached. Blocks until one byte has been read, the end of the source
+ * stream is detected or an exception is thrown.
+ *
+ * @return the byte read or -1 if the end of stream has been reached.
+ * @throws IOException
+ * if the stream is closed or another IOException occurs.
+ * @since Android 1.5
+ */
+ public int read() throws IOException {
+ byte b[] = new byte[1];
+ int ret = mSocket.readNative(b, 0, 1);
+ if (ret == 1) {
+ return (int)b[0] & 0xff;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Reads at most {@code length} bytes from this stream and stores them in
+ * the byte array {@code b} starting at {@code offset}.
+ *
+ * @param b
+ * the byte array in which to store the bytes read.
+ * @param offset
+ * the initial position in {@code buffer} to store the bytes
+ * read from this stream.
+ * @param length
+ * the maximum number of bytes to store in {@code b}.
+ * @return the number of bytes actually read or -1 if the end of the stream
+ * has been reached.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code length < 0}, or if
+ * {@code offset + length} is greater than the length of
+ * {@code b}.
+ * @throws IOException
+ * if the stream is closed or another IOException occurs.
+ * @since Android 1.5
+ */
+ public int read(byte[] b, int offset, int length) throws IOException {
+ if (b == null) {
+ throw new NullPointerException("byte array is null");
+ }
+ if ((offset | length) < 0 || length > b.length - offset) {
+ throw new ArrayIndexOutOfBoundsException("invalid offset or length");
+ }
+ return mSocket.readNative(b, offset, length);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index 344601b..2a0de61 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 =
@@ -57,6 +57,10 @@
"android.bluetooth.intent.BOND_PREVIOUS_STATE";
public static final String REASON =
"android.bluetooth.intent.REASON";
+ public static final String PAIRING_VARIANT =
+ "android.bluetooth.intent.PAIRING_VARIANT";
+ public static final String PASSKEY =
+ "android.bluetooth.intent.PASSKEY";
/** Broadcast when the local Bluetooth device state changes, for example
* when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and
diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java
new file mode 100644
index 0000000..7e2ead4
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothOutputStream.java
@@ -0,0 +1,87 @@
+/*
+ * 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 java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * BluetoothOutputStream.
+ *
+ * Used to read from a Bluetooth socket.
+ *
+ * @hide
+ */
+/*package*/ final class BluetoothOutputStream extends OutputStream {
+ private BluetoothSocket mSocket;
+
+ /*package*/ BluetoothOutputStream(BluetoothSocket s) {
+ mSocket = s;
+ }
+
+ /**
+ * Close this output stream and the socket associated with it.
+ */
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ /**
+ * Writes a single byte to this stream. Only the least significant byte of
+ * the integer {@code oneByte} is written to the stream.
+ *
+ * @param oneByte
+ * the byte to be written.
+ * @throws IOException
+ * if an error occurs while writing to this stream.
+ * @since Android 1.0
+ */
+ public void write(int oneByte) throws IOException {
+ byte b[] = new byte[1];
+ b[0] = (byte)oneByte;
+ mSocket.writeNative(b, 0, 1);
+ }
+
+ /**
+ * Writes {@code count} bytes from the byte array {@code buffer} starting
+ * at position {@code offset} to this stream.
+ *
+ * @param b
+ * the buffer to be written.
+ * @param offset
+ * the start position in {@code buffer} from where to get bytes.
+ * @param count
+ * the number of bytes from {@code buffer} to write to this
+ * stream.
+ * @throws IOException
+ * if an error occurs while writing to this stream.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code count < 0}, or if
+ * {@code offset + count} is bigger than the length of
+ * {@code buffer}.
+ * @since Android 1.0
+ */
+ public void write(byte[] b, int offset, int count) throws IOException {
+ if (b == null) {
+ throw new NullPointerException("buffer is null");
+ }
+ if ((offset | count) < 0 || count > b.length - offset) {
+ throw new IndexOutOfBoundsException("invalid offset or length");
+ }
+ mSocket.writeNative(b, offset, count);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
new file mode 100644
index 0000000..645e241
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -0,0 +1,257 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * The Android Bluetooth API is not finalized, and *will* change. Use at your
+ * own risk.
+ *
+ * Public API for controlling the Bluetooth Pbap Service. This includes
+ * Bluetooth Phone book Access profile.
+ * BluetoothPbap is a proxy object for controlling the Bluetooth Pbap
+ * Service via IPC.
+ *
+ * Creating a BluetoothPbap object will create a binding with the
+ * BluetoothPbap service. Users of this object should call close() when they
+ * are finished with the BluetoothPbap, so that this proxy object can unbind
+ * from the service.
+ *
+ * This BluetoothPbap object is not immediately bound to the
+ * BluetoothPbap service. Use the ServiceListener interface to obtain a
+ * notification when it is bound, this is especially important if you wish to
+ * immediately call methods on BluetoothPbap after construction.
+ *
+ * Android only supports one connected Bluetooth Pce at a time.
+ *
+ * @hide
+ */
+public class BluetoothPbap {
+
+ private static final String TAG = "BluetoothPbap";
+ private static final boolean DBG = false;
+
+ /** int extra for PBAP_STATE_CHANGED_ACTION */
+ public static final String PBAP_STATE =
+ "android.bluetooth.pbap.intent.PBAP_STATE";
+ /** int extra for PBAP_STATE_CHANGED_ACTION */
+ public static final String PBAP_PREVIOUS_STATE =
+ "android.bluetooth.pbap.intent.PBAP_PREVIOUS_STATE";
+
+ /** Indicates the state of an pbap connection state has changed.
+ * This intent will always contain PBAP_STATE, PBAP_PREVIOUS_STATE and
+ * BluetoothIntent.ADDRESS extras.
+ */
+ public static final String PBAP_STATE_CHANGED_ACTION =
+ "android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED";
+
+ private IBluetoothPbap mService;
+ private final Context mContext;
+ private final ServiceListener mServiceListener;
+
+ /** There was an error trying to obtain the state */
+ public static final int STATE_ERROR = -1;
+ /** No client currently connected */
+ public static final int STATE_DISCONNECTED = 0;
+ /** Connection attempt in progress */
+ public static final int STATE_CONNECTING = 1;
+ /** Client is currently connected */
+ public static final int STATE_CONNECTED = 2;
+
+ public static final int RESULT_FAILURE = 0;
+ public static final int RESULT_SUCCESS = 1;
+ /** Connection canceled before completion. */
+ public static final int RESULT_CANCELED = 2;
+
+ /**
+ * An interface for notifying Bluetooth PCE IPC clients when they have
+ * been connected to the BluetoothPbap service.
+ */
+ public interface ServiceListener {
+ /**
+ * Called to notify the client when this proxy object has been
+ * connected to the BluetoothPbap service. Clients must wait for
+ * this callback before making IPC calls on the BluetoothPbap
+ * service.
+ */
+ public void onServiceConnected();
+
+ /**
+ * Called to notify the client that this proxy object has been
+ * disconnected from the BluetoothPbap service. Clients must not
+ * make IPC calls on the BluetoothPbap service after this callback.
+ * This callback will currently only occur if the application hosting
+ * the BluetoothPbap service, but may be called more often in future.
+ */
+ public void onServiceDisconnected();
+ }
+
+ /**
+ * Create a BluetoothPbap proxy object.
+ */
+ public BluetoothPbap(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ if (!context.bindService(new Intent(IBluetoothPbap.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth Pbap Service");
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Close the connection to the backing service.
+ * Other public functions of BluetoothPbap will return default error
+ * results once close() has been called. Multiple invocations of close()
+ * are ok.
+ */
+ public synchronized void close() {
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+ }
+
+ /**
+ * Get the current state of the BluetoothPbap service.
+ * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
+ * object is currently not connected to the Pbap service.
+ */
+ public int getState() {
+ if (DBG) log("getState()");
+ if (mService != null) {
+ try {
+ return mService.getState();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return BluetoothPbap.STATE_ERROR;
+ }
+
+ /**
+ * 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 BluetoothDevice getClient() {
+ if (DBG) log("getClient()");
+ if (mService != null) {
+ try {
+ return mService.getClient();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return null;
+ }
+
+ /**
+ * 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(BluetoothDevice device) {
+ if (DBG) log("isConnected(" + device + ")");
+ if (mService != null) {
+ try {
+ return mService.isConnected(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * 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 disconnect() {
+ if (DBG) log("disconnect()");
+ if (mService != null) {
+ try {
+ mService.disconnect();
+ return true;
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Check class bits for possible PBAP support.
+ * This is a simple heuristic that tries to guess if a device with the
+ * given class bits might support PBAP. It is not accurate for all
+ * devices. It tries to err on the side of false positives.
+ * @return True if this device might support PBAP.
+ */
+ public static boolean doesClassMatchSink(int btClass) {
+ // TODO optimize the rule
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.COMPUTER_DESKTOP:
+ case BluetoothClass.Device.COMPUTER_LAPTOP:
+ case BluetoothClass.Device.COMPUTER_SERVER:
+ case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) log("Proxy object connected");
+ mService = IBluetoothPbap.Stub.asInterface(service);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected();
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) log("Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected();
+ }
+ }
+ };
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
new file mode 100644
index 0000000..8be300b
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -0,0 +1,85 @@
+/*
+ * 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 java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Server (listening) Bluetooth Socket.
+ *
+ * Currently only supports RFCOMM sockets.
+ *
+ * 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
+ */
+public final class BluetoothServerSocket implements Closeable {
+ /*package*/ final BluetoothSocket mSocket;
+
+ /**
+ * Construct a socket for incoming connections.
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param port remote port
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient priveleges
+ */
+ /*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
+ */
+ public BluetoothSocket accept() throws IOException {
+ return accept(-1);
+ }
+
+ /**
+ * 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
+ * timeout
+ */
+ public BluetoothSocket accept(int timeout) throws IOException {
+ return mSocket.acceptNative(timeout);
+ }
+
+ /**
+ * Closes this socket.
+ * This will cause other blocking calls on this socket to immediately
+ * throw an IOException.
+ */
+ public void close() throws IOException {
+ mSocket.closeNative();
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
new file mode 100644
index 0000000..dda2cef
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -0,0 +1,173 @@
+/*
+ * 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 java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a connected or connecting Bluetooth Socket.
+ *
+ * Currently only supports RFCOMM sockets.
+ *
+ * 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
+ */
+public final class BluetoothSocket implements Closeable {
+ /** Keep TYPE_RFCOMM etc 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;
+ private final BluetoothInputStream mInputStream;
+ private final BluetoothOutputStream mOutputStream;
+
+ private int mSocketData; /* used by native code only */
+
+ /**
+ * 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 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,
+ BluetoothDevice device, int port) throws IOException {
+ mType = type;
+ mAuth = auth;
+ mEncrypt = encrypt;
+ mDevice = device;
+ if (device == null) {
+ mAddress = null;
+ } else {
+ mAddress = device.getAddress();
+ }
+ mPort = port;
+ if (fd == -1) {
+ initSocketNative();
+ } else {
+ initSocketFromFdNative(fd);
+ }
+ mInputStream = new BluetoothInputStream(this);
+ 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);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Attempt to connect to a remote device.
+ * 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
+ */
+ public void connect() throws IOException {
+ connectNative();
+ }
+
+ /**
+ * Closes this socket.
+ * This will cause other blocking calls on this socket to immediately
+ * throw an IOException.
+ */
+ public void close() throws IOException {
+ closeNative();
+ }
+
+ /**
+ * Return the remote device we are connecting, or connected, to.
+ * @return remote device, or null if this socket has not yet attempted
+ * or established a connection.
+ */
+ 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
+ * connected, but operations on that stream will throw IOException until
+ * the associated socket is connected.
+ * @return InputStream
+ */
+ public InputStream getInputStream() throws IOException {
+ return mInputStream;
+ }
+
+ /**
+ * Get the output stream associated with this socket.
+ * 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
+ */
+ public OutputStream getOutputStream() throws IOException {
+ return mOutputStream;
+ }
+
+ private native void initSocketNative() throws IOException;
+ private native void initSocketFromFdNative(int fd) throws IOException;
+ private native void connectNative() throws IOException;
+ /*package*/ native void bindListenNative() throws IOException;
+ /*package*/ native BluetoothSocket acceptNative(int timeout) throws IOException;
+ /*package*/ native int availableNative() throws IOException;
+ /*package*/ native int readNative(byte[] b, int offset, int length) throws IOException;
+ /*package*/ native int writeNative(byte[] b, int offset, int length) throws IOException;
+ /*package*/ native void closeNative() throws IOException;
+ private native void destroyNative() throws IOException;
+}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
new file mode 100644
index 0000000..1ec7fb38
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -0,0 +1,64 @@
+/*
+ * 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 java.util.UUID;
+
+/**
+* Static helper methods and constants to decode the UUID of remote devices.
+* @hide
+*/
+public final class BluetoothUuid {
+
+ /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
+ * for the various services.
+ *
+ * The following 128 bit values are calculated as:
+ * uuid * 2^96 + BASE_UUID
+ */
+ public static final UUID AudioSink = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+ public static final UUID AudioSource = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+ public static final UUID AdvAudioDist = UUID.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+ public static final UUID HSP = UUID.fromString("00001108-0000-1000-8000-00805F9B34FB");
+ 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 boolean isAudioSource(UUID uuid) {
+ return uuid.equals(AudioSource);
+ }
+
+ public static boolean isAudioSink(UUID uuid) {
+ return uuid.equals(AudioSink);
+ }
+
+ public static boolean isAdvAudioDist(UUID uuid) {
+ return uuid.equals(AdvAudioDist);
+ }
+
+ public static boolean isHandsfree(UUID uuid) {
+ return uuid.equals(Handsfree);
+ }
+
+ public static boolean isHeadset(UUID uuid) {
+ return uuid.equals(HSP);
+ }
+
+ public static boolean isAvrcpController(UUID uuid) {
+ return uuid.equals(AvrcpController);
+ }
+}
diff --git a/core/java/android/bluetooth/Database.java b/core/java/android/bluetooth/Database.java
deleted file mode 100644
index fef641a..0000000
--- a/core/java/android/bluetooth/Database.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.RfcommSocket;
-
-import android.util.Log;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * A low-level API to the Service Discovery Protocol (SDP) Database.
- *
- * Allows service records to be added to the local SDP database. Once added,
- * these services will be advertised to remote devices when they make SDP
- * queries on this device.
- *
- * Currently this API is a thin wrapper to the bluez SDP Database API. See:
- * http://wiki.bluez.org/wiki/Database
- * http://wiki.bluez.org/wiki/HOWTO/ManagingServiceRecords
- * @hide
- */
-public final class Database {
- private static Database mInstance;
-
- private static final String sLogName = "android.bluetooth.Database";
-
- /**
- * Class load time initialization
- */
- static {
- classInitNative();
- }
- private native static void classInitNative();
-
- /**
- * Private to enforce singleton property
- */
- private Database() {
- initializeNativeDataNative();
- }
- private native void initializeNativeDataNative();
-
- protected void finalize() throws Throwable {
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
- private native void cleanupNativeDataNative();
-
- /**
- * Singelton accessor
- * @return The singleton instance of Database
- */
- public static synchronized Database getInstance() {
- if (mInstance == null) {
- mInstance = new Database();
- }
- return mInstance;
- }
-
- /**
- * Advertise a service with an RfcommSocket.
- *
- * This adds the service the SDP Database with the following attributes
- * set: Service Name, Protocol Descriptor List, Service Class ID List
- * TODO: Construct a byte[] record directly, rather than via XML.
- * @param socket The rfcomm socket to advertise (by channel).
- * @param serviceName A short name for this service
- * @param uuid
- * Unique identifier for this service, by which clients
- * can search for your service
- * @return Handle to the new service record
- */
- public int advertiseRfcommService(RfcommSocket socket,
- String serviceName,
- UUID uuid) throws IOException {
- String xmlRecord =
- "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
- "<record>\n" +
- " <attribute id=\"0x0001\">\n" + // ServiceClassIDList
- " <sequence>\n" +
- " <uuid value=\""
- + uuid.toString() + // UUID for this service
- "\"/>\n" +
- " </sequence>\n" +
- " </attribute>\n" +
- " <attribute id=\"0x0004\">\n" + // ProtocolDescriptorList
- " <sequence>\n" +
- " <sequence>\n" +
- " <uuid value=\"0x0100\"/>\n" + // L2CAP
- " </sequence>\n" +
- " <sequence>\n" +
- " <uuid value=\"0x0003\"/>\n" + // RFCOMM
- " <uint8 value=\"" +
- socket.getPort() + // RFCOMM port
- "\" name=\"channel\"/>\n" +
- " </sequence>\n" +
- " </sequence>\n" +
- " </attribute>\n" +
- " <attribute id=\"0x0100\">\n" + // ServiceName
- " <text value=\"" + serviceName + "\"/>\n" +
- " </attribute>\n" +
- "</record>\n";
- Log.i(sLogName, xmlRecord);
- return addServiceRecordFromXml(xmlRecord);
- }
-
-
- /**
- * Add a new service record.
- * @param record The byte[] record
- * @return A handle to the new record
- */
- public synchronized int addServiceRecord(byte[] record) throws IOException {
- int handle = addServiceRecordNative(record);
- Log.i(sLogName, "Added SDP record: " + Integer.toHexString(handle));
- return handle;
- }
- private native int addServiceRecordNative(byte[] record)
- throws IOException;
-
- /**
- * Add a new service record, using XML.
- * @param record The record as an XML string
- * @return A handle to the new record
- */
- public synchronized int addServiceRecordFromXml(String record) throws IOException {
- int handle = addServiceRecordFromXmlNative(record);
- Log.i(sLogName, "Added SDP record: " + Integer.toHexString(handle));
- return handle;
- }
- private native int addServiceRecordFromXmlNative(String record)
- throws IOException;
-
- /**
- * Update an exisiting service record.
- * @param handle Handle to exisiting record
- * @param record The updated byte[] record
- */
- public synchronized void updateServiceRecord(int handle, byte[] record) {
- try {
- updateServiceRecordNative(handle, record);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void updateServiceRecordNative(int handle, byte[] record)
- throws IOException;
-
- /**
- * Update an exisiting record, using XML.
- * @param handle Handle to exisiting record
- * @param record The record as an XML string.
- */
- public synchronized void updateServiceRecordFromXml(int handle, String record) {
- try {
- updateServiceRecordFromXmlNative(handle, record);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void updateServiceRecordFromXmlNative(int handle, String record)
- throws IOException;
-
- /**
- * Remove a service record.
- * It is only possible to remove service records that were added by the
- * current connection.
- * @param handle Handle to exisiting record to be removed
- */
- public synchronized void removeServiceRecord(int handle) {
- try {
- removeServiceRecordNative(handle);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void removeServiceRecordNative(int handle) throws IOException;
-}
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/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
new file mode 100644
index 0000000..9e05a87
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.bluetooth;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetooth
+{
+ boolean isEnabled();
+ int getBluetoothState();
+ boolean enable();
+ boolean disable(boolean persistSetting);
+
+ String getAddress();
+ String getName();
+ boolean setName(in String name);
+
+ int getScanMode();
+ boolean setScanMode(int mode);
+
+ int getDiscoverableTimeout();
+ boolean setDiscoverableTimeout(int timeout);
+
+ boolean startDiscovery();
+ boolean cancelDiscovery();
+ boolean isDiscovering();
+
+ boolean createBond(in String address);
+ boolean cancelBondProcess(in String address);
+ boolean removeBond(in String address);
+ String[] listBonds();
+ int getBondState(in String address);
+
+ String getRemoteName(in String address);
+ int getRemoteClass(in String address);
+ String[] getRemoteUuids(in String address);
+ int getRemoteServiceChannel(in String address, String uuid);
+
+ boolean setPin(in String address, in byte[] pin);
+ boolean setPasskey(in String address, int passkey);
+ boolean setPairingConfirmation(in String address, boolean confirm);
+ boolean cancelPairingUserInput(in String address);
+
+}
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/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetoothDevice.aidl
deleted file mode 100644
index 6cd792e..0000000
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ /dev/null
@@ -1,78 +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.bluetooth;
-
-import android.bluetooth.IBluetoothDeviceCallback;
-
-/**
- * System private API for talking with the Bluetooth service.
- *
- * {@hide}
- */
-interface IBluetoothDevice
-{
- boolean isEnabled();
- int getBluetoothState();
- boolean enable();
- boolean disable(boolean persistSetting);
-
- String getAddress();
- String getName();
- boolean setName(in String name);
- String getVersion();
- String getRevision();
- String getManufacturer();
- String getCompany();
-
- int getScanMode();
- boolean setScanMode(int mode);
-
- int getDiscoverableTimeout();
- boolean setDiscoverableTimeout(int timeout);
-
- boolean startDiscovery(boolean resolveNames);
- boolean cancelDiscovery();
- boolean isDiscovering();
- boolean startPeriodicDiscovery();
- boolean stopPeriodicDiscovery();
- boolean isPeriodicDiscovery();
- String[] listRemoteDevices();
-
- String[] listAclConnections();
- boolean isAclConnected(in String address);
- boolean disconnectRemoteDeviceAcl(in String address);
-
- boolean createBond(in String address);
- boolean cancelBondProcess(in String address);
- boolean removeBond(in String address);
- String[] listBonds();
- int getBondState(in String address);
-
- String getRemoteName(in String address);
- String getRemoteVersion(in String address);
- String getRemoteRevision(in String address);
- int getRemoteClass(in String address);
- String getRemoteManufacturer(in String address);
- String getRemoteCompany(in String address);
- boolean getRemoteServiceChannel(in String address, int uuid16, in IBluetoothDeviceCallback callback);
- byte[] getRemoteFeatures(in String adddress);
- String lastSeen(in String address);
- String lastUsed(in String address);
-
- boolean setPin(in String address, in byte[] pin);
- boolean cancelPin(in String address);
-}
diff --git a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
deleted file mode 100644
index d057093..0000000
--- a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
+++ /dev/null
@@ -1,25 +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.bluetooth;
-
-/**
- * {@hide}
- */
-oneway interface IBluetoothDeviceCallback
-{
- void onGetRemoteServiceChannelResult(in String address, int channel);
-}
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
new file mode 100644
index 0000000..7cc77d1
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothPbap.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth pbap service
+ *
+ * {@hide}
+ */
+interface IBluetoothPbap {
+ int getState();
+ BluetoothDevice getClient();
+ boolean connect(in BluetoothDevice device);
+ void disconnect();
+ boolean isConnected(in BluetoothDevice device);
+}
diff --git a/core/java/android/bluetooth/RfcommSocket.java b/core/java/android/bluetooth/RfcommSocket.java
deleted file mode 100644
index a33263f..0000000
--- a/core/java/android/bluetooth/RfcommSocket.java
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import java.io.IOException;
-import java.io.FileOutputStream;
-import java.io.FileInputStream;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.FileDescriptor;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * This class implements an API to the Bluetooth RFCOMM layer. An RFCOMM socket
- * is similar to a normal socket in that it takes an address and a port number.
- * The difference is of course that the address is a Bluetooth-device address,
- * and the port number is an RFCOMM channel. The API allows for the
- * establishment of listening sockets via methods
- * {@link #bind(String, int) bind}, {@link #listen(int) listen}, and
- * {@link #accept(RfcommSocket, int) accept}, as well as for the making of
- * outgoing connections with {@link #connect(String, int) connect},
- * {@link #connectAsync(String, int) connectAsync}, and
- * {@link #waitForAsyncConnect(int) waitForAsyncConnect}.
- *
- * After constructing a socket, you need to {@link #create() create} it and then
- * {@link #destroy() destroy} it when you are done using it. Both
- * {@link #create() create} and {@link #accept(RfcommSocket, int) accept} return
- * a {@link java.io.FileDescriptor FileDescriptor} for the actual data.
- * Alternatively, you may call {@link #getInputStream() getInputStream} and
- * {@link #getOutputStream() getOutputStream} to retrieve the respective streams
- * without going through the FileDescriptor.
- *
- * @hide
- */
-public class RfcommSocket {
-
- /**
- * Used by the native implementation of the class.
- */
- private int mNativeData;
-
- /**
- * Used by the native implementation of the class.
- */
- private int mPort;
-
- /**
- * Used by the native implementation of the class.
- */
- private String mAddress;
-
- /**
- * We save the return value of {@link #create() create} and
- * {@link #accept(RfcommSocket,int) accept} in this variable, and use it to
- * retrieve the I/O streams.
- */
- private FileDescriptor mFd;
-
- /**
- * After a call to {@link #waitForAsyncConnect(int) waitForAsyncConnect},
- * if the return value is zero, then, the the remaining time left to wait is
- * written into this variable (by the native implementation). It is possible
- * that {@link #waitForAsyncConnect(int) waitForAsyncConnect} returns before
- * the user-specified timeout expires, which is why we save the remaining
- * time in this member variable for the user to retrieve by calling method
- * {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs}.
- */
- private int mTimeoutRemainingMs;
-
- /**
- * Set to true when an asynchronous (nonblocking) connect is in progress.
- * {@see #connectAsync(String,int)}.
- */
- private boolean mIsConnecting;
-
- /**
- * Set to true after a successful call to {@link #bind(String,int) bind} and
- * used for error checking in {@link #listen(int) listen}. Reset to false
- * on {@link #destroy() destroy}.
- */
- private boolean mIsBound = false;
-
- /**
- * Set to true after a successful call to {@link #listen(int) listen} and
- * used for error checking in {@link #accept(RfcommSocket,int) accept}.
- * Reset to false on {@link #destroy() destroy}.
- */
- private boolean mIsListening = false;
-
- /**
- * Used to store the remaining time after an accept with a non-negative
- * timeout returns unsuccessfully. It is possible that a blocking
- * {@link #accept(int) accept} may wait for less than the time specified by
- * the user, which is why we store the remainder in this member variable for
- * it to be retrieved with method
- * {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs}.
- */
- private int mAcceptTimeoutRemainingMs;
-
- /**
- * Maintained by {@link #getInputStream() getInputStream}.
- */
- protected FileInputStream mInputStream;
-
- /**
- * Maintained by {@link #getOutputStream() getOutputStream}.
- */
- protected FileOutputStream mOutputStream;
-
- private native void initializeNativeDataNative();
-
- /**
- * Constructor.
- */
- public RfcommSocket() {
- initializeNativeDataNative();
- }
-
- private native void cleanupNativeDataNative();
-
- /**
- * Called by the GC to clean up the native data that we set up when we
- * construct the object.
- */
- protected void finalize() throws Throwable {
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
-
- private native static void classInitNative();
-
- static {
- classInitNative();
- }
-
- /**
- * Creates a socket. You need to call this method before performing any
- * other operation on a socket.
- *
- * @return FileDescriptor for the data stream.
- * @throws IOException
- * @see #destroy()
- */
- public FileDescriptor create() throws IOException {
- if (mFd == null) {
- mFd = createNative();
- }
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return mFd;
- }
-
- private native FileDescriptor createNative();
-
- /**
- * Destroys a socket created by {@link #create() create}. Call this
- * function when you no longer use the socket in order to release the
- * underlying OS resources.
- *
- * @see #create()
- */
- public void destroy() {
- synchronized (this) {
- destroyNative();
- mFd = null;
- mIsBound = false;
- mIsListening = false;
- }
- }
-
- private native void destroyNative();
-
- /**
- * Returns the {@link java.io.FileDescriptor FileDescriptor} of the socket.
- *
- * @return the FileDescriptor
- * @throws IOException
- * when the socket has not been {@link #create() created}.
- */
- public FileDescriptor getFileDescriptor() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return mFd;
- }
-
- /**
- * Retrieves the input stream from the socket. Alternatively, you can do
- * that from the FileDescriptor returned by {@link #create() create} or
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * @return InputStream
- * @throws IOException
- * if you have not called {@link #create() create} on the
- * socket.
- */
- public InputStream getInputStream() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
-
- synchronized (this) {
- if (mInputStream == null) {
- mInputStream = new FileInputStream(mFd);
- }
-
- return mInputStream;
- }
- }
-
- /**
- * Retrieves the output stream from the socket. Alternatively, you can do
- * that from the FileDescriptor returned by {@link #create() create} or
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * @return OutputStream
- * @throws IOException
- * if you have not called {@link #create() create} on the
- * socket.
- */
- public OutputStream getOutputStream() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
-
- synchronized (this) {
- if (mOutputStream == null) {
- mOutputStream = new FileOutputStream(mFd);
- }
-
- return mOutputStream;
- }
- }
-
- /**
- * Starts a blocking connect to a remote RFCOMM socket. It takes the address
- * of a device and the RFCOMM channel (port) to which to connect.
- *
- * @param address
- * is the Bluetooth address of the remote device.
- * @param port
- * is the RFCOMM channel
- * @return true on success, false on failure
- * @throws IOException
- * if {@link #create() create} has not been called.
- * @see #connectAsync(String, int)
- */
- public boolean connect(String address, int port) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return connectNative(address, port);
- }
- }
-
- private native boolean connectNative(String address, int port);
-
- /**
- * Starts an asynchronous (nonblocking) connect to a remote RFCOMM socket.
- * It takes the address of the device to connect to, as well as the RFCOMM
- * channel (port). On successful return (return value is true), you need to
- * call method {@link #waitForAsyncConnect(int) waitForAsyncConnect} to
- * block for up to a specified number of milliseconds while waiting for the
- * asyncronous connect to complete.
- *
- * @param address
- * of remote device
- * @param port
- * the RFCOMM channel
- * @return true when the asynchronous connect has successfully started,
- * false if there was an error.
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #waitForAsyncConnect(int)
- * @see #getRemainingAsyncConnectWaitingTimeMs()
- * @see #connect(String, int)
- */
- public boolean connectAsync(String address, int port) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- mIsConnecting = connectAsyncNative(address, port);
- return mIsConnecting;
- }
- }
-
- private native boolean connectAsyncNative(String address, int port);
-
- /**
- * Interrupts an asynchronous connect in progress. This method does nothing
- * when there is no asynchronous connect in progress.
- *
- * @throws IOException
- * if you have not called {@link #create() create}.
- * @see #connectAsync(String, int)
- */
- public void interruptAsyncConnect() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (mIsConnecting) {
- mIsConnecting = !interruptAsyncConnectNative();
- }
- }
- }
-
- private native boolean interruptAsyncConnectNative();
-
- /**
- * Tells you whether there is an asynchronous connect in progress. This
- * method returns an undefined value when there is a synchronous connect in
- * progress.
- *
- * @return true if there is an asyc connect in progress, false otherwise
- * @see #connectAsync(String, int)
- */
- public boolean isConnecting() {
- return mIsConnecting;
- }
-
- /**
- * Blocks for a specified amount of milliseconds while waiting for an
- * asynchronous connect to complete. Returns an integer value to indicate
- * one of the following: the connect succeeded, the connect is still in
- * progress, or the connect failed. It is possible for this method to block
- * for less than the time specified by the user, and still return zero
- * (i.e., async connect is still in progress.) For this reason, if the
- * return value is zero, you need to call method
- * {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs}
- * to retrieve the remaining time.
- *
- * @param timeoutMs
- * the time to block while waiting for the async connect to
- * complete.
- * @return a positive value if the connect succeeds; zero, if the connect is
- * still in progress, and a negative value if the connect failed.
- *
- * @throws IOException
- * @see #getRemainingAsyncConnectWaitingTimeMs()
- * @see #connectAsync(String, int)
- */
- public int waitForAsyncConnect(int timeoutMs) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- int ret = waitForAsyncConnectNative(timeoutMs);
- if (ret != 0) {
- mIsConnecting = false;
- }
- return ret;
- }
- }
-
- private native int waitForAsyncConnectNative(int timeoutMs);
-
- /**
- * Returns the number of milliseconds left to wait after the last call to
- * {@link #waitForAsyncConnect(int) waitForAsyncConnect}.
- *
- * It is possible that waitForAsyncConnect() waits for less than the time
- * specified by the user, and still returns zero (i.e., async connect is
- * still in progress.) For this reason, if the return value is zero, you
- * need to call this method to retrieve the remaining time before you call
- * waitForAsyncConnect again.
- *
- * @return the remaining timeout in milliseconds.
- * @see #waitForAsyncConnect(int)
- * @see #connectAsync(String, int)
- */
- public int getRemainingAsyncConnectWaitingTimeMs() {
- return mTimeoutRemainingMs;
- }
-
- /**
- * Shuts down both directions on a socket.
- *
- * @return true on success, false on failure; if the return value is false,
- * the socket might be left in a patially shut-down state (i.e. one
- * direction is shut down, but the other is still open.) In this
- * case, you should {@link #destroy() destroy} and then
- * {@link #create() create} the socket again.
- * @throws IOException
- * is you have not caled {@link #create() create}.
- * @see #shutdownInput()
- * @see #shutdownOutput()
- */
- public boolean shutdown() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (shutdownNative(true)) {
- return shutdownNative(false);
- }
-
- return false;
- }
- }
-
- /**
- * Shuts down the input stream of the socket, but leaves the output stream
- * in its current state.
- *
- * @return true on success, false on failure
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #shutdown()
- * @see #shutdownOutput()
- */
- public boolean shutdownInput() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return shutdownNative(true);
- }
- }
-
- /**
- * Shut down the output stream of the socket, but leaves the input stream in
- * its current state.
- *
- * @return true on success, false on failure
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #shutdown()
- * @see #shutdownInput()
- */
- public boolean shutdownOutput() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return shutdownNative(false);
- }
- }
-
- private native boolean shutdownNative(boolean shutdownInput);
-
- /**
- * Tells you whether a socket is connected to another socket. This could be
- * for input or output or both.
- *
- * @return true if connected, false otherwise.
- * @see #isInputConnected()
- * @see #isOutputConnected()
- */
- public boolean isConnected() {
- return isConnectedNative() > 0;
- }
-
- /**
- * Determines whether input is connected (i.e., whether you can receive data
- * on this socket.)
- *
- * @return true if input is connected, false otherwise.
- * @see #isConnected()
- * @see #isOutputConnected()
- */
- public boolean isInputConnected() {
- return (isConnectedNative() & 1) != 0;
- }
-
- /**
- * Determines whether output is connected (i.e., whether you can send data
- * on this socket.)
- *
- * @return true if output is connected, false otherwise.
- * @see #isConnected()
- * @see #isInputConnected()
- */
- public boolean isOutputConnected() {
- return (isConnectedNative() & 2) != 0;
- }
-
- private native int isConnectedNative();
-
- /**
- * Binds a listening socket to the local device, or a non-listening socket
- * to a remote device. The port is automatically selected as the first
- * available port in the range 12 to 30.
- *
- * NOTE: Currently we ignore the device parameter and always bind the socket
- * to the local device, assuming that it is a listening socket.
- *
- * TODO: Use bind(0) in native code to have the kernel select an unused
- * port.
- *
- * @param device
- * Bluetooth address of device to bind to (currently ignored).
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create}
- * @see #listen(int)
- * @see #accept(RfcommSocket,int)
- */
- public boolean bind(String device) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- for (int port = 12; port <= 30; port++) {
- if (bindNative(device, port)) {
- mIsBound = true;
- return true;
- }
- }
- mIsBound = false;
- return false;
- }
-
- /**
- * Binds a listening socket to the local device, or a non-listening socket
- * to a remote device.
- *
- * NOTE: Currently we ignore the device parameter and always bind the socket
- * to the local device, assuming that it is a listening socket.
- *
- * @param device
- * Bluetooth address of device to bind to (currently ignored).
- * @param port
- * RFCOMM channel to bind socket to.
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create}
- * @see #listen(int)
- * @see #accept(RfcommSocket,int)
- */
- public boolean bind(String device, int port) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- mIsBound = bindNative(device, port);
- return mIsBound;
- }
-
- private native boolean bindNative(String device, int port);
-
- /**
- * Starts listening for incoming connections on this socket, after it has
- * been bound to an address and RFCOMM channel with
- * {@link #bind(String,int) bind}.
- *
- * @param backlog
- * the number of pending incoming connections to queue for
- * {@link #accept(RfcommSocket, int) accept}.
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create} or if the
- * socket has not been bound to a device and RFCOMM channel.
- */
- public boolean listen(int backlog) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (!mIsBound) {
- throw new IOException("socket not bound");
- }
- mIsListening = listenNative(backlog);
- return mIsListening;
- }
-
- private native boolean listenNative(int backlog);
-
- /**
- * Accepts incoming-connection requests for a listening socket bound to an
- * RFCOMM channel. The user may provide a time to wait for an incoming
- * connection.
- *
- * Note that this method may return null (i.e., no incoming connection)
- * before the user-specified timeout expires. For this reason, on a null
- * return value, you need to call
- * {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs}
- * in order to see how much time is left to wait, before you call this
- * method again.
- *
- * @param newSock
- * is set to the new socket that is created as a result of a
- * successful accept.
- * @param timeoutMs
- * time (in milliseconds) to block while waiting to an
- * incoming-connection request. A negative value is an infinite
- * wait.
- * @return FileDescriptor of newSock on success, null on failure. Failure
- * occurs if the timeout expires without a successful connect.
- * @throws IOException
- * if the socket has not been {@link #create() create}ed, is
- * not bound, or is not a listening socket.
- * @see #bind(String, int)
- * @see #listen(int)
- * @see #getRemainingAcceptWaitingTimeMs()
- */
- public FileDescriptor accept(RfcommSocket newSock, int timeoutMs)
- throws IOException {
- synchronized (newSock) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (mIsListening == false) {
- throw new IOException("not listening on socket");
- }
- newSock.mFd = acceptNative(newSock, timeoutMs);
- return newSock.mFd;
- }
- }
-
- /**
- * Returns the number of milliseconds left to wait after the last call to
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * Since accept() may return null (i.e., no incoming connection) before the
- * user-specified timeout expires, you need to call this method in order to
- * see how much time is left to wait, and wait for that amount of time
- * before you call accept again.
- *
- * @return the remaining time, in milliseconds.
- */
- public int getRemainingAcceptWaitingTimeMs() {
- return mAcceptTimeoutRemainingMs;
- }
-
- private native FileDescriptor acceptNative(RfcommSocket newSock,
- int timeoutMs);
-
- /**
- * Get the port (rfcomm channel) associated with this socket.
- *
- * This is only valid if the port has been set via a successful call to
- * {@link #bind(String, int)}, {@link #connect(String, int)}
- * or {@link #connectAsync(String, int)}. This can be checked
- * with {@link #isListening()} and {@link #isConnected()}.
- * @return Port (rfcomm channel)
- */
- public int getPort() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (!mIsListening && !isConnected()) {
- throw new IOException("not listening or connected on socket");
- }
- return mPort;
- }
-
- /**
- * Return true if this socket is listening ({@link #listen(int)}
- * has been called successfully).
- */
- public boolean isListening() {
- return mIsListening;
- }
-}
diff --git a/core/java/android/content/AbstractCursorEntityIterator.java b/core/java/android/content/AbstractCursorEntityIterator.java
new file mode 100644
index 0000000..bf3c4de
--- /dev/null
+++ b/core/java/android/content/AbstractCursorEntityIterator.java
@@ -0,0 +1,112 @@
+package android.content;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.RemoteException;
+
+/**
+ * An abstract class that makes it easy to implement an EntityIterator over a cursor.
+ * The user must implement {@link #newEntityFromCursorLocked}, which runs inside of a
+ * database transaction.
+ */
+public abstract class AbstractCursorEntityIterator implements EntityIterator {
+ private final Cursor mEntityCursor;
+ private final SQLiteDatabase mDb;
+ private volatile Entity mNextEntity;
+ private volatile boolean mIsClosed;
+
+ public AbstractCursorEntityIterator(SQLiteDatabase db, Cursor entityCursor) {
+ mEntityCursor = entityCursor;
+ mDb = db;
+ mNextEntity = null;
+ mIsClosed = false;
+ }
+
+ /**
+ * If there are entries left in the cursor then advance the cursor and use the new row to
+ * populate mNextEntity. If the cursor is at the end or if advancing it causes the cursor
+ * to become at the end then set mEntityCursor to null. If newEntityFromCursor returns null
+ * then continue advancing until it either returns a non-null Entity or the cursor reaches
+ * the end.
+ */
+ private void fillEntityIfAvailable() {
+ while (mNextEntity == null) {
+ if (!mEntityCursor.moveToNext()) {
+ // the cursor is at then end, bail out
+ return;
+ }
+ // This may return null if newEntityFromCursor is not able to create an entity
+ // from the current cursor position. In that case this method will loop and try
+ // the next cursor position
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ }
+ mDb.beginTransaction();
+ try {
+ int position = mEntityCursor.getPosition();
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ int newPosition = mEntityCursor.getPosition();
+ if (newPosition != position) {
+ throw new IllegalStateException("the cursor position changed during the call to"
+ + "newEntityFromCursorLocked, from " + position + " to " + newPosition);
+ }
+ } finally {
+ mDb.endTransaction();
+ }
+ }
+
+ /**
+ * Checks if there are more Entities accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return true if the call to next() will return an Entity.
+ */
+ public boolean hasNext() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling hasNext() when the iterator is closed");
+ }
+ fillEntityIfAvailable();
+ return mNextEntity != null;
+ }
+
+ /**
+ * Returns the next Entity that is accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return the next Entity that is accessible via this iterator
+ */
+ public Entity next() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling next() when the iterator is closed");
+ }
+ if (!hasNext()) {
+ throw new IllegalStateException("you may only call next() if hasNext() is true");
+ }
+
+ try {
+ return mNextEntity;
+ } finally {
+ mNextEntity = null;
+ }
+ }
+
+ /**
+ * Closes this iterator making it invalid. If is invalid for the user to call any public
+ * method on the iterator once it has been closed.
+ */
+ public void close() {
+ if (mIsClosed) {
+ throw new IllegalStateException("closing when already closed");
+ }
+ mIsClosed = true;
+ mEntityCursor.close();
+ }
+
+ /**
+ * Returns a new Entity from the current cursor position. This is called from within a
+ * database transaction. If a new entity cannot be created from this cursor position (e.g.
+ * if the row that is referred to no longer exists) then this may return null. The cursor
+ * is guaranteed to be pointing to a valid row when this call is made. The implementation
+ * of newEntityFromCursorLocked is not allowed to change the position of the cursor.
+ * @param cursor from where to read the data for the Entity
+ * @return an Entity that corresponds to the current cursor position or null
+ */
+ public abstract Entity newEntityFromCursorLocked(Cursor cursor);
+}
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index 249d9ba..808f30c 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -4,8 +4,9 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.net.Uri;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.provider.SyncConstValue;
import android.util.Config;
import android.util.Log;
@@ -14,9 +15,12 @@
import java.util.Collections;
import java.util.Map;
-import java.util.HashMap;
import java.util.Vector;
import java.util.ArrayList;
+import java.util.Set;
+import java.util.HashSet;
+
+import com.google.android.collect.Maps;
/**
* A specialization of the ContentProvider that centralizes functionality
@@ -32,26 +36,30 @@
private final String mDatabaseName;
private final int mDatabaseVersion;
private final Uri mContentUri;
- private AccountMonitor mAccountMonitor;
/** the account set in the last call to onSyncStart() */
- private String mSyncingAccount;
+ private Account mSyncingAccount;
private SyncStateContentProviderHelper mSyncState = null;
- private static final String[] sAccountProjection = new String[] {SyncConstValue._SYNC_ACCOUNT};
+ private static final String[] sAccountProjection =
+ new String[] {SyncConstValue._SYNC_ACCOUNT, SyncConstValue._SYNC_ACCOUNT_TYPE};
private boolean mIsTemporary;
private AbstractTableMerger mCurrentMerger = null;
private boolean mIsMergeCancelled = false;
- private static final String SYNC_ACCOUNT_WHERE_CLAUSE = SyncConstValue._SYNC_ACCOUNT + "=?";
+ private static final String SYNC_ACCOUNT_WHERE_CLAUSE =
+ SyncConstValue._SYNC_ACCOUNT + "=? AND " + SyncConstValue._SYNC_ACCOUNT_TYPE + "=?";
protected boolean isTemporary() {
return mIsTemporary;
}
+ private final ThreadLocal<Boolean> mApplyingBatch = new ThreadLocal<Boolean>();
+ private final ThreadLocal<Set<Uri>> mPendingBatchNotifications = new ThreadLocal<Set<Uri>>();
+
/**
* Indicates whether or not this ContentProvider contains a full
* set of data or just diffs. This knowledge comes in handy when
@@ -133,7 +141,8 @@
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (!upgradeDatabase(db, oldVersion, newVersion)) {
mSyncState.discardSyncData(db, null /* all accounts */);
- getContext().getContentResolver().startSync(mContentUri, new Bundle());
+ ContentResolver.requestSync(null /* all accounts */,
+ mContentUri.getAuthority(), new Bundle());
}
}
@@ -150,23 +159,36 @@
mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(),
mDatabaseName);
mSyncState = new SyncStateContentProviderHelper(mOpenHelper);
-
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- // Some providers override onAccountsChanged(); give them a database to work with.
- mDb = mOpenHelper.getWritableDatabase();
- onAccountsChanged(accounts);
- TempProviderSyncAdapter syncAdapter = (TempProviderSyncAdapter)getSyncAdapter();
- if (syncAdapter != null) {
- syncAdapter.onAccountsChanged(accounts);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(getContext(), listener);
+ AccountManager.get(getContext()).addOnAccountsUpdatedListener(
+ new OnAccountsUpdatedListener() {
+ public void onAccountsUpdated(Account[] accounts) {
+ // Some providers override onAccountsChanged(); give them a database to
+ // work with.
+ mDb = mOpenHelper.getWritableDatabase();
+ // Only call onAccountsChanged on GAIA accounts; otherwise, the contacts and
+ // calendar providers will choke as they try to sync unknown accounts with
+ // AbstractGDataSyncAdapter, which will put acore into a crash loop
+ ArrayList<Account> gaiaAccounts = new ArrayList<Account>();
+ for (Account acct: accounts) {
+ if (acct.type.equals("com.google.GAIA")) {
+ gaiaAccounts.add(acct);
+ }
+ }
+ accounts = new Account[gaiaAccounts.size()];
+ int i = 0;
+ for (Account acct: gaiaAccounts) {
+ accounts[i++] = acct;
+ }
+ onAccountsChanged(accounts);
+ TempProviderSyncAdapter syncAdapter = getTempProviderSyncAdapter();
+ if (syncAdapter != null) {
+ syncAdapter.onAccountsChanged(accounts);
+ }
+ }
+ }, null /* handler */, true /* updateImmediately */);
return true;
}
-
/**
* Get a non-persistent instance of this content provider.
* You must call {@link #close} on the returned
@@ -236,147 +258,117 @@
return Collections.emptyList();
}
- /**
- * <p>
- * Call mOpenHelper.getWritableDatabase() and mDb.beginTransaction().
- * {@link #endTransaction} MUST be called after calling this method.
- * Those methods should be used like this:
- * </p>
- *
- * <pre class="prettyprint">
- * boolean successful = false;
- * beginTransaction();
- * try {
- * // Do something related to mDb
- * successful = true;
- * return ret;
- * } finally {
- * endTransaction(successful);
- * }
- * </pre>
- *
- * @hide This method is dangerous from the view of database manipulation, though using
- * this makes batch insertion/update/delete much faster.
- */
- public final void beginTransaction() {
+ @Override
+ public final int update(final Uri url, final ContentValues values,
+ final String selection, final String[] selectionArgs) {
mDb = mOpenHelper.getWritableDatabase();
- mDb.beginTransaction();
- }
-
- /**
- * <p>
- * Call mDb.endTransaction(). If successful is true, try to call
- * mDb.setTransactionSuccessful() before calling mDb.endTransaction().
- * This method MUST be used with {@link #beginTransaction()}.
- * </p>
- *
- * @hide This method is dangerous from the view of database manipulation, though using
- * this makes batch insertion/update/delete much faster.
- */
- public final void endTransaction(boolean successful) {
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
+ }
try {
- if (successful) {
- // setTransactionSuccessful() must be called just once during opening the
- // transaction.
+ if (isTemporary() && mSyncState.matches(url)) {
+ int numRows = mSyncState.asContentProvider().update(
+ url, values, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return numRows;
+ }
+
+ int result = updateInternal(url, values, selection, selectionArgs);
+ if (notApplyingBatch) {
mDb.setTransactionSuccessful();
}
- } finally {
- mDb.endTransaction();
- }
- }
-
- @Override
- public final int update(final Uri uri, final ContentValues values,
- final String selection, final String[] selectionArgs) {
- boolean successful = false;
- beginTransaction();
- try {
- int ret = nonTransactionalUpdate(uri, values, selection, selectionArgs);
- successful = true;
- return ret;
- } finally {
- endTransaction(successful);
- }
- }
-
- /**
- * @hide
- */
- public final int nonTransactionalUpdate(final Uri uri, final ContentValues values,
- final String selection, final String[] selectionArgs) {
- if (isTemporary() && mSyncState.matches(uri)) {
- int numRows = mSyncState.asContentProvider().update(
- uri, values, selection, selectionArgs);
- return numRows;
- }
-
- int result = updateInternal(uri, values, selection, selectionArgs);
- if (!isTemporary() && result > 0) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
- }
-
- return result;
- }
-
- @Override
- public final int delete(final Uri uri, final String selection,
- final String[] selectionArgs) {
- boolean successful = false;
- beginTransaction();
- try {
- int ret = nonTransactionalDelete(uri, selection, selectionArgs);
- successful = true;
- return ret;
- } finally {
- endTransaction(successful);
- }
- }
-
- /**
- * @hide
- */
- public final int nonTransactionalDelete(final Uri uri, final String selection,
- final String[] selectionArgs) {
- if (isTemporary() && mSyncState.matches(uri)) {
- int numRows = mSyncState.asContentProvider().delete(uri, selection, selectionArgs);
- return numRows;
- }
- int result = deleteInternal(uri, selection, selectionArgs);
- if (!isTemporary() && result > 0) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
- }
- return result;
- }
-
- @Override
- public final Uri insert(final Uri uri, final ContentValues values) {
- boolean successful = false;
- beginTransaction();
- try {
- Uri ret = nonTransactionalInsert(uri, values);
- successful = true;
- return ret;
- } finally {
- endTransaction(successful);
- }
- }
-
- /**
- * @hide
- */
- public final Uri nonTransactionalInsert(final Uri uri, final ContentValues values) {
- if (isTemporary() && mSyncState.matches(uri)) {
- Uri result = mSyncState.asContentProvider().insert(uri, values);
+ if (!isTemporary() && result > 0) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
return result;
+ } finally {
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
}
- Uri result = insertInternal(uri, values);
- if (!isTemporary() && result != null) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
+ }
+
+ @Override
+ public final int delete(final Uri url, final String selection,
+ final String[] selectionArgs) {
+ mDb = mOpenHelper.getWritableDatabase();
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
}
- return result;
+ try {
+ if (isTemporary() && mSyncState.matches(url)) {
+ int numRows = mSyncState.asContentProvider().delete(url, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return numRows;
+ }
+ int result = deleteInternal(url, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ if (!isTemporary() && result > 0) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
+ return result;
+ } finally {
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
+ }
+ }
+
+ private boolean applyingBatch() {
+ return mApplyingBatch.get() != null && mApplyingBatch.get();
+ }
+
+ @Override
+ public final Uri insert(final Uri url, final ContentValues values) {
+ mDb = mOpenHelper.getWritableDatabase();
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
+ }
+ try {
+ if (isTemporary() && mSyncState.matches(url)) {
+ Uri result = mSyncState.asContentProvider().insert(url, values);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return result;
+ }
+ Uri result = insertInternal(url, values);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ if (!isTemporary() && result != null) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
+ return result;
+ } finally {
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
+ }
}
@Override
@@ -411,6 +403,92 @@
}
/**
+ * <p>
+ * Start batch transaction. {@link #endTransaction} MUST be called after
+ * calling this method. Those methods should be used like this:
+ * </p>
+ *
+ * <pre class="prettyprint">
+ * boolean successful = false;
+ * beginBatch()
+ * try {
+ * // Do something related to mDb
+ * successful = true;
+ * return ret;
+ * } finally {
+ * endBatch(successful);
+ * }
+ * </pre>
+ *
+ * @hide This method should be used only when {@link ContentProvider#applyBatch} is not enough and must be
+ * used with {@link #endBatch}.
+ * e.g. If returned value has to be used during one transaction, this method might be useful.
+ */
+ public final void beginBatch() {
+ // initialize if this is the first time this thread has applied a batch
+ if (mApplyingBatch.get() == null) {
+ mApplyingBatch.set(false);
+ mPendingBatchNotifications.set(new HashSet<Uri>());
+ }
+
+ if (applyingBatch()) {
+ throw new IllegalStateException(
+ "applyBatch is not reentrant but mApplyingBatch is already set");
+ }
+ SQLiteDatabase db = getDatabase();
+ db.beginTransaction();
+ boolean successful = false;
+ try {
+ mApplyingBatch.set(true);
+ successful = true;
+ } finally {
+ if (!successful) {
+ // Something unexpected happened. We must call endTransaction() at least.
+ db.endTransaction();
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Finish batch transaction. If "successful" is true, try to call
+ * mDb.setTransactionSuccessful() before calling mDb.endTransaction().
+ * This method MUST be used with {@link #beginBatch()}.
+ * </p>
+ *
+ * @hide This method must be used with {@link #beginTransaction}
+ */
+ public final void endBatch(boolean successful) {
+ try {
+ if (successful) {
+ // setTransactionSuccessful() must be called just once during opening the
+ // transaction.
+ mDb.setTransactionSuccessful();
+ }
+ } finally {
+ mApplyingBatch.set(false);
+ getDatabase().endTransaction();
+ for (Uri url : mPendingBatchNotifications.get()) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ }
+ }
+ }
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ boolean successful = false;
+ beginBatch();
+ try {
+ ContentProviderResult[] results = super.applyBatch(operations);
+ successful = true;
+ return results;
+ } finally {
+ endBatch(successful);
+ }
+ }
+
+ /**
* Check if changes to this URI can be syncable changes.
* @param uri the URI of the resource that was changed
* @return true if changes to this URI can be syncable changes, false otherwise
@@ -437,8 +515,8 @@
* @param context the sync context for the operation
* @param account
*/
- public void onSyncStart(SyncContext context, String account) {
- if (TextUtils.isEmpty(account)) {
+ public void onSyncStart(SyncContext context, Account account) {
+ if (account == null) {
throw new IllegalArgumentException("you passed in an empty account");
}
mSyncingAccount = account;
@@ -457,7 +535,7 @@
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
return mSyncingAccount;
}
@@ -568,12 +646,11 @@
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected void onAccountsChanged(String[] accountsArray) {
- Map<String, Boolean> accounts = new HashMap<String, Boolean>();
- for (String account : accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
+ Map<Account, Boolean> accounts = Maps.newHashMap();
+ for (Account account : accountsArray) {
accounts.put(account, false);
}
- accounts.put(SyncConstValue.NON_SYNCABLE_ACCOUNT, false);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
@@ -585,8 +662,7 @@
try {
mSyncState.onAccountsChanged(accountsArray);
for (String table : tables) {
- deleteRowsForRemovedAccounts(accounts, table,
- SyncConstValue._SYNC_ACCOUNT);
+ deleteRowsForRemovedAccounts(accounts, table);
}
db.setTransactionSuccessful();
} finally {
@@ -601,23 +677,23 @@
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(table, sAccountProjection, null, null,
- accountColumnName, null, null);
+ "_sync_account, _sync_account_type", null, null);
try {
while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ if (TextUtils.isEmpty(accountName)) {
continue;
}
+ Account account = new Account(accountName, accountType);
if (!accounts.containsKey(account)) {
int numDeleted;
- numDeleted = db.delete(table, accountColumnName + "=?", new String[]{account});
+ numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
+ new String[]{account.name, account.type});
if (Config.LOGV) {
Log.v(TAG, "deleted " + numDeleted
+ " records from table " + table
@@ -634,7 +710,7 @@
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
ArrayList<String> tables = new ArrayList<String>();
@@ -649,7 +725,8 @@
// remove the data in the synced tables
for (String table : tables) {
- db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE, new String[]{account});
+ db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
+ new String[]{account.name, account.type});
}
db.setTransactionSuccessful();
} finally {
@@ -660,14 +737,14 @@
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
return mSyncState.readSyncDataBytes(mOpenHelper.getReadableDatabase(), account);
}
/**
* Sets the SyncData bytes for the given account. The byte array may be null.
*/
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
mSyncState.writeSyncDataBytes(mOpenHelper.getWritableDatabase(), account, data);
}
}
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 9f609a3..9545fd7f 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -25,6 +25,7 @@
import static android.provider.SyncConstValue.*;
import android.text.TextUtils;
import android.util.Log;
+import android.accounts.Account;
/**
* @hide
@@ -55,15 +56,17 @@
private volatile boolean mIsMergeCancelled;
- private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and " + _SYNC_ACCOUNT + "=?";
+ private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and "
+ + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_SYNC_ID_AND_ACCOUNT =
- _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=?";
+ _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_ID = BaseColumns._ID +"=?";
private static final String SELECT_UNSYNCED =
- "(" + _SYNC_ACCOUNT + " IS NULL OR " + _SYNC_ACCOUNT + "=?) AND "
- + "(" + _SYNC_ID + " IS NULL OR (" + _SYNC_DIRTY + " > 0 AND "
+ "(" + _SYNC_ACCOUNT + " IS NULL OR ("
+ + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?)) and "
+ + "(" + _SYNC_ID + " IS NULL OR (" + _SYNC_DIRTY + " > 0 and "
+ _SYNC_VERSION + " IS NOT NULL))";
public AbstractTableMerger(SQLiteDatabase database,
@@ -134,7 +137,7 @@
* construct a temporary instance to hold them.
*/
public void merge(final SyncContext context,
- final String account,
+ final Account account,
final SyncableContentProvider serverDiffs,
TempProviderSyncResult result,
SyncResult syncResult, SyncableContentProvider temporaryInstanceFactory) {
@@ -157,7 +160,7 @@
* @hide this is public for testing purposes only
*/
public void mergeServerDiffs(SyncContext context,
- String account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
+ Account account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
boolean diffsArePartial = serverDiffs.getContainsDiffs();
// mark the current rows so that we can distinguish these from new
// inserts that occur during the merge
@@ -166,342 +169,340 @@
mDb.update(mDeletedTable, mSyncMarkValues, null, null);
}
- // load the local database entries, so we can merge them with the server
- final String[] accountSelectionArgs = new String[]{account};
- Cursor localCursor = mDb.query(mTable, syncDirtyProjection,
- SELECT_MARKED, accountSelectionArgs, null, null,
- mTable + "." + _SYNC_ID);
- Cursor deletedCursor;
- if (mDeletedTable != null) {
- deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+ Cursor localCursor = null;
+ Cursor deletedCursor = null;
+ Cursor diffsCursor = null;
+ try {
+ // load the local database entries, so we can merge them with the server
+ final String[] accountSelectionArgs = new String[]{account.name, account.type};
+ localCursor = mDb.query(mTable, syncDirtyProjection,
SELECT_MARKED, accountSelectionArgs, null, null,
- mDeletedTable + "." + _SYNC_ID);
- } else {
- deletedCursor =
- mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
- }
-
- // Apply updates and insertions from the server
- Cursor diffsCursor = serverDiffs.query(mTableURL,
- null, null, null, mTable + "." + _SYNC_ID);
- int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
- int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
- int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
- int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
- int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
-
- String lastSyncId = null;
- int diffsCount = 0;
- int localCount = 0;
- localCursor.moveToFirst();
- deletedCursor.moveToFirst();
- while (diffsCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- localCursor.close();
- deletedCursor.close();
- diffsCursor.close();
- return;
- }
- mDb.yieldIfContended();
- String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
- String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
- long localRowId = 0;
- String localSyncVersion = null;
-
- diffsCount++;
- context.setStatusText("Processing " + diffsCount + "/"
- + diffsCursor.getCount());
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
- diffsCount + ", " + serverSyncId);
-
- if (TRACE) {
- if (diffsCount == 10) {
- Debug.startMethodTracing("atmtrace");
- }
- if (diffsCount == 20) {
- Debug.stopMethodTracing();
- }
+ mTable + "." + _SYNC_ID);
+ if (mDeletedTable != null) {
+ deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+ SELECT_MARKED, accountSelectionArgs, null, null,
+ mDeletedTable + "." + _SYNC_ID);
+ } else {
+ deletedCursor =
+ mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
}
- boolean conflict = false;
- boolean update = false;
- boolean insert = false;
+ // Apply updates and insertions from the server
+ diffsCursor = serverDiffs.query(mTableURL,
+ null, null, null, mTable + "." + _SYNC_ID);
+ int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
+ int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+ int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
+ int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+ int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "found event with serverSyncID " + serverSyncId);
- }
- if (TextUtils.isEmpty(serverSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.e(TAG, "server entry doesn't have a serverSyncID");
- }
- continue;
- }
-
- // It is possible that the sync adapter wrote the same record multiple times,
- // e.g. if the same record came via multiple feeds. If this happens just ignore
- // the duplicate records.
- if (serverSyncId.equals(lastSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
- }
- continue;
- }
- lastSyncId = serverSyncId;
-
- String localSyncID = null;
- boolean localSyncDirty = false;
-
- while (!localCursor.isAfterLast()) {
+ String lastSyncId = null;
+ int diffsCount = 0;
+ int localCount = 0;
+ localCursor.moveToFirst();
+ deletedCursor.moveToFirst();
+ while (diffsCursor.moveToNext()) {
if (mIsMergeCancelled) {
- localCursor.deactivate();
- deletedCursor.deactivate();
- diffsCursor.deactivate();
return;
}
- localCount++;
- localSyncID = localCursor.getString(2);
+ mDb.yieldIfContended();
+ String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
+ String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
+ long localRowId = 0;
+ String localSyncVersion = null;
- // If the local record doesn't have a _sync_id then
- // it is new. Ignore it for now, we will send an insert
- // the the server later.
- if (TextUtils.isEmpty(localSyncID)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has no _sync_id, ignoring");
+ diffsCount++;
+ context.setStatusText("Processing " + diffsCount + "/"
+ + diffsCursor.getCount());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
+ diffsCount + ", " + serverSyncId);
+
+ if (TRACE) {
+ if (diffsCount == 10) {
+ Debug.startMethodTracing("atmtrace");
}
- localCursor.moveToNext();
- localSyncID = null;
+ if (diffsCount == 20) {
+ Debug.stopMethodTracing();
+ }
+ }
+
+ boolean conflict = false;
+ boolean update = false;
+ boolean insert = false;
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "found event with serverSyncID " + serverSyncId);
+ }
+ if (TextUtils.isEmpty(serverSyncId)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.e(TAG, "server entry doesn't have a serverSyncID");
+ }
continue;
}
- int comp = serverSyncId.compareTo(localSyncID);
-
- // the local DB has a record that the server doesn't have
- if (comp > 0) {
+ // It is possible that the sync adapter wrote the same record multiple times,
+ // e.g. if the same record came via multiple feeds. If this happens just ignore
+ // the duplicate records.
+ if (serverSyncId.equals(lastSyncId)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that is < server _sync_id " + serverSyncId);
+ Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
}
- if (diffsArePartial) {
- localCursor.moveToNext();
- } else {
- deleteRow(localCursor);
- if (mDeletedTable != null) {
- mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
- }
- syncResult.stats.numDeletes++;
- mDb.yieldIfContended();
- }
- localSyncID = null;
continue;
}
+ lastSyncId = serverSyncId;
- // the server has a record that the local DB doesn't have
- if (comp < 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that is > server _sync_id " + serverSyncId);
+ String localSyncID = null;
+ boolean localSyncDirty = false;
+
+ while (!localCursor.isAfterLast()) {
+ if (mIsMergeCancelled) {
+ return;
}
- localSyncID = null;
- }
+ localCount++;
+ localSyncID = localCursor.getString(2);
- // the server and the local DB both have this record
- if (comp == 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that matches the server _sync_id");
- }
- localSyncDirty = localCursor.getInt(0) != 0;
- localRowId = localCursor.getLong(1);
- localSyncVersion = localCursor.getString(3);
- localCursor.moveToNext();
- }
-
- break;
- }
-
- // If this record is in the deleted table then update the server version
- // in the deleted table, if necessary, and then ignore it here.
- // We will send a deletion indication to the server down a
- // little further.
- if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
- }
- final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
- if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
- + serverSyncVersion);
- }
- ContentValues values = new ContentValues();
- values.put(_SYNC_VERSION, serverSyncVersion);
- mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
- }
- continue;
- }
-
- // If the _sync_local_id is present in the diffsCursor
- // then this record corresponds to a local record that was just
- // inserted into the server and the _sync_local_id is the row id
- // of the local record. Set these fields so that the next check
- // treats this record as an update, which will allow the
- // merger to update the record with the server's sync id
- if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
- localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "the remote record with sync id " + serverSyncId
- + " has a local sync id, " + localRowId);
- }
- localSyncID = serverSyncId;
- localSyncDirty = false;
- localSyncVersion = null;
- }
-
- if (!TextUtils.isEmpty(localSyncID)) {
- // An existing server item has changed
- // If serverSyncVersion is null, there is no edit URL;
- // server won't let this change be written.
- boolean recordChanged = (localSyncVersion == null) ||
- (serverSyncVersion == null) ||
- !serverSyncVersion.equals(localSyncVersion);
- if (recordChanged) {
- if (localSyncDirty) {
+ // If the local record doesn't have a _sync_id then
+ // it is new. Ignore it for now, we will send an insert
+ // the the server later.
+ if (TextUtils.isEmpty(localSyncID)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId
- + " conflicts with local _sync_id " + localSyncID
- + ", local _id " + localRowId);
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has no _sync_id, ignoring");
}
- conflict = true;
+ localCursor.moveToNext();
+ localSyncID = null;
+ continue;
+ }
+
+ int comp = serverSyncId.compareTo(localSyncID);
+
+ // the local DB has a record that the server doesn't have
+ if (comp > 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that is < server _sync_id " + serverSyncId);
+ }
+ if (diffsArePartial) {
+ localCursor.moveToNext();
+ } else {
+ deleteRow(localCursor);
+ if (mDeletedTable != null) {
+ mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
+ }
+ syncResult.stats.numDeletes++;
+ mDb.yieldIfContended();
+ }
+ localSyncID = null;
+ continue;
+ }
+
+ // the server has a record that the local DB doesn't have
+ if (comp < 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that is > server _sync_id " + serverSyncId);
+ }
+ localSyncID = null;
+ }
+
+ // the server and the local DB both have this record
+ if (comp == 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that matches the server _sync_id");
+ }
+ localSyncDirty = localCursor.getInt(0) != 0;
+ localRowId = localCursor.getLong(1);
+ localSyncVersion = localCursor.getString(3);
+ localCursor.moveToNext();
+ }
+
+ break;
+ }
+
+ // If this record is in the deleted table then update the server version
+ // in the deleted table, if necessary, and then ignore it here.
+ // We will send a deletion indication to the server down a
+ // little further.
+ if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
+ }
+ final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
+ if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
+ + serverSyncVersion);
+ }
+ ContentValues values = new ContentValues();
+ values.put(_SYNC_VERSION, serverSyncVersion);
+ mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
+ }
+ continue;
+ }
+
+ // If the _sync_local_id is present in the diffsCursor
+ // then this record corresponds to a local record that was just
+ // inserted into the server and the _sync_local_id is the row id
+ // of the local record. Set these fields so that the next check
+ // treats this record as an update, which will allow the
+ // merger to update the record with the server's sync id
+ if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
+ localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the remote record with sync id " + serverSyncId
+ + " has a local sync id, " + localRowId);
+ }
+ localSyncID = serverSyncId;
+ localSyncDirty = false;
+ localSyncVersion = null;
+ }
+
+ if (!TextUtils.isEmpty(localSyncID)) {
+ // An existing server item has changed
+ // If serverSyncVersion is null, there is no edit URL;
+ // server won't let this change be written.
+ boolean recordChanged = (localSyncVersion == null) ||
+ (serverSyncVersion == null) ||
+ !serverSyncVersion.equals(localSyncVersion);
+ if (recordChanged) {
+ if (localSyncDirty) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "remote record " + serverSyncId
+ + " conflicts with local _sync_id " + localSyncID
+ + ", local _id " + localRowId);
+ }
+ conflict = true;
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG,
+ "remote record " +
+ serverSyncId +
+ " updates local _sync_id " +
+ localSyncID + ", local _id " +
+ localRowId);
+ }
+ update = true;
+ }
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
- "remote record " +
- serverSyncId +
- " updates local _sync_id " +
- localSyncID + ", local _id " +
- localRowId);
+ "Skipping update: localSyncVersion: " + localSyncVersion +
+ ", serverSyncVersion: " + serverSyncVersion);
}
- update = true;
}
} else {
+ // the local db doesn't know about this record so add it
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
+ }
+ insert = true;
+ }
+
+ if (update) {
+ updateRow(localRowId, serverDiffs, diffsCursor);
+ syncResult.stats.numUpdates++;
+ } else if (conflict) {
+ resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
+ syncResult.stats.numUpdates++;
+ } else if (insert) {
+ insertRow(serverDiffs, diffsCursor);
+ syncResult.stats.numInserts++;
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "processed " + diffsCount + " server entries");
+ }
+
+ // If tombstones aren't in use delete any remaining local rows that
+ // don't have corresponding server rows. Keep the rows that don't
+ // have a sync id since those were created locally and haven't been
+ // synced to the server yet.
+ if (!diffsArePartial) {
+ while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ localCount++;
+ final String localSyncId = localCursor.getString(2);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
- "Skipping update: localSyncVersion: " + localSyncVersion +
- ", serverSyncVersion: " + serverSyncVersion);
+ "deleting local record " +
+ localCursor.getLong(1) +
+ " _sync_id " + localSyncId);
}
+ deleteRow(localCursor);
+ if (mDeletedTable != null) {
+ mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
+ }
+ syncResult.stats.numDeletes++;
+ mDb.yieldIfContended();
}
- } else {
- // the local db doesn't know about this record so add it
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
- }
- insert = true;
}
-
- if (update) {
- updateRow(localRowId, serverDiffs, diffsCursor);
- syncResult.stats.numUpdates++;
- } else if (conflict) {
- resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
- syncResult.stats.numUpdates++;
- } else if (insert) {
- insertRow(serverDiffs, diffsCursor);
- syncResult.stats.numInserts++;
- }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
+ " local entries");
+ } finally {
+ if (diffsCursor != null) diffsCursor.close();
+ if (localCursor != null) localCursor.close();
+ if (deletedCursor != null) deletedCursor.close();
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "processed " + diffsCount + " server entries");
- }
-
- // If tombstones aren't in use delete any remaining local rows that
- // don't have corresponding server rows. Keep the rows that don't
- // have a sync id since those were created locally and haven't been
- // synced to the server yet.
- if (!diffsArePartial) {
- while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
- if (mIsMergeCancelled) {
- localCursor.deactivate();
- deletedCursor.deactivate();
- diffsCursor.deactivate();
- return;
- }
- localCount++;
- final String localSyncId = localCursor.getString(2);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG,
- "deleting local record " +
- localCursor.getLong(1) +
- " _sync_id " + localSyncId);
- }
- deleteRow(localCursor);
- if (mDeletedTable != null) {
- mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
- }
- syncResult.stats.numDeletes++;
- mDb.yieldIfContended();
- }
- }
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
- " local entries");
- diffsCursor.deactivate();
- localCursor.deactivate();
- deletedCursor.deactivate();
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "applying deletions from the server");
// Apply deletions from the server
if (mDeletedTableURL != null) {
diffsCursor = serverDiffs.query(mDeletedTableURL, null, null, null, null);
-
- while (diffsCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- diffsCursor.deactivate();
- return;
+ try {
+ while (diffsCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ // delete all rows that match each element in the diffsCursor
+ fullyDeleteMatchingRows(diffsCursor, account, syncResult);
+ mDb.yieldIfContended();
}
- // delete all rows that match each element in the diffsCursor
- fullyDeleteMatchingRows(diffsCursor, account, syncResult);
- mDb.yieldIfContended();
+ } finally {
+ diffsCursor.close();
}
- diffsCursor.deactivate();
}
}
- private void fullyDeleteMatchingRows(Cursor diffsCursor, String account,
+ private void fullyDeleteMatchingRows(Cursor diffsCursor, Account account,
SyncResult syncResult) {
int serverSyncIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn);
// delete the rows explicitly so that the delete operation can be overridden
- final Cursor c;
final String[] selectionArgs;
- if (deleteBySyncId) {
- selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
- c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
- selectionArgs, null, null, null);
- } else {
- int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
- selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
- c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
- null, null, null);
- }
+ Cursor c = null;
try {
+ if (deleteBySyncId) {
+ selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
+ account.name, account.type};
+ c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
+ selectionArgs, null, null, null);
+ } else {
+ int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
+ selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
+ c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
+ null, null, null);
+ }
c.moveToFirst();
while (!c.isAfterLast()) {
deleteRow(c); // advances the cursor
syncResult.stats.numDeletes++;
}
} finally {
- c.deactivate();
+ if (c != null) c.close();
}
if (deleteBySyncId && mDeletedTable != null) {
mDb.delete(mDeletedTable, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs);
@@ -519,43 +520,46 @@
* Finds local changes, placing the results in the given result object.
* @param temporaryInstanceFactory As an optimization for the case
* where there are no client-side diffs, mergeResult may initially
- * have no {@link android.content.TempProviderSyncResult#tempContentProvider}. If this is
+ * have no {@link TempProviderSyncResult#tempContentProvider}. If this is
* the first in the sequence of AbstractTableMergers to find
* client-side diffs, it will use the given ContentProvider to
* create a temporary instance and store its {@link
- * ContentProvider} in the mergeResult.
+ * android.content.ContentProvider} in the mergeResult.
* @param account
* @param syncResult
*/
private void findLocalChanges(TempProviderSyncResult mergeResult,
- SyncableContentProvider temporaryInstanceFactory, String account,
+ SyncableContentProvider temporaryInstanceFactory, Account account,
SyncResult syncResult) {
SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
- final String[] accountSelectionArgs = new String[]{account};
+ final String[] accountSelectionArgs = new String[]{account.name, account.type};
// Generate the client updates and insertions
// Create a cursor for dirty records
+ long numInsertsOrUpdates = 0;
Cursor localChangesCursor = mDb.query(mTable, null, SELECT_UNSYNCED, accountSelectionArgs,
null, null, null);
- long numInsertsOrUpdates = localChangesCursor.getCount();
- while (localChangesCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- localChangesCursor.close();
- return;
+ try {
+ numInsertsOrUpdates = localChangesCursor.getCount();
+ while (localChangesCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ if (clientDiffs == null) {
+ clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ }
+ mValues.clear();
+ cursorRowToContentValues(localChangesCursor, mValues);
+ mValues.remove("_id");
+ DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
+ _SYNC_LOCAL_ID);
+ clientDiffs.insert(mTableURL, mValues);
}
- if (clientDiffs == null) {
- clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
- }
- mValues.clear();
- cursorRowToContentValues(localChangesCursor, mValues);
- mValues.remove("_id");
- DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
- _SYNC_LOCAL_ID);
- clientDiffs.insert(mTableURL, mValues);
+ } finally {
+ localChangesCursor.close();
}
- localChangesCursor.close();
// Generate the client deletions
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client deletions");
@@ -564,23 +568,25 @@
if (mDeletedTable != null) {
Cursor deletedCursor = mDb.query(mDeletedTable,
syncIdAndVersionProjection,
- _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
+ _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=? AND "
+ + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
null, null, mDeletedTable + "." + _SYNC_ID);
-
- numDeletedEntries = deletedCursor.getCount();
- while (deletedCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- deletedCursor.close();
- return;
+ try {
+ numDeletedEntries = deletedCursor.getCount();
+ while (deletedCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ if (clientDiffs == null) {
+ clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ }
+ mValues.clear();
+ DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
+ clientDiffs.insert(mDeletedTableURL, mValues);
}
- if (clientDiffs == null) {
- clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
- }
- mValues.clear();
- DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
- clientDiffs.insert(mDeletedTableURL, mValues);
+ } finally {
+ deletedCursor.close();
}
- deletedCursor.close();
}
if (clientDiffs != null) {
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
new file mode 100644
index 0000000..f15a902
--- /dev/null
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Process;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation.
+ * If a sync operation is already in progress when a startSync() request is received then an error
+ * will be returned to the new request and the existing request will be allowed to continue.
+ * When a startSync() is received and there is no sync operation in progress then a thread
+ * will be started to run the operation and {@link #performSync} will be invoked on that thread.
+ * If a cancelSync() is received that matches an existing sync operation then the thread
+ * that is running that sync operation will be interrupted, which will indicate to the thread
+ * that the sync has been canceled.
+ *
+ * @hide
+ */
+public abstract class AbstractThreadedSyncAdapter {
+ private final Context mContext;
+ private final AtomicInteger mNumSyncStarts;
+ private final ISyncAdapterImpl mISyncAdapterImpl;
+
+ // all accesses to this member variable must be synchronized on "this"
+ private SyncThread mSyncThread;
+
+ /** Kernel event log tag. Also listed in data/etc/event-log-tags. */
+ public static final int LOG_SYNC_DETAILS = 2743;
+
+ /**
+ * Creates an {@link AbstractThreadedSyncAdapter}.
+ * @param context the {@link Context} that this is running within.
+ */
+ public AbstractThreadedSyncAdapter(Context context) {
+ mContext = context;
+ mISyncAdapterImpl = new ISyncAdapterImpl();
+ mNumSyncStarts = new AtomicInteger(0);
+ mSyncThread = null;
+ }
+
+ class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ public void startSync(ISyncContext syncContext, String authority, Account account,
+ Bundle extras) {
+ final SyncContext syncContextClient = new SyncContext(syncContext);
+
+ boolean alreadyInProgress;
+ // synchronize to make sure that mSyncThread doesn't change between when we
+ // check it and when we use it
+ synchronized (this) {
+ if (mSyncThread == null) {
+ mSyncThread = new SyncThread(
+ "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(),
+ syncContextClient, authority, account, extras);
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ mSyncThread.start();
+ alreadyInProgress = false;
+ } else {
+ alreadyInProgress = true;
+ }
+ }
+
+ // do this outside since we don't want to call back into the syncContext while
+ // holding the synchronization lock
+ if (alreadyInProgress) {
+ syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS);
+ }
+ }
+
+ public void cancelSync(ISyncContext syncContext) {
+ // synchronize to make sure that mSyncThread doesn't change between when we
+ // check it and when we use it
+ synchronized (this) {
+ if (mSyncThread != null
+ && mSyncThread.mSyncContext.getISyncContext() == syncContext) {
+ mSyncThread.interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * The thread that invokes performSync(). It also acquires the provider for this sync
+ * before calling performSync and releases it afterwards. Cancel this thread in order to
+ * cancel the sync.
+ */
+ private class SyncThread extends Thread {
+ private final SyncContext mSyncContext;
+ private final String mAuthority;
+ private final Account mAccount;
+ private final Bundle mExtras;
+
+ private SyncThread(String name, SyncContext syncContext, String authority,
+ Account account, Bundle extras) {
+ super(name);
+ mSyncContext = syncContext;
+ mAuthority = authority;
+ mAccount = account;
+ mExtras = extras;
+ }
+
+ public void run() {
+ if (isCanceled()) {
+ return;
+ }
+
+ SyncResult syncResult = new SyncResult();
+ ContentProviderClient provider = null;
+ try {
+ provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority);
+ if (provider != null) {
+ AbstractThreadedSyncAdapter.this.performSync(mAccount, mExtras,
+ mAuthority, provider, syncResult);
+ } else {
+ // TODO(fredq) update the syncResults to indicate that we were unable to
+ // find the provider. maybe with a ProviderError?
+ }
+ } finally {
+ if (provider != null) {
+ provider.release();
+ }
+ if (!isCanceled()) {
+ mSyncContext.onFinished(syncResult);
+ }
+ // synchronize so that the assignment will be seen by other threads
+ // that also synchronize accesses to mSyncThread
+ synchronized (this) {
+ mSyncThread = null;
+ }
+ }
+ }
+
+ private boolean isCanceled() {
+ return Thread.currentThread().isInterrupted();
+ }
+ }
+
+ /**
+ * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation.
+ */
+ public final ISyncAdapter getISyncAdapter() {
+ return mISyncAdapterImpl;
+ }
+
+ /**
+ * Perform a sync for this account. SyncAdapter-specific parameters may
+ * be specified in extras, which is guaranteed to not be null. Invocations
+ * of this method are guaranteed to be serialized.
+ *
+ * @param account the account that should be synced
+ * @param extras SyncAdapter-specific parameters
+ * @param authority the authority of this sync request
+ * @param provider a ContentProviderClient that points to the ContentProvider for this
+ * authority
+ * @param syncResult SyncAdapter-specific parameters
+ */
+ public abstract void performSync(Account account, Bundle extras,
+ String authority, ContentProviderClient provider, SyncResult syncResult);
+}
\ No newline at end of file
diff --git a/core/java/android/content/ActiveSyncInfo.java b/core/java/android/content/ActiveSyncInfo.java
index 63be8d1..209dffa 100644
--- a/core/java/android/content/ActiveSyncInfo.java
+++ b/core/java/android/content/ActiveSyncInfo.java
@@ -16,17 +16,18 @@
package android.content;
+import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable.Creator;
/** @hide */
public class ActiveSyncInfo {
public final int authorityId;
- public final String account;
+ public final Account account;
public final String authority;
public final long startTime;
- ActiveSyncInfo(int authorityId, String account, String authority,
+ ActiveSyncInfo(int authorityId, Account account, String authority,
long startTime) {
this.authorityId = authorityId;
this.account = account;
@@ -40,14 +41,14 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(authorityId);
- parcel.writeString(account);
+ account.writeToParcel(parcel, 0);
parcel.writeString(authority);
parcel.writeLong(startTime);
}
ActiveSyncInfo(Parcel parcel) {
authorityId = parcel.readInt();
- account = parcel.readString();
+ account = new Account(parcel);
authority = parcel.readString();
startTime = parcel.readLong();
}
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index ac851cc..5e88de0 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -38,7 +38,8 @@
private static final int EVENT_ARG_INSERT = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
-
+ private static final int EVENT_ARG_QUERY_ENTITIES = 5;
+
/* package */ final WeakReference<ContentResolver> mResolver;
private static Looper sLooper = null;
@@ -85,12 +86,25 @@
cursor.getCount();
}
} catch (Exception e) {
+ Log.w(TAG, e.toString());
cursor = null;
}
args.result = cursor;
break;
+ case EVENT_ARG_QUERY_ENTITIES:
+ EntityIterator iterator = null;
+ try {
+ iterator = resolver.queryEntities(args.uri, args.selection,
+ args.selectionArgs, args.orderBy);
+ } catch (Exception e) {
+ Log.w(TAG, e.toString());
+ }
+
+ args.result = iterator;
+ break;
+
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
@@ -103,7 +117,6 @@
case EVENT_ARG_DELETE:
args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
break;
-
}
// passing the original token value back to the caller
@@ -128,7 +141,7 @@
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
thread.start();
-
+
sLooper = thread.getLooper();
}
}
@@ -182,6 +195,44 @@
}
/**
+ * This method begins an asynchronous query for an {@link EntityIterator}.
+ * When the query is done {@link #onQueryEntitiesComplete} is called.
+ *
+ * @param token A token passed into {@link #onQueryComplete} to identify the
+ * query.
+ * @param cookie An object that gets passed into {@link #onQueryComplete}
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null
+ * will return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that
+ * they appear in the selection. The values will be bound as
+ * Strings.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+ * (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ */
+ public void startQueryEntities(int token, Object cookie, Uri uri, String selection,
+ String[] selectionArgs, String orderBy) {
+ // Use the token as what so cancelOperations works properly
+ Message msg = mWorkerThreadHandler.obtainMessage(token);
+ msg.arg1 = EVENT_ARG_QUERY_ENTITIES;
+
+ WorkerArgs args = new WorkerArgs();
+ args.handler = this;
+ args.uri = uri;
+ args.selection = selection;
+ args.selectionArgs = selectionArgs;
+ args.orderBy = orderBy;
+ args.cookie = cookie;
+ msg.obj = args;
+
+ mWorkerThreadHandler.sendMessage(msg);
+ }
+
+ /**
* Attempts to cancel operation that has not already started. Note that
* there is no guarantee that the operation will be canceled. They still may
* result in a call to on[Query/Insert/Update/Delete]Complete after this
@@ -279,8 +330,8 @@
* Called when an asynchronous query is completed.
*
* @param token the token to identify the query, passed in from
- * {@link #startQuery}.
- * @param cookie the cookie object that's passed in from {@link #startQuery}.
+ * {@link #startQuery}.
+ * @param cookie the cookie object passed in from {@link #startQuery}.
* @param cursor The cursor holding the results from the query.
*/
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
@@ -288,6 +339,17 @@
}
/**
+ * Called when an asynchronous query is completed.
+ *
+ * @param token The token to identify the query.
+ * @param cookie The cookie object.
+ * @param iterator The iterator holding the query results.
+ */
+ protected void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ // Empty
+ }
+
+ /**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, passed in from
@@ -337,13 +399,17 @@
int token = msg.what;
int event = msg.arg1;
-
+
// pass token back to caller on each callback.
switch (event) {
case EVENT_ARG_QUERY:
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
+ case EVENT_ARG_QUERY_ENTITIES:
+ onQueryEntitiesComplete(token, args.cookie, (EntityIterator)args.result);
+ break;
+
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 6b50405..5b29b97 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -34,6 +34,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* Content providers are one of the primary building blocks of Android applications, providing
@@ -130,6 +131,12 @@
selectionArgs, sortOrder);
}
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ enforceReadPermission(uri);
+ return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
@@ -145,6 +152,25 @@
return ContentProvider.this.bulkInsert(uri, initialValues);
}
+ public Uri insertEntity(Uri uri, Entity entities) {
+ enforceWritePermission(uri);
+ return ContentProvider.this.insertEntity(uri, entities);
+ }
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ for (ContentProviderOperation operation : operations) {
+ if (operation.isReadOperation()) {
+ enforceReadPermission(operation.getUri());
+ }
+
+ if (operation.isWriteOperation()) {
+ enforceWritePermission(operation.getUri());
+ }
+ }
+ return ContentProvider.this.applyBatch(operations);
+ }
+
public int delete(Uri uri, String selection, String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -156,6 +182,11 @@
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
+ public int updateEntity(Uri uri, Entity entity) {
+ enforceWritePermission(uri);
+ return ContentProvider.this.updateEntity(uri, entity);
+ }
+
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -170,12 +201,6 @@
return ContentProvider.this.openAssetFile(uri, mode);
}
- public ISyncAdapter getSyncAdapter() {
- enforceWritePermission(null);
- SyncAdapter sa = ContentProvider.this.getSyncAdapter();
- return sa != null ? sa.getISyncAdapter() : null;
- }
-
private void enforceReadPermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
@@ -377,9 +402,10 @@
* Example client call:<p>
* <pre>// Request a specific record.
* Cursor managedCursor = managedQuery(
- Contacts.People.CONTENT_URI.addId(2),
+ ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
projection, // Which columns to return.
null, // WHERE clause.
+ null, // WHERE clause value substitution
People.NAME + " ASC"); // Sort order.</pre>
* Example implementation:<p>
* <pre>// SQLiteQueryBuilder is a helper class that creates the
@@ -408,20 +434,28 @@
return c;</pre>
*
* @param uri The URI to query. This will be the full URI sent by the client;
- * if the client is requesting a specific record, the URI will end in a record number
- * that the implementation should parse and add to a WHERE or HAVING clause, specifying
- * that _id value.
+ * if the client is requesting a specific record, the URI will end in a record number
+ * that the implementation should parse and add to a WHERE or HAVING clause, specifying
+ * that _id value.
* @param projection The list of columns to put into the cursor. If
* null all columns are included.
* @param selection A selection criteria to apply when filtering rows.
* If null then all rows are included.
+ * @param selectionArgs You may include ?s in selection, which will be replaced by
+ * the values from selectionArgs, in order that they appear in the selection.
+ * The values will be bound as Strings.
* @param sortOrder How the rows in the cursor should be sorted.
- * If null then the provider is free to define the sort order.
+ * If null then the provider is free to define the sort order.
* @return a Cursor or null.
*/
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Return the MIME type of the data at the given URI. This should start with
* <code>vnd.android.cursor.item</code> for a single record,
@@ -472,6 +506,10 @@
return numValues;
}
+ public Uri insertEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* A request to delete one or more rows. The selection clause is applied when performing
* the deletion, allowing the operation to affect multiple rows in a
@@ -516,6 +554,10 @@
public abstract int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs);
+ public int updateEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Open a file blob associated with a content URI.
* This method can be called from multiple
@@ -639,23 +681,6 @@
}
/**
- * Get the sync adapter that is to be used by this content provider.
- * This is intended for use by the sync system. If null then this
- * content provider is considered not syncable.
- * This method can be called from multiple
- * threads, as described in
- * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
- * Processes and Threads</a>.
- *
- * @return the SyncAdapter that is to be used by this ContentProvider, or null
- * if this ContentProvider is not syncable
- * @hide
- */
- public SyncAdapter getSyncAdapter() {
- return null;
- }
-
- /**
* Returns true if this instance is a temporary content provider.
* @return true if this instance is a temporary content provider
*/
@@ -697,4 +722,27 @@
ContentProvider.this.onCreate();
}
}
-}
+
+ /**
+ * Applies each of the {@link ContentProviderOperation} objects and returns an array
+ * of their results. Passes through OperationApplicationException, which may be thrown
+ * by the call to {@link ContentProviderOperation#apply}.
+ * If all the applications succeed then a {@link ContentProviderResult} array with the
+ * same number of elements as the operations will be returned. It is implementation-specific
+ * how many, if any, operations will have been successfully applied if a call to
+ * apply results in a {@link OperationApplicationException}.
+ * @param operations the operations to apply
+ * @return the results of the applications
+ * @throws OperationApplicationException thrown if an application fails.
+ * See {@link ContentProviderOperation#apply} for more information.
+ */
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ final int numOperations = operations.size();
+ final ContentProviderResult[] results = new ContentProviderResult[numOperations];
+ for (int i = 0; i < numOperations; i++) {
+ results[i] = operations.get(i).apply(this, results, i);
+ }
+ return results;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
new file mode 100644
index 0000000..452653e
--- /dev/null
+++ b/core/java/android/content/ContentProviderClient.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ParcelFileDescriptor;
+import android.content.res.AssetFileDescriptor;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
+ * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
+ * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
+ * no longer needed and can be killed to free up resources.
+ */
+public class ContentProviderClient {
+ private final IContentProvider mContentProvider;
+ private final ContentResolver mContentResolver;
+
+ /**
+ * @hide
+ */
+ ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider) {
+ mContentProvider = contentProvider;
+ mContentResolver = contentResolver;
+ }
+
+ /** see {@link ContentProvider#query} */
+ public Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) throws RemoteException {
+ return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder);
+ }
+
+ /** see {@link ContentProvider#getType} */
+ public String getType(Uri url) throws RemoteException {
+ return mContentProvider.getType(url);
+ }
+
+ /** see {@link ContentProvider#insert} */
+ public Uri insert(Uri url, ContentValues initialValues)
+ throws RemoteException {
+ return mContentProvider.insert(url, initialValues);
+ }
+
+ /** see {@link ContentProvider#bulkInsert} */
+ public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+ return mContentProvider.bulkInsert(url, initialValues);
+ }
+
+ /** see {@link ContentProvider#delete} */
+ public int delete(Uri url, String selection, String[] selectionArgs)
+ throws RemoteException {
+ return mContentProvider.delete(url, selection, selectionArgs);
+ }
+
+ /** see {@link ContentProvider#update} */
+ public int update(Uri url, ContentValues values, String selection,
+ String[] selectionArgs) throws RemoteException {
+ return mContentProvider.update(url, values, selection, selectionArgs);
+ }
+
+ /** see {@link ContentProvider#openFile} */
+ public ParcelFileDescriptor openFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
+ return mContentProvider.openFile(url, mode);
+ }
+
+ /** see {@link ContentProvider#openAssetFile} */
+ public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
+ return mContentProvider.openAssetFile(url, mode);
+ }
+
+ /** see {@link ContentProvider#queryEntities} */
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ return mContentProvider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
+ /** see {@link ContentProvider#insertEntity} */
+ public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.insertEntity(uri, entity);
+ }
+
+ /** see {@link ContentProvider#updateEntity} */
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.updateEntity(uri, entity);
+ }
+
+ /** see {@link ContentProvider#applyBatch} */
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ return mContentProvider.applyBatch(operations);
+ }
+
+ /**
+ * Call this to indicate to the system that the associated {@link ContentProvider} is no
+ * longer needed by this {@link ContentProviderClient}.
+ * @return true if this was release, false if it was already released
+ */
+ public boolean release() {
+ return mContentResolver.releaseProvider(mContentProvider);
+ }
+
+ /**
+ * Get a reference to the {@link ContentProvider} that is associated with this
+ * client. If the {@link ContentProvider} is running in a different process then
+ * null will be returned. This can be used if you know you are running in the same
+ * process as a provider, and want to get direct access to its implementation details.
+ *
+ * @return If the associated {@link ContentProvider} is local, returns it.
+ * Otherwise returns null.
+ */
+ public ContentProvider getLocalContentProvider() {
+ return ContentProvider.coerceToLocalContentProvider(mContentProvider);
+ }
+}
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index e5e3f74..a4c217b 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -33,6 +33,7 @@
import android.os.Parcelable;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* {@hide}
@@ -105,6 +106,20 @@
return true;
}
+ case QUERY_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri url = Uri.CREATOR.createFromParcel(data);
+ String selection = data.readString();
+ String[] selectionArgs = data.readStringArray();
+ String sortOrder = data.readString();
+ EntityIterator entityIterator = queryEntities(url, selection, selectionArgs,
+ sortOrder);
+ reply.writeNoException();
+ reply.writeStrongBinder(new IEntityIteratorImpl(entityIterator).asBinder());
+ return true;
+ }
+
case GET_TYPE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -140,6 +155,43 @@
return true;
}
+ case INSERT_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ Entity entity = (Entity) data.readParcelable(null);
+ Uri newUri = insertEntity(uri, entity);
+ reply.writeNoException();
+ Uri.writeToParcel(reply, newUri);
+ return true;
+ }
+
+ case UPDATE_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ Entity entity = (Entity) data.readParcelable(null);
+ int count = updateEntity(uri, entity);
+ reply.writeNoException();
+ reply.writeInt(count);
+ return true;
+ }
+
+ case APPLY_BATCH_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ final int numOperations = data.readInt();
+ final ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>(numOperations);
+ for (int i = 0; i < numOperations; i++) {
+ operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
+ }
+ final ContentProviderResult[] results = applyBatch(operations);
+ reply.writeNoException();
+ reply.writeTypedArray(results, 0);
+ return true;
+ }
+
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -206,15 +258,6 @@
}
return true;
}
-
- case GET_SYNC_ADAPTER_TRANSACTION:
- {
- data.enforceInterface(IContentProvider.descriptor);
- ISyncAdapter sa = getSyncAdapter();
- reply.writeNoException();
- reply.writeStrongBinder(sa != null ? sa.asBinder() : null);
- return true;
- }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -224,6 +267,25 @@
return super.onTransact(code, data, reply, flags);
}
+ private class IEntityIteratorImpl extends IEntityIterator.Stub {
+ private final EntityIterator mEntityIterator;
+
+ IEntityIteratorImpl(EntityIterator iterator) {
+ mEntityIterator = iterator;
+ }
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() throws RemoteException {
+ mEntityIterator.close();
+ }
+ }
+
public IBinder asBinder()
{
return this;
@@ -297,7 +359,7 @@
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
adaptor.getObserver(), window);
-
+
if (bulkCursor == null) {
return null;
}
@@ -305,6 +367,54 @@
return adaptor;
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ url.writeToParcel(data, 0);
+ data.writeString(selection);
+ data.writeStringArray(selectionArgs);
+ data.writeString(sortOrder);
+
+ mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+
+ IBinder entityIteratorBinder = reply.readStrongBinder();
+
+ data.recycle();
+ reply.recycle();
+
+ return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder));
+ }
+
+ static class RemoteEntityIterator implements EntityIterator {
+ private final IEntityIterator mEntityIterator;
+ RemoteEntityIterator(IEntityIterator entityIterator) {
+ mEntityIterator = entityIterator;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() {
+ try {
+ mEntityIterator.close();
+ } catch (RemoteException e) {
+ // doesn't matter
+ }
+ }
+ }
+
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -366,6 +476,66 @@
return count;
}
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeInt(operations.size());
+ for (ContentProviderOperation operation : operations) {
+ operation.writeToParcel(data, 0);
+ }
+ mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
+ final ContentProviderResult[] results =
+ reply.createTypedArray(ContentProviderResult.CREATOR);
+
+ data.recycle();
+ reply.recycle();
+
+ return results;
+ }
+
+ public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeParcelable(entity, 0);
+
+ mRemote.transact(IContentProvider.INSERT_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ return Uri.CREATOR.createFromParcel(reply);
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeParcelable(entity, 0);
+
+ mRemote.transact(IContentProvider.UPDATE_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ return reply.readInt();
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -456,23 +626,6 @@
return fd;
}
- public ISyncAdapter getSyncAdapter() throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
-
- data.writeInterfaceToken(IContentProvider.descriptor);
-
- mRemote.transact(IContentProvider.GET_SYNC_ADAPTER_TRANSACTION, data, reply, 0);
-
- DatabaseUtils.readExceptionFromParcel(reply);
- ISyncAdapter syncAdapter = ISyncAdapter.Stub.asInterface(reply.readStrongBinder());
-
- data.recycle();
- reply.recycle();
-
- return syncAdapter;
- }
-
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
new file mode 100644
index 0000000..f5a4b75
--- /dev/null
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ContentProviderOperation implements Parcelable {
+ /** @hide exposed for unit tests */
+ public final static int TYPE_INSERT = 1;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_UPDATE = 2;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_DELETE = 3;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_ASSERT = 4;
+
+ private final int mType;
+ private final Uri mUri;
+ private final String mSelection;
+ private final String[] mSelectionArgs;
+ private final ContentValues mValues;
+ private final Integer mExpectedCount;
+ private final ContentValues mValuesBackReferences;
+ private final Map<Integer, Integer> mSelectionArgsBackReferences;
+
+ /**
+ * Creates a {@link ContentProviderOperation} by copying the contents of a
+ * {@link Builder}.
+ */
+ private ContentProviderOperation(Builder builder) {
+ mType = builder.mType;
+ mUri = builder.mUri;
+ mValues = builder.mValues;
+ mSelection = builder.mSelection;
+ mSelectionArgs = builder.mSelectionArgs;
+ mExpectedCount = builder.mExpectedCount;
+ mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
+ mValuesBackReferences = builder.mValuesBackReferences;
+ }
+
+ private ContentProviderOperation(Parcel source) {
+ mType = source.readInt();
+ mUri = Uri.CREATOR.createFromParcel(source);
+ mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
+ mSelection = source.readInt() != 0 ? source.readString() : null;
+ mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
+ mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
+ mValuesBackReferences = source.readInt() != 0
+
+ ? ContentValues.CREATOR.createFromParcel(source)
+ : null;
+ mSelectionArgsBackReferences = source.readInt() != 0
+ ? new HashMap<Integer, Integer>()
+ : null;
+ if (mSelectionArgsBackReferences != null) {
+ final int count = source.readInt();
+ for (int i = 0; i < count; i++) {
+ mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
+ }
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType);
+ Uri.writeToParcel(dest, mUri);
+ if (mValues != null) {
+ dest.writeInt(1);
+ mValues.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelection != null) {
+ dest.writeInt(1);
+ dest.writeString(mSelection);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelectionArgs != null) {
+ dest.writeInt(1);
+ dest.writeStringArray(mSelectionArgs);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mExpectedCount != null) {
+ dest.writeInt(1);
+ dest.writeInt(mExpectedCount);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mValuesBackReferences != null) {
+ dest.writeInt(1);
+ mValuesBackReferences.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelectionArgsBackReferences != null) {
+ dest.writeInt(1);
+ dest.writeInt(mSelectionArgsBackReferences.size());
+ for (Map.Entry<Integer, Integer> entry : mSelectionArgsBackReferences.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeInt(entry.getValue());
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building an insert {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the insert.
+ * @return a {@link Builder}
+ */
+ public static Builder newInsert(Uri uri) {
+ return new Builder(TYPE_INSERT, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building an update {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the update.
+ * @return a {@link Builder}
+ */
+ public static Builder newUpdate(Uri uri) {
+ return new Builder(TYPE_UPDATE, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building a delete {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the delete.
+ * @return a {@link Builder}
+ */
+ public static Builder newDelete(Uri uri) {
+ return new Builder(TYPE_DELETE, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building a
+ * {@link ContentProviderOperation} to assert a set of values as provided
+ * through {@link Builder#withValues(ContentValues)}.
+ */
+ public static Builder newAssertQuery(Uri uri) {
+ return new Builder(TYPE_ASSERT, uri);
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /** @hide exposed for unit tests */
+ public int getType() {
+ return mType;
+ }
+
+ public boolean isWriteOperation() {
+ return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
+ }
+
+ public boolean isReadOperation() {
+ return mType == TYPE_ASSERT;
+ }
+
+ /**
+ * Applies this operation using the given provider. The backRefs array is used to resolve any
+ * back references that were requested using
+ * {@link Builder#withValueBackReferences(ContentValues)} and
+ * {@link Builder#withSelectionBackReference}.
+ * @param provider the {@link ContentProvider} on which this batch is applied
+ * @param backRefs a {@link ContentProviderResult} array that will be consulted
+ * to resolve any requested back references.
+ * @param numBackRefs the number of valid results on the backRefs array.
+ * @return a {@link ContentProviderResult} that contains either the {@link Uri} of the inserted
+ * row if this was an insert otherwise the number of rows affected.
+ * @throws OperationApplicationException thrown if either the insert fails or
+ * if the number of rows affected didn't match the expected count
+ */
+ public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
+ int numBackRefs) throws OperationApplicationException {
+ ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
+ String[] selectionArgs =
+ resolveSelectionArgsBackReferences(backRefs, numBackRefs);
+
+ if (mType == TYPE_INSERT) {
+ Uri newUri = provider.insert(mUri, values);
+ if (newUri == null) {
+ throw new OperationApplicationException("insert failed");
+ }
+ return new ContentProviderResult(newUri);
+ }
+
+ int numRows;
+ if (mType == TYPE_DELETE) {
+ numRows = provider.delete(mUri, mSelection, selectionArgs);
+ } else if (mType == TYPE_UPDATE) {
+ numRows = provider.update(mUri, values, mSelection, selectionArgs);
+ } else if (mType == TYPE_ASSERT) {
+ // Build projection map from expected values
+ final ArrayList<String> projectionList = new ArrayList<String>();
+ for (Map.Entry<String, Object> entry : values.valueSet()) {
+ projectionList.add(entry.getKey());
+ }
+
+ // Assert that all rows match expected values
+ final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+ final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
+ numRows = cursor.getCount();
+ try {
+ while (cursor.moveToNext()) {
+ for (int i = 0; i < projection.length; i++) {
+ final String cursorValue = cursor.getString(i);
+ final String expectedValue = values.getAsString(projection[i]);
+ if (!TextUtils.equals(cursorValue, expectedValue)) {
+ // Throw exception when expected values don't match
+ throw new OperationApplicationException("Found value " + cursorValue
+ + " when expected " + expectedValue + " for column "
+ + projection[i]);
+ }
+ }
+ }
+ } finally {
+ cursor.close();
+ }
+ } else {
+ throw new IllegalStateException("bad type, " + mType);
+ }
+
+ if (mExpectedCount != null && mExpectedCount != numRows) {
+ throw new OperationApplicationException("wrong number of rows: " + numRows);
+ }
+
+ return new ContentProviderResult(numRows);
+ }
+
+ /**
+ * The ContentValues back references are represented as a ContentValues object where the
+ * key refers to a column and the value is an index of the back reference whose
+ * valued should be associated with the column.
+ * @param backRefs an array of previous results
+ * @param numBackRefs the number of valid previous results in backRefs
+ * @return the ContentValues that should be used in this operation application after
+ * expansion of back references. This can be called if either mValues or mValuesBackReferences
+ * is null
+ * @VisibleForTesting this is intended to be a private method but it is exposed for
+ * unit testing purposes
+ */
+ public ContentValues resolveValueBackReferences(
+ ContentProviderResult[] backRefs, int numBackRefs) {
+ if (mValuesBackReferences == null) {
+ return mValues;
+ }
+ final ContentValues values;
+ if (mValues == null) {
+ values = new ContentValues();
+ } else {
+ values = new ContentValues(mValues);
+ }
+ for (Map.Entry<String, Object> entry : mValuesBackReferences.valueSet()) {
+ String key = entry.getKey();
+ Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
+ if (backRefIndex == null) {
+ throw new IllegalArgumentException("values backref " + key + " is not an integer");
+ }
+ values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
+ }
+ return values;
+ }
+
+ /**
+ * The Selection Arguments back references are represented as a Map of Integer->Integer where
+ * the key is an index into the selection argument array (see {@link Builder#withSelection})
+ * and the value is the index of the previous result that should be used for that selection
+ * argument array slot.
+ * @param backRefs an array of previous results
+ * @param numBackRefs the number of valid previous results in backRefs
+ * @return the ContentValues that should be used in this operation application after
+ * expansion of back references. This can be called if either mValues or mValuesBackReferences
+ * is null
+ * @VisibleForTesting this is intended to be a private method but it is exposed for
+ * unit testing purposes
+ */
+ public String[] resolveSelectionArgsBackReferences(
+ ContentProviderResult[] backRefs, int numBackRefs) {
+ if (mSelectionArgsBackReferences == null) {
+ return mSelectionArgs;
+ }
+ String[] newArgs = new String[mSelectionArgs.length];
+ System.arraycopy(mSelectionArgs, 0, newArgs, 0, mSelectionArgs.length);
+ for (Map.Entry<Integer, Integer> selectionArgBackRef
+ : mSelectionArgsBackReferences.entrySet()) {
+ final Integer selectionArgIndex = selectionArgBackRef.getKey();
+ final int backRefIndex = selectionArgBackRef.getValue();
+ newArgs[selectionArgIndex] =
+ String.valueOf(backRefToValue(backRefs, numBackRefs, backRefIndex));
+ }
+ return newArgs;
+ }
+
+ /**
+ * Return the string representation of the requested back reference.
+ * @param backRefs an array of results
+ * @param numBackRefs the number of items in the backRefs array that are valid
+ * @param backRefIndex which backRef to be used
+ * @throws ArrayIndexOutOfBoundsException thrown if the backRefIndex is larger than
+ * the numBackRefs
+ * @return the string representation of the requested back reference.
+ */
+ private static long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
+ Integer backRefIndex) {
+ if (backRefIndex >= numBackRefs) {
+ throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
+ + " but there are only " + numBackRefs + " back refs");
+ }
+ ContentProviderResult backRef = backRefs[backRefIndex];
+ long backRefValue;
+ if (backRef.uri != null) {
+ backRefValue = ContentUris.parseId(backRef.uri);
+ } else {
+ backRefValue = backRef.count;
+ }
+ return backRefValue;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ContentProviderOperation> CREATOR =
+ new Creator<ContentProviderOperation>() {
+ public ContentProviderOperation createFromParcel(Parcel source) {
+ return new ContentProviderOperation(source);
+ }
+
+ public ContentProviderOperation[] newArray(int size) {
+ return new ContentProviderOperation[size];
+ }
+ };
+
+
+ /**
+ * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
+ * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
+ * {@link ContentProviderOperation#newUpdate(android.net.Uri)},
+ * {@link ContentProviderOperation#newDelete(android.net.Uri)} or
+ * {@link ContentProviderOperation#newAssertQuery(Uri)}. The withXXX methods
+ * can then be used to add parameters to the builder. See the specific methods to find for
+ * which {@link Builder} type each is allowed. Call {@link #build} to create the
+ * {@link ContentProviderOperation} once all the parameters have been supplied.
+ */
+ public static class Builder {
+ private final int mType;
+ private final Uri mUri;
+ private String mSelection;
+ private String[] mSelectionArgs;
+ private ContentValues mValues;
+ private Integer mExpectedCount;
+ private ContentValues mValuesBackReferences;
+ private Map<Integer, Integer> mSelectionArgsBackReferences;
+
+ /** Create a {@link Builder} of a given type. The uri must not be null. */
+ private Builder(int type, Uri uri) {
+ if (uri == null) {
+ throw new IllegalArgumentException("uri must not be null");
+ }
+ mType = type;
+ mUri = uri;
+ }
+
+ /** Create a ContentProviderOperation from this {@link Builder}. */
+ public ContentProviderOperation build() {
+ if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
+ if ((mValues == null || mValues.size() == 0)
+ && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
+ throw new IllegalArgumentException("Empty values");
+ }
+ }
+ return new ContentProviderOperation(this);
+ }
+
+ /**
+ * Add a {@link ContentValues} of back references. The key is the name of the column
+ * and the value is an integer that is the index of the previous result whose
+ * value should be used for the column. The value is added as a {@link String}.
+ * A column value from the back references takes precedence over a value specified in
+ * {@link #withValues}.
+ * This can only be used with builders of type insert, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReferences(ContentValues backReferences) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts can have value back-references");
+ }
+ mValuesBackReferences = backReferences;
+ return this;
+ }
+
+ /**
+ * Add a ContentValues back reference.
+ * A column value from the back references takes precedence over a value specified in
+ * {@link #withValues}.
+ * This can only be used with builders of type insert, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReference(String key, int previousResult) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts can have value back-references");
+ }
+ if (mValuesBackReferences == null) {
+ mValuesBackReferences = new ContentValues();
+ }
+ mValuesBackReferences.put(key, previousResult);
+ return this;
+ }
+
+ /**
+ * Add a back references as a selection arg. Any value at that index of the selection arg
+ * that was specified by {@link #withSelection} will be overwritten.
+ * This can only be used with builders of type update, delete, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException("only updates, deletes, and asserts "
+ + "can have selection back-references");
+ }
+ if (mSelectionArgsBackReferences == null) {
+ mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
+ }
+ mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
+ return this;
+ }
+
+ /**
+ * The ContentValues to use. This may be null. These values may be overwritten by
+ * the corresponding value specified by {@link #withValueBackReference} or by
+ * future calls to {@link #withValues} or {@link #withValue}.
+ * This can only be used with builders of type insert, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValues(ContentValues values) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts can have values");
+ }
+ if (mValues == null) {
+ mValues = new ContentValues();
+ }
+ mValues.putAll(values);
+ return this;
+ }
+
+ /**
+ * A value to insert or update. This value may be overwritten by
+ * the corresponding value specified by {@link #withValueBackReference}.
+ * This can only be used with builders of type insert, update, or assert.
+ * @param key the name of this value
+ * @param value the value itself. the type must be acceptable for insertion by
+ * {@link ContentValues#put}
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValue(String key, Object value) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException("only inserts and updates can have values");
+ }
+ if (mValues == null) {
+ mValues = new ContentValues();
+ }
+ if (value == null) {
+ mValues.putNull(key);
+ } else if (value instanceof String) {
+ mValues.put(key, (String) value);
+ } else if (value instanceof Byte) {
+ mValues.put(key, (Byte) value);
+ } else if (value instanceof Short) {
+ mValues.put(key, (Short) value);
+ } else if (value instanceof Integer) {
+ mValues.put(key, (Integer) value);
+ } else if (value instanceof Long) {
+ mValues.put(key, (Long) value);
+ } else if (value instanceof Float) {
+ mValues.put(key, (Float) value);
+ } else if (value instanceof Double) {
+ mValues.put(key, (Double) value);
+ } else if (value instanceof Boolean) {
+ mValues.put(key, (Boolean) value);
+ } else if (value instanceof byte[]) {
+ mValues.put(key, (byte[]) value);
+ } else {
+ throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
+ }
+ return this;
+ }
+
+ /**
+ * The selection and arguments to use. An occurrence of '?' in the selection will be
+ * replaced with the corresponding occurence of the selection argument. Any of the
+ * selection arguments may be overwritten by a selection argument back reference as
+ * specified by {@link #withSelectionBackReference}.
+ * This can only be used with builders of type update, delete, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelection(String selection, String[] selectionArgs) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only updates, deletes, and asserts can have selections");
+ }
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ return this;
+ }
+
+ /**
+ * If set then if the number of rows affected by this operation do not match
+ * this count {@link OperationApplicationException} will be throw.
+ * This can only be used with builders of type update, delete, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withExpectedCount(int count) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only updates, deletes, and asserts can have expected counts");
+ }
+ mExpectedCount = count;
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
new file mode 100644
index 0000000..5d188ef
--- /dev/null
+++ b/core/java/android/content/ContentProviderResult.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.net.Uri;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed
+ * to have exactly one of {@link #uri} or {@link #count} set.
+ */
+public class ContentProviderResult implements Parcelable {
+ public final Uri uri;
+ public final Integer count;
+
+ public ContentProviderResult(Uri uri) {
+ if (uri == null) throw new IllegalArgumentException("uri must not be null");
+ this.uri = uri;
+ this.count = null;
+ }
+
+ public ContentProviderResult(int count) {
+ this.count = count;
+ this.uri = null;
+ }
+
+ public ContentProviderResult(Parcel source) {
+ int type = source.readInt();
+ if (type == 1) {
+ count = source.readInt();
+ uri = null;
+ } else {
+ count = null;
+ uri = Uri.CREATOR.createFromParcel(source);
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (uri == null) {
+ dest.writeInt(1);
+ dest.writeInt(count);
+ } else {
+ dest.writeInt(2);
+ uri.writeToParcel(dest, 0);
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ContentProviderResult> CREATOR =
+ new Creator<ContentProviderResult>() {
+ public ContentProviderResult createFromParcel(Parcel source) {
+ return new ContentProviderResult(source);
+ }
+
+ public ContentProviderResult[] newArray(int size) {
+ return new ContentProviderResult[size];
+ }
+ };
+
+ public String toString() {
+ if (uri != null) {
+ return "ContentProviderResult(uri=" + uri.toString() + ")";
+ }
+ return "ContentProviderResult(count=" + count + ")";
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 74144fc..bf1a442 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -30,6 +30,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
+import android.accounts.Account;
import android.util.Config;
import android.util.Log;
@@ -40,15 +41,25 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import java.util.ArrayList;
/**
* This class provides applications access to the content model.
*/
public abstract class ContentResolver {
- public final static String SYNC_EXTRAS_ACCOUNT = "account";
+ /**
+ * @deprecated instead use
+ * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
+ */
+ public static final String SYNC_EXTRAS_ACCOUNT = "account";
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
+ /**
+ * @deprecated instead use
+ * {@link #SYNC_EXTRAS_MANUAL}
+ */
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";
@@ -88,7 +99,35 @@
* in the cursor is the same.
*/
public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
-
+
+ /** @hide */
+ public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
+ /** @hide */
+ public static final int SYNC_ERROR_AUTHENTICATION = 2;
+ /** @hide */
+ public static final int SYNC_ERROR_IO = 3;
+ /** @hide */
+ public static final int SYNC_ERROR_PARSE = 4;
+ /** @hide */
+ public static final int SYNC_ERROR_CONFLICT = 5;
+ /** @hide */
+ public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
+ /** @hide */
+ public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
+ /** @hide */
+ public static final int SYNC_ERROR_INTERNAL = 8;
+
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
+
public ContentResolver(Context context) {
mContext = context;
}
@@ -166,6 +205,87 @@
}
/**
+ * EntityIterator wrapper that releases the associated ContentProviderClient when the
+ * iterator is closed.
+ */
+ private class EntityIteratorWrapper implements EntityIterator {
+ private final EntityIterator mInner;
+ private final ContentProviderClient mClient;
+ private volatile boolean mClientReleased;
+
+ EntityIteratorWrapper(EntityIterator inner, ContentProviderClient client) {
+ mInner = inner;
+ mClient = client;
+ mClientReleased = false;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ return mInner.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ return mInner.next();
+ }
+
+ public void close() {
+ mClient.release();
+ mInner.close();
+ mClientReleased = true;
+ }
+
+ protected void finalize() throws Throwable {
+ if (!mClientReleased) {
+ mClient.release();
+ }
+ super.finalize();
+ }
+ }
+
+ /**
+ * Query the given URI, returning an {@link EntityIterator} over the result set.
+ *
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @return An EntityIterator object
+ * @throws RemoteException thrown if a RemoteException is encountered while attempting
+ * to communicate with a remote provider.
+ * @throws IllegalArgumentException thrown if there is no provider that matches the uri
+ */
+ public final EntityIterator queryEntities(Uri uri,
+ String selection, String[] selectionArgs, String sortOrder) throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ EntityIterator entityIterator =
+ provider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ return new EntityIteratorWrapper(entityIterator, provider);
+ } catch(RuntimeException e) {
+ provider.release();
+ throw e;
+ } catch(RemoteException e) {
+ provider.release();
+ throw e;
+ }
+ }
+
+ /**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
*
@@ -485,6 +605,36 @@
}
/**
+ * Applies each of the {@link ContentProviderOperation} objects and returns an array
+ * of their results. Passes through OperationApplicationException, which may be thrown
+ * by the call to {@link ContentProviderOperation#apply}.
+ * If all the applications succeed then a {@link ContentProviderResult} array with the
+ * same number of elements as the operations will be returned. It is implementation-specific
+ * how many, if any, operations will have been successfully applied if a call to
+ * apply results in a {@link OperationApplicationException}.
+ * @param authority the authority of the ContentProvider to which this batch should be applied
+ * @param operations the operations to apply
+ * @return the results of the applications
+ * @throws OperationApplicationException thrown if an application fails.
+ * See {@link ContentProviderOperation#apply} for more information.
+ * @throws RemoteException thrown if a RemoteException is encountered while attempting
+ * to communicate with a remote provider.
+ */
+ public ContentProviderResult[] applyBatch(String authority,
+ ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ ContentProviderClient provider = acquireContentProviderClient(authority);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown authority " + authority);
+ }
+ try {
+ return provider.applyBatch(operations);
+ } finally {
+ provider.release();
+ }
+ }
+
+ /**
* Inserts multiple rows into a table at the given URL.
*
* This function make no guarantees about the atomicity of the insertions.
@@ -592,6 +742,46 @@
}
/**
+ * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * that services the content at uri, starting the provider if necessary. Returns
+ * null if there is no provider associated wih the uri. The caller must indicate that they are
+ * done with the provider by calling {@link ContentProviderClient#release} which will allow
+ * the system to release the provider it it determines that there is no other reason for
+ * keeping it active.
+ * @param uri specifies which provider should be acquired
+ * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * that services the content at uri or null if there isn't one.
+ */
+ public final ContentProviderClient acquireContentProviderClient(Uri uri) {
+ IContentProvider provider = acquireProvider(uri);
+ if (provider != null) {
+ return new ContentProviderClient(this, provider);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * with the authority of name, starting the provider if necessary. Returns
+ * null if there is no provider associated wih the uri. The caller must indicate that they are
+ * done with the provider by calling {@link ContentProviderClient#release} which will allow
+ * the system to release the provider it it determines that there is no other reason for
+ * keeping it active.
+ * @param name specifies which provider should be acquired
+ * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * with the authority of name or null if there isn't one.
+ */
+ public final ContentProviderClient acquireContentProviderClient(String name) {
+ IContentProvider provider = acquireProvider(name);
+ if (provider != null) {
+ return new ContentProviderClient(this, provider);
+ }
+
+ return null;
+ }
+
+ /**
* Register an observer class that gets callbacks when data identified by a
* given content URI changes.
*
@@ -676,11 +866,42 @@
*
* @param uri the uri of the provider to sync or null to sync all providers.
* @param extras any extras to pass to the SyncAdapter.
+ * @deprecated instead use
+ * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
*/
public void startSync(Uri uri, Bundle extras) {
+ Account account = null;
+ if (extras != null) {
+ String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
+ if (!TextUtils.isEmpty(accountName)) {
+ account = new Account(accountName, "com.google.GAIA");
+ }
+ extras.remove(SYNC_EXTRAS_ACCOUNT);
+ }
+ requestSync(account, uri != null ? uri.getAuthority() : null, extras);
+ }
+
+ /**
+ * Start an asynchronous sync operation. If you want to monitor the progress
+ * of the sync you may register a SyncObserver. Only values of the following
+ * types may be used in the extras bundle:
+ * <ul>
+ * <li>Integer</li>
+ * <li>Long</li>
+ * <li>Boolean</li>
+ * <li>Float</li>
+ * <li>Double</li>
+ * <li>String</li>
+ * </ul>
+ *
+ * @param account which account should be synced
+ * @param authority which authority should be synced
+ * @param extras any extras to pass to the SyncAdapter.
+ */
+ public static void requestSync(Account account, String authority, Bundle extras) {
validateSyncExtrasBundle(extras);
try {
- getContentService().startSync(uri, extras);
+ getContentService().requestSync(account, authority, extras);
} catch (RemoteException e) {
}
}
@@ -694,6 +915,7 @@
* <li>Float</li>
* <li>Double</li>
* <li>String</li>
+ * <li>Account</li>
* <li>null</li>
* </ul>
* @param extras the Bundle to check
@@ -709,6 +931,7 @@
if (value instanceof Float) continue;
if (value instanceof Double) continue;
if (value instanceof String) continue;
+ if (value instanceof Account) continue;
throw new IllegalArgumentException("unexpected value type: "
+ value.getClass().getName());
}
@@ -719,13 +942,211 @@
}
}
+ /**
+ * Cancel any active or pending syncs that match the Uri. If the uri is null then
+ * all syncs will be canceled.
+ *
+ * @param uri the uri of the provider to sync or null to sync all providers.
+ * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
+ */
public void cancelSync(Uri uri) {
+ cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
+ }
+
+ /**
+ * Cancel any active or pending syncs that match account and authority. The account and
+ * authority can each independently be set to null, which means that syncs with any account
+ * or authority, respectively, will match.
+ *
+ * @param account filters the syncs that match by this account
+ * @param authority filters the syncs that match by this authority
+ */
+ public static void cancelSync(Account account, String authority) {
try {
- getContentService().cancelSync(uri);
+ getContentService().cancelSync(account, authority);
} catch (RemoteException e) {
}
}
+ /**
+ * Get information about the SyncAdapters that are known to the system.
+ * @return an array of SyncAdapters that have registered with the system
+ */
+ public static SyncAdapterType[] getSyncAdapterTypes() {
+ try {
+ return getContentService().getSyncAdapterTypes();
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Check if the provider should be synced when a network tickle is received
+ *
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose setting we are querying
+ * @return true if the provider should be synced when a network tickle is received
+ */
+ public static boolean getSyncAutomatically(Account account, String authority) {
+ try {
+ return getContentService().getSyncAutomatically(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Set whether or not the provider is synced when it receives a network tickle.
+ *
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being controlled
+ * @param sync true if the provider should be synced when tickles are received for it
+ */
+ public static void setSyncAutomatically(Account account, String authority, boolean sync) {
+ try {
+ getContentService().setSyncAutomatically(account, authority, sync);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @return the master auto-sync setting that applies to all the providers and accounts
+ */
+ public static boolean getMasterSyncAutomatically() {
+ try {
+ return getContentService().getMasterSyncAutomatically();
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Sets 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.
+ *
+ * @param sync the master auto-sync setting that applies to all the providers and accounts
+ */
+ public static void setMasterSyncAutomatically(boolean sync) {
+ try {
+ getContentService().setMasterSyncAutomatically(sync);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
+ * Returns true if there is currently a sync operation for the given
+ * account or authority in the pending list, or actively being processed.
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being queried
+ * @return true if a sync is active for the given account or authority.
+ */
+ public static boolean isSyncActive(Account account, String authority) {
+ try {
+ return getContentService().isSyncActive(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * If a sync is active returns the information about it, otherwise returns false.
+ * @return the ActiveSyncInfo for the currently active sync or null if one is not active.
+ * @hide
+ */
+ public static ActiveSyncInfo getActiveSync() {
+ try {
+ return getContentService().getActiveSync();
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Returns the status that matches the authority. If there are multiples accounts for
+ * the authority, the one with the latest "lastSuccessTime" status is returned.
+ * @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
+ * @hide
+ */
+ public static SyncStatusInfo getSyncStatus(Account account, String authority) {
+ try {
+ return getContentService().getSyncStatus(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Return true if the pending status is true of any matching authorities.
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being queried
+ * @return true if there is a pending sync with the matching account and authority
+ */
+ public static boolean isSyncPending(Account account, String authority) {
+ try {
+ return getContentService().isSyncPending(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
+ try {
+ ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
+ public void onStatusChanged(int which) throws RemoteException {
+ callback.onStatusChanged(which);
+ }
+ };
+ getContentService().addStatusChangeListener(mask, observer);
+ return observer;
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ public static void removeStatusChangeListener(Object handle) {
+ try {
+ getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+
private final class CursorWrapperInner extends CursorWrapper {
private IContentProvider mContentProvider;
public static final String TAG="CursorWrapperInner";
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 6cd2c54..c4d8aaf 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -160,7 +161,9 @@
}
if (syncToNetwork) {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) syncManager.scheduleLocalSync(uri);
+ if (syncManager != null) {
+ syncManager.scheduleLocalSync(null /* all accounts */, uri.getAuthority());
+ }
}
} finally {
restoreCallingIdentity(identityToken);
@@ -186,14 +189,16 @@
}
}
- public void startSync(Uri url, Bundle extras) {
+ public void requestSync(Account account, String authority, Bundle extras) {
ContentResolver.validateSyncExtrasBundle(extras);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) syncManager.startSync(url, extras);
+ if (syncManager != null) {
+ syncManager.scheduleSync(account, authority, extras, 0 /* no delay */);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -201,34 +206,50 @@
/**
* Clear all scheduled sync operations that match the uri and cancel the active sync
- * if it matches the uri. If the uri is null, clear all scheduled syncs and cancel
- * the active one, if there is one.
- * @param uri Filter on the sync operations to cancel, or all if null.
+ * if they match the authority and account, if they are present.
+ * @param account filter the pending and active syncs to cancel using this account
+ * @param authority filter the pending and active syncs to cancel using this authority
*/
- public void cancelSync(Uri uri) {
+ public void cancelSync(Account account, String authority) {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.clearScheduledSyncOperations(uri);
- syncManager.cancelActiveSync(uri);
+ syncManager.clearScheduledSyncOperations(account, authority);
+ syncManager.cancelActiveSync(account, authority);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- public boolean getSyncProviderAutomatically(String providerName) {
+ /**
+ * Get information about the SyncAdapters that are known to the system.
+ * @return an array of SyncAdapters that have registered with the system
+ */
+ public SyncAdapterType[] getSyncAdapterTypes() {
+ // This makes it so that future permission checks will be in the context of this
+ // process rather than the caller's process. We will restore this before returning.
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ return syncManager.getSyncAdapterTypes();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public boolean getSyncAutomatically(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().getSyncProviderAutomatically(
- null, providerName);
+ return syncManager.getSyncStorageEngine().getSyncAutomatically(
+ account, providerName);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -236,29 +257,60 @@
return false;
}
- public void setSyncProviderAutomatically(String providerName, boolean sync) {
+ public void setSyncAutomatically(Account account, String providerName, boolean sync) {
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().setSyncProviderAutomatically(
- null, providerName, sync);
+ syncManager.getSyncStorageEngine().setSyncAutomatically(
+ account, providerName, sync);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- public boolean getListenForNetworkTickles() {
+ 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().getListenForNetworkTickles();
+ 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");
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ return syncManager.getSyncStorageEngine().getMasterSyncAutomatically();
}
} finally {
restoreCallingIdentity(identityToken);
@@ -266,21 +318,21 @@
return false;
}
- public void setListenForNetworkTickles(boolean flag) {
+ public void setMasterSyncAutomatically(boolean flag) {
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().setListenForNetworkTickles(flag);
+ syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- public boolean isSyncActive(String account, String authority) {
+ public boolean isSyncActive(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
@@ -311,7 +363,7 @@
return null;
}
- public SyncStatusInfo getStatusByAuthority(String authority) {
+ public SyncStatusInfo getSyncStatus(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
@@ -327,15 +379,14 @@
return null;
}
- public boolean isAuthorityPending(String account, String authority) {
+ public boolean isSyncPending(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().isAuthorityPending(
- account, authority);
+ return syncManager.getSyncStorageEngine().isSyncPending(account, authority);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -348,8 +399,7 @@
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().addStatusChangeListener(
- mask, callback);
+ syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -361,8 +411,7 @@
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().removeStatusChangeListener(
- callback);
+ syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 25b5de3..8ab67c5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -488,89 +488,44 @@
public abstract String[] databaseList();
/**
- * Like {@link #peekWallpaper}, but always returns a valid Drawable. If
- * no wallpaper is set, the system default wallpaper is returned.
- *
- * @return Returns a Drawable object that will draw the wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#getDrawable
+ * WallpaperManager.get()} instead.
*/
public abstract Drawable getWallpaper();
/**
- * Retrieve the current system wallpaper. This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set. If there is no wallpaper set,
- * a null pointer is returned.
- *
- * @return Returns a Drawable object that will draw the wallpaper or a
- * null pointer if these is none.
+ * @deprecated Use {@link android.app.WallpaperManager#peekDrawable
+ * WallpaperManager.peek()} instead.
*/
public abstract Drawable peekWallpaper();
/**
- * Returns the desired minimum width for the wallpaper. Callers of
- * {@link #setWallpaper(android.graphics.Bitmap)} or
- * {@link #setWallpaper(java.io.InputStream)} should check this value
- * beforehand to make sure the supplied wallpaper respects the desired
- * minimum width.
- *
- * If the returned value is <= 0, the caller should use the width of
- * the default display instead.
- *
- * @return The desired minimum width for the wallpaper. This value should
- * be honored by applications that set the wallpaper but it is not
- * mandatory.
+ * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumWidth()
+ * WallpaperManager.getDesiredMinimumWidth()} instead.
*/
public abstract int getWallpaperDesiredMinimumWidth();
/**
- * Returns the desired minimum height for the wallpaper. Callers of
- * {@link #setWallpaper(android.graphics.Bitmap)} or
- * {@link #setWallpaper(java.io.InputStream)} should check this value
- * beforehand to make sure the supplied wallpaper respects the desired
- * minimum height.
- *
- * If the returned value is <= 0, the caller should use the height of
- * the default display instead.
- *
- * @return The desired minimum height for the wallpaper. This value should
- * be honored by applications that set the wallpaper but it is not
- * mandatory.
+ * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumHeight()
+ * WallpaperManager.getDesiredMinimumHeight()} instead.
*/
public abstract int getWallpaperDesiredMinimumHeight();
/**
- * Change the current system wallpaper to a bitmap. The given bitmap is
- * converted to a PNG and stored as the wallpaper. On success, the intent
- * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
- *
- * @param bitmap The bitmap to save.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#setBitmap(Bitmap)
+ * WallpaperManager.set()} instead.
*/
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
/**
- * Change the current system wallpaper to a specific byte stream. The
- * give InputStream is copied into persistent storage and will now be
- * used as the wallpaper. Currently it must be either a JPEG or PNG
- * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
- * is broadcast.
- *
- * @param data A stream containing the raw data to install as a wallpaper.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#setStream(InputStream)
+ * WallpaperManager.set()} instead.
*/
public abstract void setWallpaper(InputStream data) throws IOException;
/**
- * Remove any currently set wallpaper, reverting to the system's default
- * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
- * is broadcast.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#clear
+ * WallpaperManager.clear()} instead.
*/
public abstract void clearWallpaper() throws IOException;
@@ -1110,6 +1065,16 @@
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.accounts.AccountManager} for receiving intents at a
+ * time of your choosing.
+ * TODO STOPSHIP perform a final review of the the account apis before shipping
+ *
+ * @see #getSystemService
+ * @see android.accounts.AccountManager
+ */
+ public static final String ACCOUNT_SERVICE = "account";
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.app.ActivityManager} for interacting with the global
* system state.
*
@@ -1179,10 +1144,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
+ * @see android.bluetooth.BluetoothAdapter
* @hide
*/
public static final String BLUETOOTH_SERVICE = "bluetooth";
diff --git a/core/java/android/content/Entity.aidl b/core/java/android/content/Entity.aidl
new file mode 100644
index 0000000..fb201f3
--- /dev/null
+++ b/core/java/android/content/Entity.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Entity.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content;
+
+parcelable Entity;
diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java
new file mode 100644
index 0000000..325dce5
--- /dev/null
+++ b/core/java/android/content/Entity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Objects that pass through the ContentProvider and ContentResolver's methods that deal with
+ * Entities must implement this abstract base class and thus themselves be Parcelable.
+ */
+public final class Entity implements Parcelable {
+ final private ContentValues mValues;
+ final private ArrayList<NamedContentValues> mSubValues;
+
+ public Entity(ContentValues values) {
+ mValues = values;
+ mSubValues = new ArrayList<NamedContentValues>();
+ }
+
+ public ContentValues getEntityValues() {
+ return mValues;
+ }
+
+ public ArrayList<NamedContentValues> getSubValues() {
+ return mSubValues;
+ }
+
+ public void addSubValue(Uri uri, ContentValues values) {
+ mSubValues.add(new Entity.NamedContentValues(uri, values));
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ mValues.writeToParcel(dest, 0);
+ dest.writeInt(mSubValues.size());
+ for (NamedContentValues value : mSubValues) {
+ value.uri.writeToParcel(dest, 0);
+ value.values.writeToParcel(dest, 0);
+ }
+ }
+
+ private Entity(Parcel source) {
+ mValues = ContentValues.CREATOR.createFromParcel(source);
+ final int numValues = source.readInt();
+ mSubValues = new ArrayList<NamedContentValues>(numValues);
+ for (int i = 0; i < numValues; i++) {
+ final Uri uri = Uri.CREATOR.createFromParcel(source);
+ final ContentValues values = ContentValues.CREATOR.createFromParcel(source);
+ mSubValues.add(new NamedContentValues(uri, values));
+ }
+ }
+
+ public static final Creator<Entity> CREATOR = new Creator<Entity>() {
+ public Entity createFromParcel(Parcel source) {
+ return new Entity(source);
+ }
+
+ public Entity[] newArray(int size) {
+ return new Entity[size];
+ }
+ };
+
+ public static class NamedContentValues {
+ public final Uri uri;
+ public final ContentValues values;
+
+ public NamedContentValues(Uri uri, ContentValues values) {
+ this.uri = uri;
+ this.values = values;
+ }
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Entity: ").append(getEntityValues());
+ for (Entity.NamedContentValues namedValue : getSubValues()) {
+ sb.append("\n ").append(namedValue.uri);
+ sb.append("\n -> ").append(namedValue.values);
+ }
+ return sb.toString();
+ }
+}
diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java
new file mode 100644
index 0000000..5e5f14c
--- /dev/null
+++ b/core/java/android/content/EntityIterator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.RemoteException;
+
+public interface EntityIterator {
+ /**
+ * Returns whether there are more elements to iterate, i.e. whether the
+ * iterator is positioned in front of an element.
+ *
+ * @return {@code true} if there are more elements, {@code false} otherwise.
+ * @see #next
+ * @since Android 1.0
+ */
+ public boolean hasNext() throws RemoteException;
+
+ /**
+ * Returns the next object in the iteration, i.e. returns the element in
+ * front of the iterator and advances the iterator by one position.
+ *
+ * @return the next object.
+ * @throws java.util.NoSuchElementException
+ * if there are no more elements.
+ * @see #hasNext
+ * @since Android 1.0
+ */
+ public Entity next() throws RemoteException;
+
+ /**
+ * Indicates that this iterator is no longer needed and that any associated resources
+ * may be released (such as a SQLite cursor).
+ */
+ public void close();
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 0606956..7e5aba5 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -28,6 +28,7 @@
import android.os.ParcelFileDescriptor;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* The ipc interface to talk to a content provider.
@@ -43,19 +44,25 @@
CursorWindow window) throws RemoteException;
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException;
+ public EntityIterator queryEntities(Uri url, String selection,
+ String[] selectionArgs, String sortOrder)
+ throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException;
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException;
+ public Uri insertEntity(Uri uri, Entity entities) throws RemoteException;
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException;
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException;
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException;
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
- public ISyncAdapter getSyncAdapter() throws RemoteException;
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException;
/* IPC constants */
static final String descriptor = "android.content.IContentProvider";
@@ -65,8 +72,11 @@
static final int INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2;
static final int DELETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3;
static final int UPDATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 9;
- static final int GET_SYNC_ADAPTER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10;
static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12;
static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13;
static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14;
+ static final int INSERT_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 16;
+ static final int UPDATE_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 17;
+ static final int QUERY_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 18;
+ static final int APPLY_BATCH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 19;
}
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 8617d949..b0f14c1 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -16,8 +16,10 @@
package android.content;
+import android.accounts.Account;
import android.content.ActiveSyncInfo;
import android.content.ISyncStatusObserver;
+import android.content.SyncAdapterType;
import android.content.SyncStatusInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -34,15 +36,15 @@
void notifyChange(in Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork);
- void startSync(in Uri url, in Bundle extras);
- void cancelSync(in Uri uri);
+ void requestSync(in Account account, String authority, in Bundle extras);
+ void cancelSync(in Account account, String authority);
/**
* Check if the provider should be synced when a network tickle is received
* @param providerName the provider whose setting we are querying
* @return true of the provider should be synced when a network tickle is received
*/
- boolean getSyncProviderAutomatically(String providerName);
+ boolean getSyncAutomatically(in Account account, String providerName);
/**
* Set whether or not the provider is synced when it receives a network tickle.
@@ -50,32 +52,50 @@
* @param providerName the provider whose behavior is being controlled
* @param sync true if the provider should be synced when tickles are received for it
*/
- void setSyncProviderAutomatically(String providerName, boolean sync);
+ void setSyncAutomatically(in Account account, String providerName, boolean sync);
- void setListenForNetworkTickles(boolean flag);
+ /**
+ * 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);
- boolean getListenForNetworkTickles();
+ /**
+ * 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();
/**
* Returns true if there is currently a sync operation for the given
* account or authority in the pending list, or actively being processed.
*/
- boolean isSyncActive(String account, String authority);
+ boolean isSyncActive(in Account account, String authority);
ActiveSyncInfo getActiveSync();
/**
+ * Returns the types of the SyncAdapters that are registered with the system.
+ * @return Returns the types of the SyncAdapters that are registered with the system.
+ */
+ SyncAdapterType[] getSyncAdapterTypes();
+
+ /**
* Returns the status that matches the authority. If there are multiples accounts for
* the authority, the one with the latest "lastSuccessTime" status is returned.
* @param authority the authority whose row should be selected
* @return the SyncStatusInfo for the authority, or null if none exists
*/
- SyncStatusInfo getStatusByAuthority(String authority);
+ SyncStatusInfo getSyncStatus(in Account account, String authority);
/**
* Return true if the pending status is true of any matching authorities.
*/
- boolean isAuthorityPending(String account, String authority);
+ boolean isSyncPending(in Account account, String authority);
void addStatusChangeListener(int mask, ISyncStatusObserver callback);
diff --git a/core/java/android/content/IEntityIterator.java b/core/java/android/content/IEntityIterator.java
new file mode 100644
index 0000000..1c478b3
--- /dev/null
+++ b/core/java/android/content/IEntityIterator.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * ICPC interface methods for an iterator over Entity objects.
+ * @hide
+ */
+public interface IEntityIterator extends IInterface {
+ /** Local-side IPC implementation stub class. */
+ public static abstract class Stub extends Binder implements IEntityIterator {
+ private static final String TAG = "IEntityIterator";
+ private static final java.lang.String DESCRIPTOR = "android.content.IEntityIterator";
+
+ /** Construct the stub at attach it to the interface. */
+ public Stub() {
+ this.attachInterface(this, DESCRIPTOR);
+ }
+ /**
+ * Cast an IBinder object into an IEntityIterator interface,
+ * generating a proxy if needed.
+ */
+ public static IEntityIterator asInterface(IBinder obj) {
+ if ((obj==null)) {
+ return null;
+ }
+ IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+ if (((iin!=null)&&(iin instanceof IEntityIterator))) {
+ return ((IEntityIterator)iin);
+ }
+ return new IEntityIterator.Stub.Proxy(obj);
+ }
+
+ public IBinder asBinder() {
+ return this;
+ }
+
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ {
+ reply.writeString(DESCRIPTOR);
+ return true;
+ }
+
+ case TRANSACTION_hasNext:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ boolean _result;
+ try {
+ _result = this.hasNext();
+ } catch (Exception e) {
+ Log.e(TAG, "caught exception in hasNext()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ reply.writeInt(((_result)?(1):(0)));
+ return true;
+ }
+
+ case TRANSACTION_next:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ Entity entity;
+ try {
+ entity = this.next();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in next()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ entity.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ }
+
+ case TRANSACTION_close:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ try {
+ this.close();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in close()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ return true;
+ }
+ }
+ return super.onTransact(code, data, reply, flags);
+ }
+
+ private static class Proxy implements IEntityIterator {
+ private IBinder mRemote;
+ Proxy(IBinder remote) {
+ mRemote = remote;
+ }
+ public IBinder asBinder() {
+ return mRemote;
+ }
+ public java.lang.String getInterfaceDescriptor() {
+ return DESCRIPTOR;
+ }
+ public boolean hasNext() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ boolean _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_hasNext, _data, _reply, 0);
+ _reply.readException();
+ _result = (0!=_reply.readInt());
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public Entity next() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0);
+ _reply.readException();
+ return Entity.CREATOR.createFromParcel(_reply);
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ public void close() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_close, _data, _reply, 0);
+ _reply.readException();
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+ }
+ static final int TRANSACTION_hasNext = (IBinder.FIRST_CALL_TRANSACTION + 0);
+ static final int TRANSACTION_next = (IBinder.FIRST_CALL_TRANSACTION + 1);
+ static final int TRANSACTION_close = (IBinder.FIRST_CALL_TRANSACTION + 2);
+ }
+ public boolean hasNext() throws RemoteException;
+ public Entity next() throws RemoteException;
+ public void close() throws RemoteException;
+}
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 671188c..4660527 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.os.Bundle;
import android.content.ISyncContext;
@@ -30,14 +31,17 @@
*
* @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 authority the authority that should be synced
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- void startSync(ISyncContext syncContext, String account, in Bundle extras);
+ void startSync(ISyncContext syncContext, String authority,
+ in Account account, in Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
* after the ISyncContext.onFinished() for that sync was called.
+ * @param syncContext the ISyncContext that was passed to {@link #startSync}
*/
- void cancelSync();
+ void cancelSync(ISyncContext syncContext);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c62d66b..a3517f8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -75,10 +75,10 @@
* <p>Some examples of action/data pairs are:</p>
*
* <ul>
- * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/1</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/people/1</i></b> -- Display
* information about the person whose identifier is "1".</p>
* </li>
- * <li> <p><b>{@link #ACTION_DIAL} <i>content://contacts/1</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_DIAL} <i>content://contacts/people/1</i></b> -- Display
* the phone dialer with the person filled in.</p>
* </li>
* <li> <p><b>{@link #ACTION_VIEW} <i>tel:123</i></b> -- Display
@@ -89,10 +89,10 @@
* <li> <p><b>{@link #ACTION_DIAL} <i>tel:123</i></b> -- Display
* the phone dialer with the given number filled in.</p>
* </li>
- * <li> <p><b>{@link #ACTION_EDIT} <i>content://contacts/1</i></b> -- Edit
+ * <li> <p><b>{@link #ACTION_EDIT} <i>content://contacts/people/1</i></b> -- Edit
* information about the person whose identifier is "1".</p>
* </li>
- * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/people/</i></b> -- Display
* a list of people, which the user can browse through. This example is a
* typical top-level entry into the Contacts application, showing you the
* list of people. Selecting a particular person to view would result in a
@@ -156,7 +156,7 @@
* defined in the Intent class, but applications can also define their own.
* These strings use java style scoping, to ensure they are unique -- for
* example, the standard {@link #ACTION_VIEW} is called
- * "android.app.action.VIEW".</p>
+ * "android.intent.action.VIEW".</p>
*
* <p>Put together, the set of actions, data types, categories, and extra data
* defines a language for the system allowing for the expression of phrases
@@ -347,7 +347,7 @@
* <li> <p><b>{ action=android.app.action.MAIN,
* category=android.app.category.LAUNCHER }</b> is the actual intent
* used by the Launcher to populate its top-level list.</p>
- * <li> <p><b>{ action=android.app.action.VIEW
+ * <li> <p><b>{ action=android.intent.action.VIEW
* data=content://com.google.provider.NotePad/notes }</b>
* displays a list of all the notes under
* "content://com.google.provider.NotePad/notes", which
@@ -399,7 +399,7 @@
* NoteEditor activity:</p>
*
* <ul>
- * <li> <p><b>{ action=android.app.action.VIEW
+ * <li> <p><b>{ action=android.intent.action.VIEW
* data=content://com.google.provider.NotePad/notes/<var>{ID}</var> }</b>
* shows the user the content of note <var>{ID}</var>.</p>
* <li> <p><b>{ action=android.app.action.EDIT
@@ -1382,7 +1382,7 @@
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
+ public static final String ACTION_POWER_CONNECTED = "android.intent.action.POWER_CONNECTED";
/**
* Broadcast Action: External power has been removed from the device.
* This is intended for applications that wish to register specifically to this notification.
@@ -1394,7 +1394,8 @@
* by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
+ public static final String ACTION_POWER_DISCONNECTED =
+ "android.intent.action.POWER_DISCONNECTED";
/**
* Broadcast Action: Device is shutting down.
* This is broadcast when the device is being shut down (completely turned
@@ -1408,6 +1409,17 @@
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
/**
+ * Activity Action: Start this activity to request system shutdown.
+ * The optional boolean extra field {@link #EXTRA_KEY_CONFIRM} can be set to true
+ * to request confirmation from the user before shutting down.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * {@hide}
+ */
+ public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
+ /**
* Broadcast Action: Indicates low memory condition on the device
*
* <p class="note">This is a protected intent that can only be sent
@@ -1685,6 +1697,20 @@
"android.intent.action.REBOOT";
+ /**
+ * Broadcast Action: a remote intent is to be broadcasted.
+ *
+ * A remote intent is used for remote RPC between devices. The remote intent
+ * is serialized and sent from one device to another device. The receiving
+ * device parses the remote intent and broadcasts it. Note that anyone can
+ * broadcast a remote intent. However, if the intent receiver of the remote intent
+ * does not trust intent broadcasts from arbitrary intent senders, it should require
+ * the sender to hold certain permissions so only trusted sender's broadcast will be
+ * let through.
+ */
+ public static final String ACTION_REMOTE_INTENT =
+ "android.intent.action.REMOTE_INTENT";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -1812,6 +1838,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.
@@ -1878,6 +1912,14 @@
public static final String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
/**
+ * Set to true in {@link #ACTION_REQUEST_SHUTDOWN} to request confirmation from the user
+ * before shutting down.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_KEY_CONFIRM = "android.intent.extra.KEY_CONFIRM";
+
+ /**
* Used as an boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} or
* {@link android.content.Intent#ACTION_PACKAGE_CHANGED} intents to override the default action
* of restarting the application.
@@ -1926,6 +1968,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#ACTION_DOCK_STATE_UNDOCKED},
+ * {@link android.content.Intent#ACTION_DOCK_STATE_DESK}, or
+ * {@link android.content.Intent#ACTION_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.
*
@@ -1943,6 +2016,13 @@
public static final String EXTRA_INSTALLER_PACKAGE_NAME
= "android.intent.extra.INSTALLER_PACKAGE_NAME";
+ /**
+ * Used in the extra field in the remote intent. It's astring token passed with the
+ * remote intent.
+ */
+ public static final String EXTRA_REMOTE_INTENT_TOKEN =
+ "android.intent.extra.remote_intent_token";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/OperationApplicationException.java b/core/java/android/content/OperationApplicationException.java
new file mode 100644
index 0000000..d4101bf
--- /dev/null
+++ b/core/java/android/content/OperationApplicationException.java
@@ -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.
+ */
+
+package android.content;
+
+/**
+ * Thrown when an application of a {@link ContentProviderOperation} fails due the specified
+ * constraints.
+ */
+public class OperationApplicationException extends Exception {
+ public OperationApplicationException() {
+ super();
+ }
+ public OperationApplicationException(String message) {
+ super(message);
+ }
+ public OperationApplicationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public OperationApplicationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 7826e50..1d5ade1 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
import android.os.RemoteException;
+import android.accounts.Account;
/**
* @hide
@@ -29,12 +30,12 @@
public static final int LOG_SYNC_DETAILS = 2743;
class Transport extends ISyncAdapter.Stub {
- public void startSync(ISyncContext syncContext, String account,
+ public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) throws RemoteException {
SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
}
- public void cancelSync() throws RemoteException {
+ public void cancelSync(ISyncContext syncContext) throws RemoteException {
SyncAdapter.this.cancelSync();
}
}
@@ -42,9 +43,9 @@
Transport mTransport = new Transport();
/**
- * Get the Transport object. (note this is package private).
+ * Get the Transport object.
*/
- final ISyncAdapter getISyncAdapter()
+ public final ISyncAdapter getISyncAdapter()
{
return mTransport;
}
@@ -59,7 +60,7 @@
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- public abstract void startSync(SyncContext syncContext, String account, Bundle extras);
+ public abstract void startSync(SyncContext syncContext, Account account, Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncAdapterType.aidl b/core/java/android/content/SyncAdapterType.aidl
new file mode 100644
index 0000000..e67841f
--- /dev/null
+++ b/core/java/android/content/SyncAdapterType.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+parcelable SyncAdapterType;
+
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
new file mode 100644
index 0000000..d3f8230
--- /dev/null
+++ b/core/java/android/content/SyncAdapterType.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.text.TextUtils;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Value type that represents a SyncAdapterType. This object overrides {@link #equals} and
+ * {@link #hashCode}, making it suitable for use as the key of a {@link java.util.Map}
+ */
+public class SyncAdapterType implements Parcelable {
+ public final String authority;
+ public final String accountType;
+ public final boolean isUserFacing = true; // TODO: implement logic to set this
+
+ public 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;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof SyncAdapterType)) return false;
+ final SyncAdapterType other = (SyncAdapterType)o;
+ return authority.equals(other.authority) && accountType.equals(other.accountType);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + authority.hashCode();
+ result = 31 * result + accountType.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}";
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(authority);
+ dest.writeString(accountType);
+ }
+
+ public SyncAdapterType(Parcel source) {
+ this(source.readString(), source.readString());
+ }
+
+ public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() {
+ public SyncAdapterType createFromParcel(Parcel source) {
+ return new SyncAdapterType(source);
+ }
+
+ public SyncAdapterType[] newArray(int size) {
+ return new SyncAdapterType[size];
+ }
+ };
+}
\ No newline at end of file
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
new file mode 100644
index 0000000..ce47d76
--- /dev/null
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.content.pm.RegisteredServicesCache;
+import android.content.res.TypedArray;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * A cache of services that export the {@link android.content.ISyncAdapter} interface.
+ * @hide
+ */
+/* package private */ class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType> {
+ private static final String TAG = "Account";
+
+ private static final String SERVICE_INTERFACE = "android.content.SyncAdapter";
+ private static final String SERVICE_META_DATA = "android.content.SyncAdapter";
+ private static final String ATTRIBUTES_NAME = "sync-adapter";
+
+ SyncAdaptersCache(Context context) {
+ super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME);
+ }
+
+ public SyncAdapterType parseServiceAttributes(String packageName, AttributeSet attrs) {
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.SyncAdapter);
+ try {
+ final String authority =
+ sa.getString(com.android.internal.R.styleable.SyncAdapter_contentAuthority);
+ final String accountType =
+ sa.getString(com.android.internal.R.styleable.SyncAdapter_accountType);
+ if (authority == null || accountType == null) {
+ return null;
+ }
+ return new SyncAdapterType(authority, accountType);
+ } finally {
+ sa.recycle();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4d2cce8..f50fd74 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -21,8 +21,9 @@
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -30,11 +31,10 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.RegisteredServicesCache;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -48,7 +48,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Config;
@@ -72,11 +71,12 @@
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Random;
+import java.util.Collection;
/**
* @hide
*/
-class SyncManager {
+class SyncManager implements OnAccountsUpdatedListener {
private static final String TAG = "SyncManager";
// used during dumping of the Sync history
@@ -117,14 +117,11 @@
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
private Context mContext;
- private ContentResolver mContentResolver;
private String mStatusText = "";
private long mHeartbeatTime = 0;
- private AccountMonitor mAccountMonitor;
-
- private volatile String[] mAccounts = null;
+ private volatile Account[] mAccounts = null;
volatile private PowerManager.WakeLock mSyncWakeLock;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
@@ -151,17 +148,18 @@
private final PendingIntent mSyncAlarmIntent;
private final PendingIntent mSyncPollAlarmIntent;
+ private final SyncAdaptersCache mSyncAdapters;
+
private BroadcastReceiver mStorageIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- ensureContentResolver();
String action = intent.getAction();
if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Internal storage is low.");
}
mStorageIsLow = true;
- cancelActiveSync(null /* no url */);
+ cancelActiveSync(null /* any account */, null /* any authority */);
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Internal storage is ok.");
@@ -172,6 +170,43 @@
}
};
+ private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (!mFactoryTest) {
+ AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,
+ mSyncHandler, true /* updateImmediately */);
+ }
+ }
+ };
+
+ public void onAccountsUpdated(Account[] accounts) {
+ final boolean hadAccountsAlready = mAccounts != null;
+ mAccounts = accounts;
+
+ // if a sync is in progress yet it is no longer in the accounts list,
+ // cancel it
+ ActiveSyncContext activeSyncContext = mActiveSyncContext;
+ if (activeSyncContext != null) {
+ if (!ArrayUtils.contains(accounts, activeSyncContext.mSyncOperation.account)) {
+ Log.d(TAG, "canceling sync since the account has been removed");
+ sendSyncFinishedOrCanceledMessage(activeSyncContext,
+ null /* no result since this is a cancel */);
+ }
+ }
+
+ // we must do this since we don't bother scheduling alarms when
+ // the accounts are not set yet
+ sendCheckAlarmsMessage();
+
+ 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 */);
+ }
+ }
+
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -229,7 +264,11 @@
private static final String SYNCMANAGER_PREFS_FILENAME = "/data/system/syncmanager.prefs";
+ private final boolean mFactoryTest;
+
public SyncManager(Context context, boolean factoryTest) {
+ mFactoryTest = factoryTest;
+
// Initialize the SyncStorageEngine first, before registering observers
// and creating threads and so on; it may fail if the disk is full.
SyncStorageEngine.init(context);
@@ -244,6 +283,8 @@
mPackageManager = null;
+ mSyncAdapters = new SyncAdaptersCache(mContext);
+
mSyncAlarmIntent = PendingIntent.getBroadcast(
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
@@ -253,6 +294,9 @@
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
+ intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ context.registerReceiver(mBootCompletedReceiver, intentFilter);
+
intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
context.registerReceiver(mStorageIntentReceiver, intentFilter);
@@ -282,48 +326,12 @@
mHandleAlarmWakeLock.setReferenceCounted(false);
mSyncStorageEngine.addStatusChangeListener(
- SyncStorageEngine.CHANGE_SETTINGS, new ISyncStatusObserver.Stub() {
+ ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
public void onStatusChanged(int which) {
// force the sync loop to run if the settings change
sendCheckAlarmsMessage();
}
});
-
- if (!factoryTest) {
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- final boolean hadAccountsAlready = mAccounts != null;
- // copy the accounts into a new array and change mAccounts to point to it
- String[] newAccounts = new String[accounts.length];
- System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
- mAccounts = newAccounts;
-
- // if a sync is in progress yet it is no longer in the accounts list, cancel it
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
- if (activeSyncContext != null) {
- if (!ArrayUtils.contains(newAccounts,
- activeSyncContext.mSyncOperation.account)) {
- Log.d(TAG, "canceling sync since the account has been removed");
- sendSyncFinishedOrCanceledMessage(activeSyncContext,
- null /* no result since this is a cancel */);
- }
- }
-
- // we must do this since we don't bother scheduling alarms when
- // the accounts are not set yet
- sendCheckAlarmsMessage();
-
- mSyncStorageEngine.doDatabaseCleanup(accounts);
-
- if (hadAccountsAlready && mAccounts.length > 0) {
- // request a sync so that if the password was changed we will retry any sync
- // that failed when it was wrong
- startSync(null /* all providers */, null /* no extras */);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(context, listener);
- }
}
private synchronized void initializeSyncPoll() {
@@ -397,7 +405,8 @@
scheduleSyncPollAlarm(nextRelativePollTimeMs);
// perform a poll
- scheduleSync(null /* sync all syncable providers */, new Bundle(), 0 /* no delay */);
+ scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */,
+ new Bundle(), 0 /* no delay */);
}
private void writeSyncPollTime(long when) {
@@ -452,19 +461,13 @@
return mSyncStorageEngine;
}
- private void ensureContentResolver() {
- if (mContentResolver == null) {
- mContentResolver = mContext.getContentResolver();
- }
- }
-
private void ensureAlarmService() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
}
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
ActiveSyncContext activeSyncContext = mActiveSyncContext;
return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
}
@@ -499,20 +502,21 @@
*
* <p>You'll start getting callbacks after this.
*
- * @param url The Uri of a specific provider to be synced, or
- * null to sync all providers.
+ * @param requestedAccount the account to sync, may be null to signify all accounts
+ * @param requestedAuthority the authority to sync, may be null to indicate all authorities
* @param extras a Map of SyncAdapter-specific information to control
* 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
- * sync. -1 means to make this the next sync to perform.
*/
- public void scheduleSync(Uri url, Bundle extras, long delay) {
+ public void scheduleSync(Account requestedAccount, String requestedAuthority,
+ Bundle extras, long delay) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) {
Log.v(TAG, "scheduleSync:"
+ " delay " + delay
- + ", url " + ((url == null) ? "(null)" : url)
+ + ", account " + requestedAccount
+ + ", authority " + requestedAuthority
+ ", extras " + ((extras == null) ? "(null)" : extras));
}
@@ -535,10 +539,9 @@
delay = -1; // this means schedule at the front of the queue
}
- String[] accounts;
- String accountFromExtras = extras.getString(ContentResolver.SYNC_EXTRAS_ACCOUNT);
- if (!TextUtils.isEmpty(accountFromExtras)) {
- accounts = new String[]{accountFromExtras};
+ Account[] accounts;
+ if (requestedAccount != null) {
+ accounts = new Account[]{requestedAccount};
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
@@ -560,14 +563,14 @@
}
final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
- final boolean force = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
+ final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
int source;
if (uploadOnly) {
source = SyncStorageEngine.SOURCE_LOCAL;
- } else if (force) {
+ } else if (manualSync) {
source = SyncStorageEngine.SOURCE_USER;
- } else if (url == null) {
+ } else if (requestedAuthority == null) {
source = SyncStorageEngine.SOURCE_POLL;
} else {
// this isn't strictly server, since arbitrary callers can (and do) request
@@ -575,20 +578,32 @@
source = SyncStorageEngine.SOURCE_SERVER;
}
- List<String> names = new ArrayList<String>();
- List<ProviderInfo> providers = new ArrayList<ProviderInfo>();
- populateProvidersList(url, names, providers);
+ // Compile a list of authorities that have sync adapters.
+ // For each authority sync each account that matches a sync adapter.
+ final HashSet<String> syncableAuthorities = new HashSet<String>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
+ mSyncAdapters.getAllServices()) {
+ syncableAuthorities.add(syncAdapter.type.authority);
+ }
- final int numProviders = providers.size();
- for (int i = 0; i < numProviders; i++) {
- if (!providers.get(i).isSyncable) continue;
- final String name = names.get(i);
- for (String account : accounts) {
- scheduleSyncOperation(new SyncOperation(account, source, name, 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(name)) {
- break;
+ // 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 hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
+ syncableAuthorities.clear();
+ if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
+ }
+
+ for (String authority : syncableAuthorities) {
+ for (Account account : accounts) {
+ boolean isSyncable = mSyncStorageEngine.getIsSyncable(account, authority) > 0;
+ if (!isSyncable) {
+ continue;
+ }
+ if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type))
+ != null) {
+ scheduleSyncOperation(
+ new SyncOperation(account, source, authority, extras, delay));
}
}
}
@@ -598,36 +613,10 @@
mStatusText = message;
}
- private void populateProvidersList(Uri url, List<String> names, List<ProviderInfo> providers) {
- try {
- final IPackageManager packageManager = getPackageManager();
- if (url == null) {
- packageManager.querySyncProviders(names, providers);
- } else {
- final String authority = url.getAuthority();
- ProviderInfo info = packageManager.resolveContentProvider(url.getAuthority(), 0);
- if (info != null) {
- // only set this provider if the requested authority is the primary authority
- String[] providerNames = info.authority.split(";");
- if (url.getAuthority().equals(providerNames[0])) {
- names.add(authority);
- providers.add(info);
- }
- }
- }
- } catch (RemoteException ex) {
- // we should really never get this, but if we do then clear the lists, which
- // will result in the dropping of the sync request
- Log.e(TAG, "error trying to get the ProviderInfo for " + url, ex);
- names.clear();
- providers.clear();
- }
- }
-
- public void scheduleLocalSync(Uri url) {
+ public void scheduleLocalSync(Account account, String authority) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
- scheduleSync(url, extras, LOCAL_SYNC_DELAY);
+ scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY);
}
private IPackageManager getPackageManager() {
@@ -641,18 +630,16 @@
return mPackageManager;
}
- /**
- * Initiate a sync for this given URL, or pass null for a full sync.
- *
- * <p>You'll start getting callbacks after this.
- *
- * @param url The Uri of a specific provider to be synced, or
- * null to sync all providers.
- * @param extras a Map of SyncAdapter specific information to control
- * syncs of a specific provider. Can be null. Is ignored
- */
- public void startSync(Uri url, Bundle extras) {
- scheduleSync(url, extras, 0 /* no delay */);
+ public SyncAdapterType[] getSyncAdapterTypes() {
+ final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos =
+ mSyncAdapters.getAllServices();
+ SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
+ int i = 0;
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
+ types[i] = serviceInfo.type;
+ ++i;
+ }
+ return types;
}
public void updateHeartbeatTime() {
@@ -721,8 +708,7 @@
}
// Cap the delay
- ensureContentResolver();
- long maxSyncRetryTimeInSeconds = Settings.Gservices.getLong(mContentResolver,
+ long maxSyncRetryTimeInSeconds = Settings.Gservices.getLong(mContext.getContentResolver(),
Settings.Gservices.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
@@ -736,17 +722,22 @@
}
/**
- * Cancel the active sync if it matches the uri. The uri corresponds to the one passed
- * in to startSync().
- * @param uri If non-null, the active sync is only canceled if it matches the uri.
- * If null, any active sync is canceled.
+ * Cancel the active sync if it matches the authority and account.
+ * @param account limit the cancelations to syncs with this account, if non-null
+ * @param authority limit the cancelations to syncs with this authority, if non-null
*/
- public void cancelActiveSync(Uri uri) {
+ public void cancelActiveSync(Account account, String authority) {
ActiveSyncContext activeSyncContext = mActiveSyncContext;
if (activeSyncContext != null) {
- // if a Uri was specified then only cancel the sync if it matches the the uri
- if (uri != null) {
- if (!uri.getAuthority().equals(activeSyncContext.mSyncOperation.authority)) {
+ // if an authority was specified then only cancel the sync if it matches
+ if (account != null) {
+ if (!account.equals(activeSyncContext.mSyncOperation.account)) {
+ return;
+ }
+ }
+ // if an account was specified then only cancel the sync if it matches
+ if (authority != null) {
+ if (!authority.equals(activeSyncContext.mSyncOperation.authority)) {
return;
}
}
@@ -798,14 +789,13 @@
}
/**
- * Remove any scheduled sync operations that match uri. The uri corresponds to the one passed
- * in to startSync().
- * @param uri If non-null, only operations that match the uri are cleared.
- * If null, all operations are cleared.
+ * Remove scheduled sync operations.
+ * @param account limit the removals to operations with this account, if non-null
+ * @param authority limit the removals to operations with this authority, if non-null
*/
- public void clearScheduledSyncOperations(Uri uri) {
+ public void clearScheduledSyncOperations(Account account, String authority) {
synchronized (mSyncQueue) {
- mSyncQueue.clear(null, uri != null ? uri.getAuthority() : null);
+ mSyncQueue.clear(account, authority);
}
}
@@ -857,7 +847,7 @@
* Value type that represents a sync operation.
*/
static class SyncOperation implements Comparable {
- final String account;
+ final Account account;
int syncSource;
String authority;
Bundle extras;
@@ -866,7 +856,7 @@
long delay;
SyncStorageEngine.PendingOperation pendingOperation;
- SyncOperation(String account, int source, String authority, Bundle extras, long delay) {
+ SyncOperation(Account account, int source, String authority, Bundle extras, long delay) {
this.account = account;
this.syncSource = source;
this.authority = authority;
@@ -937,21 +927,19 @@
/**
* @hide
*/
- class ActiveSyncContext extends ISyncContext.Stub {
+ class ActiveSyncContext extends ISyncContext.Stub implements ServiceConnection {
final SyncOperation mSyncOperation;
final long mHistoryRowId;
- final IContentProvider mContentProvider;
- final ISyncAdapter mSyncAdapter;
+ ISyncAdapter mSyncAdapter;
final long mStartTime;
long mTimeoutStartTime;
- public ActiveSyncContext(SyncOperation syncOperation, IContentProvider contentProvider,
- ISyncAdapter syncAdapter, long historyRowId) {
+ public ActiveSyncContext(SyncOperation syncOperation,
+ long historyRowId) {
super();
mSyncOperation = syncOperation;
mHistoryRowId = historyRowId;
- mContentProvider = contentProvider;
- mSyncAdapter = syncAdapter;
+ mSyncAdapter = null;
mStartTime = SystemClock.elapsedRealtime();
mTimeoutStartTime = mStartTime;
}
@@ -977,6 +965,37 @@
.append(", syncOperation ").append(mSyncOperation);
}
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Message msg = mSyncHandler.obtainMessage();
+ msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
+ msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
+ mSyncHandler.sendMessage(msg);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ Message msg = mSyncHandler.obtainMessage();
+ msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
+ msg.obj = new ServiceConnectionData(this, null);
+ mSyncHandler.sendMessage(msg);
+ }
+
+ boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);
+ }
+ Intent intent = new Intent();
+ intent.setAction("android.content.SyncAdapter");
+ intent.setComponent(info.componentName);
+ return mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
+ }
+
+ void unBindFromSyncAdapter() {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
+ }
+ mContext.unbindService(this);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -991,6 +1010,12 @@
if (isSyncEnabled()) {
dumpSyncHistory(pw, sb);
}
+
+ pw.println();
+ pw.println("SyncAdapters:");
+ for (RegisteredServicesCache.ServiceInfo info : mSyncAdapters.getAllServices()) {
+ pw.println(" " + info);
+ }
}
static String formatTime(long time) {
@@ -1004,7 +1029,7 @@
pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
pw.print("memory low: "); pw.println(mStorageIsLow);
- final String[] accounts = mAccounts;
+ final Account[] accounts = mAccounts;
pw.print("accounts: ");
if (accounts != null) {
pw.println(accounts.length);
@@ -1068,7 +1093,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); 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);
@@ -1078,7 +1104,7 @@
}
}
- HashSet<String> processedAccounts = new HashSet<String>();
+ HashSet<Account> processedAccounts = new HashSet<Account>();
ArrayList<SyncStatusInfo> statuses
= mSyncStorageEngine.getSyncStatus();
if (statuses != null && statuses.size() > 0) {
@@ -1090,7 +1116,7 @@
SyncStorageEngine.AuthorityInfo authority
= mSyncStorageEngine.getAuthority(status.authorityId);
if (authority != null) {
- String curAccount = authority.account;
+ Account curAccount = authority.account;
if (processedAccounts.contains(curAccount)) {
continue;
@@ -1098,8 +1124,9 @@
processedAccounts.add(curAccount);
- pw.print(" Account "); pw.print(authority.account);
- pw.println(":");
+ 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);
authority = mSyncStorageEngine.getAuthority(status.authorityId);
@@ -1219,9 +1246,15 @@
SyncStorageEngine.AuthorityInfo authority
= mSyncStorageEngine.getAuthority(item.authorityId);
pw.print(" #"); pw.print(i+1); pw.print(": ");
- pw.print(authority != null ? authority.account : "<no account>");
- pw.print(" ");
- pw.print(authority != null ? authority.authority : "<no account>");
+ if (authority != null) {
+ pw.print(authority.account.name);
+ pw.print(":");
+ pw.print(authority.account.type);
+ pw.print(" ");
+ pw.print(authority.authority);
+ } else {
+ pw.print("<no account>");
+ }
Time time = new Time();
time.set(item.eventTime);
pw.print(" "); pw.print(SyncStorageEngine.SOURCES[item.source]);
@@ -1278,6 +1311,15 @@
}
}
+ class ServiceConnectionData {
+ public final ActiveSyncContext activeSyncContext;
+ public final ISyncAdapter syncAdapter;
+ ServiceConnectionData(ActiveSyncContext activeSyncContext, ISyncAdapter syncAdapter) {
+ this.activeSyncContext = activeSyncContext;
+ this.syncAdapter = syncAdapter;
+ }
+ }
+
/**
* Handles SyncOperation Messages that are posted to the associated
* HandlerThread.
@@ -1287,6 +1329,8 @@
private static final int MESSAGE_SYNC_FINISHED = 1;
private static final int MESSAGE_SYNC_ALARM = 2;
private static final int MESSAGE_CHECK_ALARMS = 3;
+ private static final int MESSAGE_SERVICE_CONNECTED = 4;
+ private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
@@ -1301,7 +1345,7 @@
*/
class SyncNotificationInfo {
// only valid if isActive is true
- public String account;
+ public Account account;
// only valid if isActive is true
public String authority;
@@ -1358,6 +1402,53 @@
runStateIdle();
break;
+ case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
+ ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
+ + msgData.activeSyncContext
+ + " active is " + mActiveSyncContext);
+ }
+ // check that this isn't an old message
+ if (mActiveSyncContext == msgData.activeSyncContext) {
+ runBoundToSyncAdapter(msgData.syncAdapter);
+ }
+ break;
+ }
+
+ case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
+ ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
+ + msgData.activeSyncContext
+ + " active is " + mActiveSyncContext);
+ }
+ // check that this isn't an old message
+ if (mActiveSyncContext == msgData.activeSyncContext) {
+ // cancel the sync if we have a syncadapter, which means one is
+ // outstanding
+ if (mActiveSyncContext.mSyncAdapter != null) {
+ try {
+ mActiveSyncContext.mSyncAdapter.cancelSync(mActiveSyncContext);
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
+ }
+
+ // pretend that the sync failed with an IOException,
+ // which is a soft error
+ SyncResult syncResult = new SyncResult();
+ syncResult.stats.numIoExceptions++;
+ runSyncFinishedOrCanceled(syncResult);
+
+ // since we are no longer syncing, check if it is time to start a new
+ // sync
+ runStateIdle();
+ }
+
+ break;
+ }
+
case SyncHandler.MESSAGE_SYNC_ALARM: {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) {
@@ -1456,7 +1547,7 @@
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- String[] accounts = mAccounts;
+ Account[] accounts = mAccounts;
if (accounts == null) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: accounts not known, skipping");
@@ -1468,14 +1559,14 @@
// Otherwise consume SyncOperations from the head of the SyncQueue until one is
// found that is runnable (not disabled, etc). If that one is ready to run then
// start it, otherwise just get out.
- SyncOperation syncOperation;
+ SyncOperation op;
final ConnectivityManager connManager = (ConnectivityManager)
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- final boolean backgroundDataSetting = connManager.getBackgroundDataSetting();
+ final boolean backgroundDataUsageAllowed = connManager.getBackgroundDataSetting();
synchronized (mSyncQueue) {
while (true) {
- syncOperation = mSyncQueue.head();
- if (syncOperation == null) {
+ op = mSyncQueue.head();
+ if (op == null) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: no more sync operations, returning");
}
@@ -1485,39 +1576,42 @@
// Sync is disabled, drop this operation.
if (!isSyncEnabled()) {
if (isLoggable) {
- Log.v(TAG, "runStateIdle: sync disabled, dropping " + syncOperation);
+ Log.v(TAG, "runStateIdle: sync disabled, dropping " + op);
}
mSyncQueue.popHead();
continue;
}
- // skip the sync if it isn't a force and the settings are off for this provider
- final boolean force = syncOperation.extras.getBoolean(
- ContentResolver.SYNC_EXTRAS_FORCE, false);
- if (!force && (!backgroundDataSetting
- || !mSyncStorageEngine.getListenForNetworkTickles()
- || !mSyncStorageEngine.getSyncProviderAutomatically(
- null, syncOperation.authority))) {
+ // skip the sync if it isn't manual and auto sync is disabled
+ final boolean manualSync = op.extras.getBoolean(
+ ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ final boolean syncAutomatically =
+ mSyncStorageEngine.getSyncAutomatically(op.account, op.authority)
+ && mSyncStorageEngine.getMasterSyncAutomatically();
+ boolean isSyncable =
+ mSyncStorageEngine.getIsSyncable(op.account, op.authority) > 0;
+ boolean syncAllowed =
+ manualSync || (backgroundDataUsageAllowed && syncAutomatically);
+ if (!syncAllowed || !isSyncable) {
if (isLoggable) {
- Log.v(TAG, "runStateIdle: sync off, dropping " + syncOperation);
+ Log.v(TAG, "runStateIdle: sync off, dropping " + op);
}
mSyncQueue.popHead();
continue;
}
// skip the sync if the account of this operation no longer exists
- if (!ArrayUtils.contains(accounts, syncOperation.account)) {
+ if (!ArrayUtils.contains(accounts, op.account)) {
mSyncQueue.popHead();
if (isLoggable) {
- Log.v(TAG, "runStateIdle: account not present, dropping "
- + syncOperation);
+ Log.v(TAG, "runStateIdle: account not present, dropping " + op);
}
continue;
}
// go ahead and try to sync this syncOperation
if (isLoggable) {
- Log.v(TAG, "runStateIdle: found sync candidate: " + syncOperation);
+ Log.v(TAG, "runStateIdle: found sync candidate: " + op);
}
break;
}
@@ -1525,11 +1619,10 @@
// If the first SyncOperation isn't ready to run schedule a wakeup and
// get out.
final long now = SystemClock.elapsedRealtime();
- if (syncOperation.earliestRunTime > now) {
+ if (op.earliestRunTime > now) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "runStateIdle: the time is " + now + " yet the next "
- + "sync operation is for " + syncOperation.earliestRunTime
- + ": " + syncOperation);
+ + "sync operation is for " + op.earliestRunTime + ": " + op);
}
return;
}
@@ -1537,72 +1630,73 @@
// We will do this sync. Remove it from the queue and run it outside of the
// synchronized block.
if (isLoggable) {
- Log.v(TAG, "runStateIdle: we are going to sync " + syncOperation);
+ Log.v(TAG, "runStateIdle: we are going to sync " + op);
}
mSyncQueue.popHead();
}
- String providerName = syncOperation.authority;
- ensureContentResolver();
- IContentProvider contentProvider;
-
- // acquire the provider and update the sync history
- try {
- contentProvider = mContentResolver.acquireProvider(providerName);
- if (contentProvider == null) {
- Log.e(TAG, "Provider " + providerName + " doesn't exist");
- return;
+ // connect to the sync adapter
+ SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority,
+ op.account.type);
+ RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(syncAdapterType);
+ if (syncAdapterInfo == null) {
+ if (Config.LOGD) {
+ Log.d(TAG, "can't find a sync adapter for " + syncAdapterType);
}
- if (contentProvider.getSyncAdapter() == null) {
- Log.e(TAG, "Provider " + providerName + " isn't syncable, " + contentProvider);
- return;
- }
- } catch (RemoteException remoteExc) {
- Log.e(TAG, "Caught a RemoteException while preparing for sync, rescheduling "
- + syncOperation, remoteExc);
- rescheduleWithDelay(syncOperation);
- return;
- } catch (RuntimeException exc) {
- Log.e(TAG, "Caught a RuntimeException while validating sync of " + providerName,
- exc);
+ runStateIdle();
return;
}
- final long historyRowId = insertStartSyncEvent(syncOperation);
-
- try {
- ISyncAdapter syncAdapter = contentProvider.getSyncAdapter();
- ActiveSyncContext activeSyncContext = new ActiveSyncContext(syncOperation,
- contentProvider, syncAdapter, historyRowId);
- mSyncWakeLock.acquire();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "starting sync of " + syncOperation);
- }
- syncAdapter.startSync(activeSyncContext, syncOperation.account,
- syncOperation.extras);
- mActiveSyncContext = activeSyncContext;
+ ActiveSyncContext activeSyncContext =
+ new ActiveSyncContext(op, insertStartSyncEvent(op));
+ mActiveSyncContext = activeSyncContext;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "runStateIdle: setting mActiveSyncContext to " + mActiveSyncContext);
+ }
+ mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {
+ Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
+ mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ runStateIdle();
+ return;
+ }
+
+ mSyncWakeLock.acquire();
+ // no need to schedule an alarm, as that will be done by our caller.
+
+ // the next step will occur when we get either a timeout or a
+ // MESSAGE_SERVICE_CONNECTED or MESSAGE_SERVICE_DISCONNECTED message
+ }
+
+ private void runBoundToSyncAdapter(ISyncAdapter syncAdapter) {
+ mActiveSyncContext.mSyncAdapter = syncAdapter;
+ final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation;
+ try {
+ syncAdapter.startSync(mActiveSyncContext, syncOperation.authority,
+ syncOperation.account, syncOperation.extras);
} catch (RemoteException remoteExc) {
if (Config.LOGD) {
Log.d(TAG, "runStateIdle: caught a RemoteException, rescheduling", remoteExc);
}
+ mActiveSyncContext.unBindFromSyncAdapter();
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
rescheduleWithDelay(syncOperation);
} catch (RuntimeException exc) {
+ mActiveSyncContext.unBindFromSyncAdapter();
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
Log.e(TAG, "Caught a RuntimeException while starting the sync " + syncOperation,
exc);
}
-
- // no need to schedule an alarm, as that will be done by our caller.
}
private void runSyncFinishedOrCanceled(SyncResult syncResult) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) Log.v(TAG, "runSyncFinishedOrCanceled");
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
+ final ActiveSyncContext activeSyncContext = mActiveSyncContext;
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
@@ -1642,10 +1736,12 @@
Log.v(TAG, "runSyncFinishedOrCanceled: is a cancel: operation "
+ syncOperation);
}
- try {
- activeSyncContext.mSyncAdapter.cancelSync();
- } catch (RemoteException e) {
- // we don't need to retry this in this case
+ if (activeSyncContext.mSyncAdapter != null) {
+ try {
+ activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
}
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
@@ -1655,7 +1751,7 @@
stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
upstreamActivity, downstreamActivity, elapsedTime);
- mContentResolver.releaseProvider(activeSyncContext.mContentProvider);
+ activeSyncContext.unBindFromSyncAdapter();
if (syncResult != null && syncResult.tooManyDeletions) {
installHandleTooManyDeletesNotification(syncOperation.account,
@@ -1683,21 +1779,21 @@
*/
private int syncResultToErrorNumber(SyncResult syncResult) {
if (syncResult.syncAlreadyInProgress)
- return SyncStorageEngine.ERROR_SYNC_ALREADY_IN_PROGRESS;
+ return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
if (syncResult.stats.numAuthExceptions > 0)
- return SyncStorageEngine.ERROR_AUTHENTICATION;
+ return ContentResolver.SYNC_ERROR_AUTHENTICATION;
if (syncResult.stats.numIoExceptions > 0)
- return SyncStorageEngine.ERROR_IO;
+ return ContentResolver.SYNC_ERROR_IO;
if (syncResult.stats.numParseExceptions > 0)
- return SyncStorageEngine.ERROR_PARSE;
+ return ContentResolver.SYNC_ERROR_PARSE;
if (syncResult.stats.numConflictDetectedExceptions > 0)
- return SyncStorageEngine.ERROR_CONFLICT;
+ return ContentResolver.SYNC_ERROR_CONFLICT;
if (syncResult.tooManyDeletions)
- return SyncStorageEngine.ERROR_TOO_MANY_DELETIONS;
+ return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
if (syncResult.tooManyRetries)
- return SyncStorageEngine.ERROR_TOO_MANY_RETRIES;
+ return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
if (syncResult.databaseError)
- return SyncStorageEngine.ERROR_INTERNAL;
+ return ContentResolver.SYNC_ERROR_INTERNAL;
throw new IllegalStateException("we are not in an error state, " + syncResult);
}
@@ -1738,9 +1834,10 @@
} else {
final boolean timeToShowNotification =
now > mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY;
- final boolean syncIsForced = syncOperation.extras
- .getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
- shouldInstall = timeToShowNotification || syncIsForced;
+ // show the notification immediately if this is a manual sync
+ final boolean manualSync = syncOperation.extras
+ .getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ shouldInstall = timeToShowNotification || manualSync;
}
}
@@ -1860,7 +1957,7 @@
mContext.sendBroadcast(syncStateIntent);
}
- private void installHandleTooManyDeletesNotification(String account, String authority,
+ private void installHandleTooManyDeletesNotification(Account account, String authority,
long numDeletes) {
if (mNotificationMgr == null) return;
Intent clickIntent = new Intent();
@@ -1995,9 +2092,9 @@
SyncOperation existingOperation = mOpsByKey.get(operationKey);
// if this operation matches an existing operation that is being retried (delay > 0)
- // and this operation isn't forced, ignore this operation
+ // and this isn't a manual sync operation, ignore this operation
if (existingOperation != null && existingOperation.delay > 0) {
- if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)) {
+ if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
return false;
}
}
@@ -2071,7 +2168,7 @@
if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
}
- public void clear(String account, String authority) {
+ public void clear(Account account, String authority) {
Iterator<Map.Entry<String, SyncOperation>> entries = mOpsByKey.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, SyncOperation> entry = entries.next();
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index f503e6f..64bbe25 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -23,6 +23,7 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.accounts.Account;
/**
* Extends the schema of a ContentProvider to include the _sync_state table
@@ -43,14 +44,15 @@
private static final Uri CONTENT_URI =
Uri.parse("content://" + SYNC_STATE_AUTHORITY + "/state");
- private static final String ACCOUNT_WHERE = "_sync_account = ?";
+ private static final String ACCOUNT_WHERE = "_sync_account = ? AND _sync_account_type = ?";
private final Provider mInternalProviderInterface;
private static final String SYNC_STATE_TABLE = "_sync_state";
- private static long DB_VERSION = 2;
+ private static long DB_VERSION = 3;
- private static final String[] ACCOUNT_PROJECTION = new String[]{"_sync_account"};
+ private static final String[] ACCOUNT_PROJECTION =
+ new String[]{"_sync_account", "_sync_account_type"};
static {
sURIMatcher.addURI(SYNC_STATE_AUTHORITY, "state", STATE);
@@ -70,8 +72,9 @@
db.execSQL("CREATE TABLE _sync_state (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"data TEXT," +
- "UNIQUE(_sync_account)" +
+ "UNIQUE(_sync_account, _sync_account_type)" +
");");
db.execSQL("DROP TABLE IF EXISTS _sync_state_metadata");
@@ -168,15 +171,17 @@
* @param account the account of the row that should be copied over.
*/
public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
- String account) {
- final String[] whereArgs = new String[]{account};
- Cursor c = dbSrc.query(SYNC_STATE_TABLE, new String[]{"_sync_account", "data"},
+ Account account) {
+ 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);
try {
if (c.moveToNext()) {
ContentValues values = new ContentValues();
values.put("_sync_account", c.getString(0));
- values.put("data", c.getBlob(1));
+ values.put("_sync_account_type", c.getString(1));
+ values.put("data", c.getBlob(2));
dbDest.replace(SYNC_STATE_TABLE, "_sync_account", values);
}
} finally {
@@ -184,14 +189,17 @@
}
}
- public void onAccountsChanged(String[] accounts) {
+ public void onAccountsChanged(Account[] accounts) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
try {
while (c.moveToNext()) {
- final String account = c.getString(0);
+ final String accountName = c.getString(0);
+ final String accountType = c.getString(1);
+ Account account = new Account(accountName, accountType);
if (!ArrayUtils.contains(accounts, account)) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE,
+ new String[]{accountName, accountType});
}
}
} finally {
@@ -199,9 +207,9 @@
}
}
- public void discardSyncData(SQLiteDatabase db, String account) {
+ public void discardSyncData(SQLiteDatabase db, Account account) {
if (account != null) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.name, account.type});
} else {
db.delete(SYNC_STATE_TABLE, null, null);
}
@@ -210,9 +218,9 @@
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(SQLiteDatabase db, String account) {
+ public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
- new String[]{account}, null, null, null);
+ new String[]{account.name, account.type}, null, null, null);
try {
if (c.moveToFirst()) {
return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -226,9 +234,10 @@
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public void writeSyncDataBytes(SQLiteDatabase db, String account, byte[] data) {
+ public void writeSyncDataBytes(SQLiteDatabase db, Account account, byte[] data) {
ContentValues values = new ContentValues();
values.put("data", data);
- db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE, new String[]{account});
+ db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
+ new String[]{account.name, account.type});
}
}
diff --git a/core/java/android/content/SyncStatusObserver.java b/core/java/android/content/SyncStatusObserver.java
new file mode 100644
index 0000000..663378a
--- /dev/null
+++ b/core/java/android/content/SyncStatusObserver.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+public interface SyncStatusObserver {
+ void onStatusChanged(int which);
+}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 756f35c..2647962 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -24,6 +24,7 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.accounts.Account;
import android.backup.IBackupManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -88,6 +89,9 @@
/** Enum value for a user-initiated sync. */
public static final int SOURCE_USER = 3;
+ private static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
+ new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
+
// TODO: i18n -- grab these out of resources.
/** String names for the sync source types. */
public static final String[] SOURCES = { "SERVER",
@@ -95,26 +99,10 @@
"POLL",
"USER" };
- // Error types
- public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
- public static final int ERROR_AUTHENTICATION = 2;
- public static final int ERROR_IO = 3;
- public static final int ERROR_PARSE = 4;
- public static final int ERROR_CONFLICT = 5;
- public static final int ERROR_TOO_MANY_DELETIONS = 6;
- public static final int ERROR_TOO_MANY_RETRIES = 7;
- public static final int ERROR_INTERNAL = 8;
-
// The MESG column will contain one of these or one of the Error types.
public static final String MESG_SUCCESS = "success";
public static final String MESG_CANCELED = "canceled";
- public static final int CHANGE_SETTINGS = 1<<0;
- public static final int CHANGE_PENDING = 1<<1;
- public static final int CHANGE_ACTIVE = 1<<2;
- public static final int CHANGE_STATUS = 1<<3;
- public static final int CHANGE_ALL = 0x7fffffff;
-
public static final int MAX_HISTORY = 15;
private static final int MSG_WRITE_STATUS = 1;
@@ -122,9 +110,11 @@
private static final int MSG_WRITE_STATISTICS = 2;
private static final long WRITE_STATISTICS_DELAY = 1000*60*30; // 1/2 hour
+
+ private static final boolean SYNC_ENABLED_DEFAULT = false;
public static class PendingOperation {
- final String account;
+ final Account account;
final int syncSource;
final String authority;
final Bundle extras; // note: read-only.
@@ -132,7 +122,7 @@
int authorityId;
byte[] flatExtras;
- PendingOperation(String account, int source,
+ PendingOperation(Account account, int source,
String authority, Bundle extras) {
this.account = account;
this.syncSource = source;
@@ -151,26 +141,29 @@
}
static class AccountInfo {
- final String account;
+ final Account account;
final HashMap<String, AuthorityInfo> authorities =
new HashMap<String, AuthorityInfo>();
- AccountInfo(String account) {
+ AccountInfo(Account account) {
this.account = account;
}
}
public static class AuthorityInfo {
- final String account;
+ final Account account;
final String authority;
final int ident;
boolean enabled;
-
- AuthorityInfo(String account, String authority, int ident) {
+ int syncable;
+
+ AuthorityInfo(Account account, String authority, int ident) {
this.account = account;
this.authority = authority;
this.ident = ident;
- enabled = true;
+ enabled = SYNC_ENABLED_DEFAULT;
+ // TODO: change the default to -1 when the syncadapters are changed to set this
+ syncable = 1;
}
}
@@ -202,8 +195,8 @@
private final SparseArray<AuthorityInfo> mAuthorities =
new SparseArray<AuthorityInfo>();
- private final HashMap<String, AccountInfo> mAccounts =
- new HashMap<String, AccountInfo>();
+ private final HashMap<Account, AccountInfo> mAccounts =
+ new HashMap<Account, AccountInfo>();
private final ArrayList<PendingOperation> mPendingOperations =
new ArrayList<PendingOperation>();
@@ -258,7 +251,7 @@
private int mNumPendingFinished = 0;
private int mNextHistoryId = 0;
- private boolean mListenForTickles = true;
+ private boolean mMasterSyncAutomatically = true;
private SyncStorageEngine(Context context) {
mContext = context;
@@ -366,14 +359,14 @@
}
}
- public boolean getSyncProviderAutomatically(String account, String providerName) {
+ public boolean getSyncAutomatically(Account account, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
- "getSyncProviderAutomatically");
- return authority != null ? authority.enabled : false;
+ "getSyncAutomatically");
+ return authority != null && authority.enabled;
}
-
+
int i = mAuthorities.size();
while (i > 0) {
i--;
@@ -387,45 +380,80 @@
}
}
- public void setSyncProviderAutomatically(String account, String providerName, boolean sync) {
+ public void setSyncAutomatically(Account account, String providerName, boolean sync) {
+ boolean wasEnabled;
+ synchronized (mAuthorities) {
+ AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
+ wasEnabled = authority.enabled;
+ authority.enabled = sync;
+ writeAccountInfoLocked();
+ }
+
+ if (!wasEnabled && sync) {
+ mContext.getContentResolver().requestSync(account, providerName, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+
+ public int getIsSyncable(Account account, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
- "setSyncProviderAutomatically");
- if (authority != null) {
- authority.enabled = sync;
+ "getIsSyncable");
+ if (authority == null) {
+ return -1;
}
- } else {
- int i = mAuthorities.size();
- while (i > 0) {
- i--;
- AuthorityInfo authority = mAuthorities.get(i);
- if (authority.authority.equals(providerName)) {
- authority.enabled = sync;
- }
+ return authority.syncable;
+ }
+
+ int i = mAuthorities.size();
+ while (i > 0) {
+ i--;
+ AuthorityInfo authority = mAuthorities.get(i);
+ if (authority.authority.equals(providerName)) {
+ return authority.syncable;
}
}
- writeAccountInfoLocked();
+ return -1;
}
-
- reportChange(CHANGE_SETTINGS);
}
- public void setListenForNetworkTickles(boolean flag) {
+ public void setIsSyncable(Account account, String providerName, int syncable) {
+ int oldState;
synchronized (mAuthorities) {
- mListenForTickles = flag;
+ AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
+ oldState = authority.syncable;
+ authority.syncable = syncable;
writeAccountInfoLocked();
}
- reportChange(CHANGE_SETTINGS);
+
+ if (oldState <= 0 && syncable > 0) {
+ mContext.getContentResolver().requestSync(account, providerName, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public boolean getListenForNetworkTickles() {
+ public void setMasterSyncAutomatically(boolean flag) {
+ boolean old;
synchronized (mAuthorities) {
- return mListenForTickles;
+ old = mMasterSyncAutomatically;
+ mMasterSyncAutomatically = flag;
+ writeAccountInfoLocked();
+ }
+ if (!old && flag) {
+ mContext.getContentResolver().requestSync(null, null, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ mContext.sendBroadcast(SYNC_CONNECTION_SETTING_CHANGED_INTENT);
+ }
+
+ public boolean getMasterSyncAutomatically() {
+ synchronized (mAuthorities) {
+ return mMasterSyncAutomatically;
}
}
- public AuthorityInfo getAuthority(String account, String authority) {
+ public AuthorityInfo getAuthority(Account account, String authority) {
synchronized (mAuthorities) {
return getAuthorityLocked(account, authority, null);
}
@@ -441,7 +469,7 @@
* Returns true if there is currently a sync operation for the given
* account or authority in the pending list, or actively being processed.
*/
- public boolean isSyncActive(String account, String authority) {
+ public boolean isSyncActive(Account account, String authority) {
synchronized (mAuthorities) {
int i = mPendingOperations.size();
while (i > 0) {
@@ -490,7 +518,7 @@
status.pending = true;
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return op;
}
@@ -536,7 +564,7 @@
}
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return res;
}
@@ -552,7 +580,7 @@
}
writePendingOperationsLocked();
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return num;
}
@@ -580,7 +608,7 @@
* Called when the set of account has changed, given the new array of
* active accounts.
*/
- public void doDatabaseCleanup(String[] accounts) {
+ public void doDatabaseCleanup(Account[] accounts) {
synchronized (mAuthorities) {
if (DEBUG) Log.w(TAG, "Updating for new accounts...");
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
@@ -659,20 +687,20 @@
}
}
- reportChange(CHANGE_ACTIVE);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE);
}
/**
* To allow others to send active change reports, to poke clients.
*/
public void reportActiveChange() {
- reportChange(CHANGE_ACTIVE);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE);
}
/**
* Note that sync has started for the given account and authority.
*/
- public long insertStartSyncEvent(String accountName, String authorityName,
+ public long insertStartSyncEvent(Account accountName, String authorityName,
long now, int source) {
long id;
synchronized (mAuthorities) {
@@ -698,7 +726,7 @@
if (DEBUG) Log.v(TAG, "returning historyId " + id);
}
- reportChange(CHANGE_STATUS);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
return id;
}
@@ -802,7 +830,7 @@
}
}
- reportChange(CHANGE_STATUS);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
}
/**
@@ -860,7 +888,7 @@
/**
* Return true if the pending status is true of any matching authorities.
*/
- public boolean isAuthorityPending(String account, String authority) {
+ public boolean isSyncPending(Account account, String authority) {
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
for (int i=0; i<N; i++) {
@@ -916,7 +944,7 @@
*/
public long getInitialSyncFailureTime() {
synchronized (mAuthorities) {
- if (!mListenForTickles) {
+ if (!mMasterSyncAutomatically) {
return 0;
}
@@ -957,7 +985,7 @@
* @param tag If non-null, this will be used in a log message if the
* requested authority does not exist.
*/
- private AuthorityInfo getAuthorityLocked(String accountName, String authorityName,
+ private AuthorityInfo getAuthorityLocked(Account accountName, String authorityName,
String tag) {
AccountInfo account = mAccounts.get(accountName);
if (account == null) {
@@ -977,7 +1005,7 @@
return authority;
}
- private AuthorityInfo getOrCreateAuthorityLocked(String accountName,
+ private AuthorityInfo getOrCreateAuthorityLocked(Account accountName,
String authorityName, int ident, boolean doWrite) {
AccountInfo account = mAccounts.get(accountName);
if (account == null) {
@@ -1050,7 +1078,7 @@
if ("accounts".equals(tagName)) {
String listen = parser.getAttributeValue(
null, "listen-for-tickles");
- mListenForTickles = listen == null
+ mMasterSyncAutomatically = listen == null
|| Boolean.parseBoolean(listen);
eventType = parser.next();
do {
@@ -1068,26 +1096,43 @@
if (id >= 0) {
String accountName = parser.getAttributeValue(
null, "account");
+ String accountType = parser.getAttributeValue(
+ null, "type");
+ if (accountType == null) {
+ accountType = "com.google.GAIA";
+ }
String authorityName = parser.getAttributeValue(
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(
- accountName, authorityName, id, false);
+ new Account(accountName, accountType),
+ authorityName, id, false);
}
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);
}
}
}
@@ -1125,7 +1170,7 @@
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "accounts");
- if (!mListenForTickles) {
+ if (!mMasterSyncAutomatically) {
out.attribute(null, "listen-for-tickles", "false");
}
@@ -1134,11 +1179,17 @@
AuthorityInfo authority = mAuthorities.get(i);
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, "account", authority.account);
+ 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");
}
@@ -1183,6 +1234,8 @@
}
if (db != null) {
+ final boolean hasType = db.getVersion() >= 11;
+
// Copy in all of the status information, as well as accounts.
if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db");
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
@@ -1190,6 +1243,9 @@
HashMap<String,String> map = new HashMap<String,String>();
map.put("_id", "status._id as _id");
map.put("account", "stats.account as account");
+ if (hasType) {
+ map.put("account_type", "stats.account_type as account_type");
+ }
map.put("authority", "stats.authority as authority");
map.put("totalElapsedTime", "totalElapsedTime");
map.put("numSyncs", "numSyncs");
@@ -1208,9 +1264,15 @@
Cursor c = qb.query(db, null, null, null, null, null, null);
while (c.moveToNext()) {
String accountName = c.getString(c.getColumnIndex("account"));
+ String accountType = hasType
+ ? c.getString(c.getColumnIndex("account_type")) : null;
+ if (accountType == null) {
+ accountType = "com.google.GAIA";
+ }
String authorityName = c.getString(c.getColumnIndex("authority"));
AuthorityInfo authority = this.getOrCreateAuthorityLocked(
- accountName, authorityName, -1, false);
+ new Account(accountName, accountType),
+ authorityName, -1, false);
if (authority != null) {
int i = mSyncStatus.size();
boolean found = false;
@@ -1253,13 +1315,19 @@
String value = c.getString(c.getColumnIndex("value"));
if (name == null) continue;
if (name.equals("listen_for_tickles")) {
- setListenForNetworkTickles(value == null
- || Boolean.parseBoolean(value));
+ setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value));
} else if (name.startsWith("sync_provider_")) {
String provider = name.substring("sync_provider_".length(),
name.length());
- setSyncProviderAutomatically(null, provider,
- value == null || Boolean.parseBoolean(value));
+ int i = mAuthorities.size();
+ while (i > 0) {
+ i--;
+ 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/SyncableContentProvider.java b/core/java/android/content/SyncableContentProvider.java
index e0cd786..ab4e91c 100644
--- a/core/java/android/content/SyncableContentProvider.java
+++ b/core/java/android/content/SyncableContentProvider.java
@@ -19,6 +19,7 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
+import android.accounts.Account;
import java.util.Map;
@@ -32,6 +33,16 @@
public abstract class SyncableContentProvider extends ContentProvider {
protected abstract boolean isTemporary();
+ private volatile TempProviderSyncAdapter mTempProviderSyncAdapter;
+
+ public void setTempProviderSyncAdapter(TempProviderSyncAdapter syncAdapter) {
+ mTempProviderSyncAdapter = syncAdapter;
+ }
+
+ public TempProviderSyncAdapter getTempProviderSyncAdapter() {
+ return mTempProviderSyncAdapter;
+ }
+
/**
* Close resources that must be closed. You must call this to properly release
* the resources used by the SyncableContentProvider.
@@ -110,7 +121,7 @@
* @param context the sync context for the operation
* @param account
*/
- public abstract void onSyncStart(SyncContext context, String account);
+ public abstract void onSyncStart(SyncContext context, Account account);
/**
* Called right after a sync is completed
@@ -124,7 +135,7 @@
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public abstract String getSyncingAccount();
+ public abstract Account getSyncingAccount();
/**
* Merge diffs from a sync source with this content provider.
@@ -194,7 +205,7 @@
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected abstract void onAccountsChanged(String[] accountsArray);
+ protected abstract void onAccountsChanged(Account[] accountsArray);
/**
* A helper method to delete all rows whose account is not in the accounts
@@ -203,26 +214,24 @@
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected abstract void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName);
+ protected abstract void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts,
+ String table);
/**
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public abstract void wipeAccount(String account);
+ public abstract void wipeAccount(Account account);
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public abstract byte[] readSyncDataBytes(String account);
+ public abstract byte[] readSyncDataBytes(Account account);
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public abstract void writeSyncDataBytes(String account, byte[] data);
+ public abstract void writeSyncDataBytes(Account account, byte[] data);
}
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index eb3a5da..fb05fe7 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -12,6 +12,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.TimingLogger;
+import android.accounts.Account;
/**
* @hide
@@ -62,12 +63,10 @@
*
* @param context allows you to publish status and interact with the
* @param account the account to sync
- * @param forced if true then the sync was forced
+ * @param manualSync true if this sync was requested manually by the user
* @param result information to track what happened during this sync attempt
- * @return true, if the sync was successfully started. One reason it can
- * fail to start is if there is no user configured on the device.
*/
- public abstract void onSyncStarting(SyncContext context, String account, boolean forced,
+ public abstract void onSyncStarting(SyncContext context, Account account, boolean manualSync,
SyncResult result);
/**
@@ -168,12 +167,12 @@
* exist.
* @param accounts the list of accounts
*/
- public abstract void onAccountsChanged(String[] accounts);
+ public abstract void onAccountsChanged(Account[] accounts);
private Context mContext;
private class SyncThread extends Thread {
- private final String mAccount;
+ private final Account mAccount;
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
@@ -181,7 +180,7 @@
private long mInitialRxBytes;
private final SyncResult mResult;
- SyncThread(SyncContext syncContext, String account, Bundle extras) {
+ SyncThread(SyncContext syncContext, Account account, Bundle extras) {
super("SyncThread");
mAccount = account;
mExtras = extras;
@@ -221,19 +220,19 @@
}
}
- private void sync(SyncContext syncContext, String account, Bundle extras) {
+ private void sync(SyncContext syncContext, Account account, Bundle extras) {
mIsCanceled = false;
mProviderSyncStarted = false;
mAdapterSyncStarted = false;
String message = null;
- boolean syncForced = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
+ boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
try {
mProvider.onSyncStart(syncContext, account);
mProviderSyncStarted = true;
- onSyncStarting(syncContext, account, syncForced, mResult);
+ onSyncStarting(syncContext, account, manualSync, mResult);
if (mResult.hasError()) {
message = "SyncAdapter failed while trying to start sync";
return;
@@ -273,7 +272,7 @@
}
}
- private void runSyncLoop(SyncContext syncContext, String account, Bundle extras) {
+ private void runSyncLoop(SyncContext syncContext, Account account, Bundle extras) {
TimingLogger syncTimer = new TimingLogger(TAG + "Profiling", "sync");
syncTimer.addSplit("start");
int loopCount = 0;
@@ -518,7 +517,7 @@
EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, "");
}
- public void startSync(SyncContext syncContext, String account, Bundle extras) {
+ public void startSync(SyncContext syncContext, Account account, Bundle extras) {
if (mSyncThread != null) {
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
return;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e587ca7..7760612 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -75,6 +75,8 @@
int checkSignatures(String pkg1, String pkg2);
+ int checkUidSignatures(int uid1, int uid2);
+
String[] getPackagesForUid(int uid);
String getNameForUid(int uid);
@@ -121,6 +123,7 @@
* 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/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 67bd1ac..fca005c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -865,6 +865,7 @@
* {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
* or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
*
+ * @see #checkSignatures(int, int)
* @see #SIGNATURE_MATCH
* @see #SIGNATURE_NEITHER_SIGNED
* @see #SIGNATURE_FIRST_NOT_SIGNED
@@ -875,6 +876,34 @@
public abstract int checkSignatures(String pkg1, String pkg2);
/**
+ * Like {@link #checkSignatures(String, String)}, but takes UIDs of
+ * the two packages to be checked. This can be useful, for example,
+ * when doing the check in an IPC, where the UID is the only identity
+ * available. It is functionally identical to determining the package
+ * associated with the UIDs and checking their signatures.
+ *
+ * @param uid1 First UID whose signature will be compared.
+ * @param uid2 Second UID whose signature will be compared.
+ * @return Returns an integer indicating whether there is a matching
+ * signature: the value is >= 0 if there is a match (or neither package
+ * is signed), or < 0 if there is not a match. The match result can be
+ * further distinguished with the success (>= 0) constants
+ * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
+ * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
+ * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
+ * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
+ *
+ * @see #checkSignatures(int, int)
+ * @see #SIGNATURE_MATCH
+ * @see #SIGNATURE_NEITHER_SIGNED
+ * @see #SIGNATURE_FIRST_NOT_SIGNED
+ * @see #SIGNATURE_SECOND_NOT_SIGNED
+ * @see #SIGNATURE_NO_MATCH
+ * @see #SIGNATURE_UNKNOWN_PACKAGE
+ */
+ public abstract int checkSignatures(int uid1, int uid2);
+
+ /**
* Retrieve the names of all packages that are associated with a particular
* user id. In most cases, this will be a single package name, the package
* that has been assigned that user id. Where there are multiple packages
@@ -1429,8 +1458,6 @@
* which market the package came from.
*
* @param packageName The name of the package to query
- *
- * @hide
*/
public abstract String getInstallerPackageName(String packageName);
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index d01460e..d61e95b 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -74,7 +74,11 @@
* running in the same process. Higher goes first. */
public int initOrder = 0;
- /** Whether or not this provider is syncable. */
+ /**
+ * Whether or not this provider is syncable.
+ * @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.
+ */
public boolean isSyncable = false;
public ProviderInfo() {
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
new file mode 100644
index 0000000..342de2b
--- /dev/null
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ComponentName;
+import android.content.res.XmlResourceParser;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+import com.google.android.collect.Maps;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A cache of registered services. This cache
+ * is built by interrogating the {@link PackageManager} and is updated as packages are added,
+ * removed and changed. The services are referred to by type V and
+ * are made available via the {@link #getServiceInfo} method.
+ * @hide
+ */
+public abstract class RegisteredServicesCache<V> {
+ private static final String TAG = "PackageManager";
+
+ public final Context mContext;
+ private final String mInterfaceName;
+ private final String mMetaDataName;
+ private final String mAttributesName;
+
+ // no need to be synchronized since the map is never changed once mService is written
+ private volatile Map<V, ServiceInfo<V>> mServices;
+
+ // synchronized on "this"
+ private BroadcastReceiver mReceiver = null;
+
+ public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
+ String attributeName) {
+ mContext = context;
+ mInterfaceName = interfaceName;
+ mMetaDataName = metaDataName;
+ mAttributesName = attributeName;
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ getAllServices();
+ Map<V, ServiceInfo<V>> services = mServices;
+ fout.println("RegisteredServicesCache: " + services.size() + " services");
+ for (ServiceInfo info : services.values()) {
+ fout.println(" " + info);
+ }
+ }
+
+ private boolean maybeRegisterForPackageChanges() {
+ synchronized (this) {
+ if (mReceiver == null) {
+ synchronized (this) {
+ mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ mServices = generateServicesMap();
+ }
+ };
+ }
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ mContext.registerReceiver(mReceiver, intentFilter);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private void maybeUnregisterForPackageChanges() {
+ synchronized (this) {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+ }
+
+ /**
+ * Value type that describes a Service. The information within can be used
+ * to bind to the service.
+ */
+ public static class ServiceInfo<V> {
+ public final V type;
+ public final ComponentName componentName;
+ public final int uid;
+
+ private ServiceInfo(V type, ComponentName componentName, int uid) {
+ this.type = type;
+ this.componentName = componentName;
+ this.uid = uid;
+ }
+
+ public String toString() {
+ return "ServiceInfo: " + type + ", " + componentName;
+ }
+ }
+
+ /**
+ * Accessor for the registered authenticators.
+ * @param type the account type of the authenticator
+ * @return the AuthenticatorInfo that matches the account type or null if none is present
+ */
+ public ServiceInfo<V> getServiceInfo(V type) {
+ if (mServices == null) {
+ maybeRegisterForPackageChanges();
+ mServices = generateServicesMap();
+ }
+ return mServices.get(type);
+ }
+
+ /**
+ * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all
+ * registered authenticators.
+ */
+ public Collection<ServiceInfo<V>> getAllServices() {
+ if (mServices == null) {
+ maybeRegisterForPackageChanges();
+ mServices = generateServicesMap();
+ }
+ return Collections.unmodifiableCollection(mServices.values());
+ }
+
+ /**
+ * Stops the monitoring of package additions, removals and changes.
+ */
+ public void close() {
+ maybeUnregisterForPackageChanges();
+ }
+
+ protected void finalize() throws Throwable {
+ synchronized (this) {
+ if (mReceiver != null) {
+ Log.e(TAG, "RegisteredServicesCache finalized without being closed");
+ }
+ }
+ close();
+ super.finalize();
+ }
+
+ private Map<V, ServiceInfo<V>> generateServicesMap() {
+ Map<V, ServiceInfo<V>> services = Maps.newHashMap();
+ PackageManager pm = mContext.getPackageManager();
+
+ List<ResolveInfo> resolveInfos =
+ pm.queryIntentServices(new Intent(mInterfaceName), PackageManager.GET_META_DATA);
+
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ try {
+ ServiceInfo<V> info = parseServiceInfo(resolveInfo);
+ if (info != null) {
+ services.put(info.type, info);
+ } else {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString());
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+ }
+ }
+
+ return services;
+ }
+
+ private ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+ throws XmlPullParserException, IOException {
+ android.content.pm.ServiceInfo si = service.serviceInfo;
+ ComponentName componentName = new ComponentName(si.packageName, si.name);
+
+ PackageManager pm = mContext.getPackageManager();
+
+ XmlResourceParser parser = null;
+ try {
+ parser = si.loadXmlMetaData(pm, mMetaDataName);
+ if (parser == null) {
+ throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
+ }
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!mAttributesName.equals(nodeName)) {
+ throw new XmlPullParserException(
+ "Meta-data does not start with " + mAttributesName + " tag");
+ }
+
+ V v = parseServiceAttributes(si.packageName, attrs);
+ if (v == null) {
+ return null;
+ }
+ final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo;
+ final ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+ final int uid = applicationInfo.uid;
+ return new ServiceInfo<V>(v, componentName, uid);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ public abstract V parseServiceAttributes(String packageName, AttributeSet attrs);
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 5f44cc9..cbf8410 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -93,7 +93,8 @@
/**
* The kind of keyboard attached to the device.
- * One of: {@link #KEYBOARD_QWERTY}, {@link #KEYBOARD_12KEY}.
+ * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
+ * {@link #KEYBOARD_12KEY}.
*/
public int keyboard;
@@ -132,8 +133,8 @@
/**
* The kind of navigation method available on the device.
- * One of: {@link #NAVIGATION_DPAD}, {@link #NAVIGATION_TRACKBALL},
- * {@link #NAVIGATION_WHEEL}.
+ * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
+ * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
*/
public int navigation;
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/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index e684cb8..8fb82be 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -202,7 +202,7 @@
sub = subtag(tag, ";size=");
if (sub != null) {
int size = Integer.parseInt(sub);
- buffer.setSpan(new AbsoluteSizeSpan(size),
+ buffer.setSpan(new AbsoluteSizeSpan(size, true),
style[i+1], style[i+2]+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@@ -310,7 +310,7 @@
* the ascent if possible, or the descent if shrinking the ascent further
* will make the text unreadable.
*/
- private static class Height implements LineHeightSpan {
+ private static class Height implements LineHeightSpan.WithDensity {
private int mSize;
private static float sProportion = 0;
@@ -321,9 +321,21 @@
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm) {
- if (fm.bottom - fm.top < mSize) {
- fm.top = fm.bottom - mSize;
- fm.ascent = fm.ascent - mSize;
+ // Should not get called, at least not by StaticLayout.
+ chooseHeight(text, start, end, spanstartv, v, fm, null);
+ }
+
+ public void chooseHeight(CharSequence text, int start, int end,
+ int spanstartv, int v,
+ Paint.FontMetricsInt fm, TextPaint paint) {
+ int size = mSize;
+ if (paint != null) {
+ size *= paint.density;
+ }
+
+ if (fm.bottom - fm.top < size) {
+ fm.top = fm.bottom - size;
+ fm.ascent = fm.ascent - size;
} else {
if (sProportion == 0) {
/*
@@ -343,27 +355,27 @@
int need = (int) Math.ceil(-fm.top * sProportion);
- if (mSize - fm.descent >= need) {
+ if (size - fm.descent >= need) {
/*
* It is safe to shrink the ascent this much.
*/
- fm.top = fm.bottom - mSize;
- fm.ascent = fm.descent - mSize;
- } else if (mSize >= need) {
+ fm.top = fm.bottom - size;
+ fm.ascent = fm.descent - size;
+ } else if (size >= need) {
/*
* We can't show all the descent, but we can at least
* show all the ascent.
*/
fm.top = fm.ascent = -need;
- fm.bottom = fm.descent = fm.top + mSize;
+ fm.bottom = fm.descent = fm.top + size;
} else {
/*
* Show as much of the ascent as we can, and no descent.
*/
- fm.top = fm.ascent = -mSize;
+ fm.top = fm.ascent = -size;
fm.bottom = fm.descent = 0;
}
}
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 4ac0aef..27a02e2 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -166,6 +166,48 @@
return mWindow.isBlob(mPos, columnIndex);
}
+ public boolean isString(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object == null || object instanceof String;
+ }
+ }
+
+ return mWindow.isString(mPos, columnIndex);
+ }
+
+ public boolean isLong(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object != null && (object instanceof Integer || object instanceof Long);
+ }
+ }
+
+ return mWindow.isLong(mPos, columnIndex);
+ }
+
+ public boolean isFloat(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object != null && (object instanceof Float || object instanceof Double);
+ }
+ }
+
+ return mWindow.isFloat(mPos, columnIndex);
+ }
+
@Override
protected void checkPosition()
{
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 8e26730..99db81b 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -263,7 +263,58 @@
}
}
+ /**
+ * Checks if a field contains a long
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is a long
+ */
+ public boolean isLong(int row, int col) {
+ acquireReference();
+ try {
+ return isInteger_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
+ /**
+ * Checks if a field contains a float.
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is a float
+ */
+ public boolean isFloat(int row, int col) {
+ acquireReference();
+ try {
+ return isFloat_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
+ /**
+ * Checks if a field contains either a String or is null.
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is {@code NULL} or a String
+ */
+ public boolean isString(int row, int col) {
+ acquireReference();
+ try {
+ return isString_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
private native boolean isBlob_native(int row, int col);
+ private native boolean isString_native(int row, int col);
+ private native boolean isInteger_native(int row, int col);
+ private native boolean isFloat_native(int row, int col);
/**
* Returns a String for the given field.
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 10f3806..4ca6601 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -20,6 +20,7 @@
import android.content.ContentValues;
import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.sqlite.SQLiteAbortException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
@@ -82,6 +83,8 @@
code = 8;
} else if (e instanceof SQLiteException) {
code = 9;
+ } else if (e instanceof OperationApplicationException) {
+ code = 10;
} else {
reply.writeException(e);
Log.e(TAG, "Writing exception to parcel", e);
@@ -123,6 +126,18 @@
}
}
+ public static void readExceptionWithOperationApplicationExceptionFromParcel(
+ Parcel reply) throws OperationApplicationException {
+ int code = reply.readInt();
+ if (code == 0) return;
+ String msg = reply.readString();
+ if (code == 10) {
+ throw new OperationApplicationException(msg);
+ } else {
+ DatabaseUtils.readExceptionFromParcel(reply, msg, code);
+ }
+ }
+
private static final void readExceptionFromParcel(Parcel reply, String msg, int code) {
switch (code) {
case 2:
@@ -211,7 +226,7 @@
sb.append(sqlString);
sb.append('\'');
}
-
+
/**
* SQL-escape a string.
*/
@@ -240,7 +255,7 @@
appendEscapedSQLString(sql, value.toString());
}
}
-
+
/**
* Concatenates two SQL WHERE clauses, handling empty or null values.
* @hide
@@ -252,12 +267,12 @@
if (TextUtils.isEmpty(b)) {
return a;
}
-
+
return "(" + a + ") AND (" + b + ")";
}
-
+
/**
- * return the collation key
+ * return the collation key
* @param name
* @return the collation key
*/
@@ -269,7 +284,7 @@
return "";
}
}
-
+
/**
* return the collation key in hex format
* @param name
@@ -280,7 +295,7 @@
char[] keys = Hex.encodeHex(arr);
return new String(keys, 0, getKeyLen(arr) * 2);
}
-
+
private static int getKeyLen(byte[] arr) {
if (arr[arr.length - 1] != 0) {
return arr.length;
@@ -289,16 +304,16 @@
return arr.length-1;
}
}
-
+
private static byte[] getCollationKeyInBytes(String name) {
if (mColl == null) {
mColl = Collator.getInstance();
mColl.setStrength(Collator.PRIMARY);
}
- return mColl.getCollationKey(name).toByteArray();
+ return mColl.getCollationKey(name).toByteArray();
}
-
- private static Collator mColl = null;
+
+ private static Collator mColl = null;
/**
* Prints the contents of a Cursor to System.out. The position is restored
* after printing.
@@ -591,10 +606,12 @@
public static long queryNumEntries(SQLiteDatabase db, String table) {
Cursor cursor = db.query(table, countProjection,
null, null, null, null, null);
- cursor.moveToFirst();
- long count = cursor.getLong(0);
- cursor.deactivate();
- return count;
+ try {
+ cursor.moveToFirst();
+ return cursor.getLong(0);
+ } finally {
+ cursor.close();
+ }
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 8a63919..af54a71 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -355,23 +355,26 @@
String groupBy, String having, String sortOrder, String limit) {
String[] projection = computeProjection(projectionIn);
+ StringBuilder where = new StringBuilder();
+
if (mWhereClause.length() > 0) {
- mWhereClause.append(')');
+ where.append(mWhereClause.toString());
+ where.append(')');
}
// Tack on the user's selection, if present.
if (selection != null && selection.length() > 0) {
if (mWhereClause.length() > 0) {
- mWhereClause.append(" AND ");
+ where.append(" AND ");
}
- mWhereClause.append('(');
- mWhereClause.append(selection);
- mWhereClause.append(')');
+ where.append('(');
+ where.append(selection);
+ where.append(')');
}
return buildQueryString(
- mDistinct, mTables, projection, mWhereClause.toString(),
+ mDistinct, mTables, projection, where.toString(),
groupBy, having, sortOrder, limit);
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 091bc17..aa3b852 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -40,15 +40,16 @@
private static final String TAG = "Camera";
// These match the enums in frameworks/base/include/ui/Camera.h
- private static final int CAMERA_MSG_ERROR = 0;
- private static final int CAMERA_MSG_SHUTTER = 1;
- private static final int CAMERA_MSG_FOCUS = 2;
- private static final int CAMERA_MSG_ZOOM = 3;
- private static final int CAMERA_MSG_PREVIEW_FRAME = 4;
- private static final int CAMERA_MSG_VIDEO_FRAME = 5;
- private static final int CAMERA_MSG_POSTVIEW_FRAME = 6;
- private static final int CAMERA_MSG_RAW_IMAGE = 7;
- private static final int CAMERA_MSG_COMPRESSED_IMAGE = 8;
+ private static final int CAMERA_MSG_ERROR = 0x001;
+ private static final int CAMERA_MSG_SHUTTER = 0x002;
+ private static final int CAMERA_MSG_FOCUS = 0x004;
+ private static final int CAMERA_MSG_ZOOM = 0x008;
+ private static final int CAMERA_MSG_PREVIEW_FRAME = 0x010;
+ private static final int CAMERA_MSG_VIDEO_FRAME = 0x020;
+ private static final int CAMERA_MSG_POSTVIEW_FRAME = 0x040;
+ private static final int CAMERA_MSG_RAW_IMAGE = 0x080;
+ private static final int CAMERA_MSG_COMPRESSED_IMAGE = 0x100;
+ private static final int CAMERA_MSG_ALL_MSGS = 0x1FF;
private int mNativeContext; // accessed by native methods
private EventHandler mEventHandler;
@@ -56,7 +57,9 @@
private PictureCallback mRawImageCallback;
private PictureCallback mJpegCallback;
private PreviewCallback mPreviewCallback;
+ private PictureCallback mPostviewCallback;
private AutoFocusCallback mAutoFocusCallback;
+ private ZoomCallback mZoomCallback;
private ErrorCallback mErrorCallback;
private boolean mOneShot;
@@ -72,6 +75,8 @@
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
+ mPostviewCallback = null;
+ mZoomCallback = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -245,13 +250,15 @@
return;
case CAMERA_MSG_RAW_IMAGE:
- if (mRawImageCallback != null)
+ if (mRawImageCallback != null) {
mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
- if (mJpegCallback != null)
+ if (mJpegCallback != null) {
mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
return;
case CAMERA_MSG_PREVIEW_FRAME:
@@ -263,15 +270,29 @@
}
return;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ if (mPostviewCallback != null) {
+ mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
+ return;
+
case CAMERA_MSG_FOCUS:
- if (mAutoFocusCallback != null)
+ if (mAutoFocusCallback != null) {
mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
+ }
+ return;
+
+ case CAMERA_MSG_ZOOM:
+ if (mZoomCallback != null) {
+ mZoomCallback.onZoomUpdate(msg.arg1, mCamera);
+ }
return;
case CAMERA_MSG_ERROR :
Log.e(TAG, "Error " + msg.arg1);
- if (mErrorCallback != null)
+ if (mErrorCallback != null) {
mErrorCallback.onError(msg.arg1, mCamera);
+ }
return;
default:
@@ -364,13 +385,63 @@
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
- mShutterCallback = shutter;
- mRawImageCallback = raw;
- mJpegCallback = jpeg;
- native_takePicture();
+ takePicture(shutter, raw, null, jpeg);
}
private native final void native_takePicture();
+ /**
+ * Triggers an asynchronous image capture. The camera service
+ * will initiate a series of callbacks to the application as the
+ * image capture progresses. The shutter callback occurs after
+ * the image is captured. This can be used to trigger a sound
+ * to let the user know that image has been captured. The raw
+ * callback occurs when the raw image data is available. The
+ * postview callback occurs when a scaled, fully processed
+ * postview image is available (NOTE: not all hardware supports
+ * this). The jpeg callback occurs when the compressed image is
+ * available. If the application does not need a particular
+ * callback, a null can be passed instead of a callback method.
+ *
+ * @param shutter callback after the image is captured, may be null
+ * @param raw callback with raw image data, may be null
+ * @param postview callback with postview image data, may be null
+ * @param jpeg callback with jpeg image data, may be null
+ */
+ public final void takePicture(ShutterCallback shutter, PictureCallback raw,
+ PictureCallback postview, PictureCallback jpeg) {
+ mShutterCallback = shutter;
+ mRawImageCallback = raw;
+ mPostviewCallback = postview;
+ mJpegCallback = jpeg;
+ native_takePicture();
+ }
+
+ /**
+ * Handles the zoom callback.
+ */
+ public interface ZoomCallback
+ {
+ /**
+ * Callback for zoom updates
+ * @param zoomLevel new zoom level in 1/1000 increments,
+ * e.g. a zoom of 3.2x is stored as 3200. Accuracy of the
+ * value is dependent on the hardware implementation. Not
+ * all devices will generate this callback.
+ * @param camera the Camera service object
+ */
+ void onZoomUpdate(int zoomLevel, Camera camera);
+ };
+
+ /**
+ * Registers a callback to be invoked when the zoom
+ * level is updated by the camera driver.
+ * @param cb the callback to run
+ */
+ public final void setZoomCallback(ZoomCallback cb)
+ {
+ mZoomCallback = cb;
+ }
+
// These match the enum in include/ui/Camera.h
/** Unspecified camerar error. @see #ErrorCallback */
public static final int CAMERA_ERROR_UNKNOWN = 1;
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index fea63be..4814b0a 100755
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -142,7 +142,7 @@
private int[][] mGridNeighbors;
private int mProximityThreshold;
/** Number of key widths from current touch point to search for nearest keys. */
- private static float SEARCH_DISTANCE = 1.4f;
+ private static float SEARCH_DISTANCE = 1.8f;
/**
* Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 9c9c143..9e966cd 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -30,7 +30,6 @@
import android.inputmethodservice.Keyboard.Key;
import android.os.Handler;
import android.os.Message;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
@@ -38,6 +37,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;
@@ -163,8 +163,8 @@
private static final int MSG_REPEAT = 3;
private static final int MSG_LONGPRESS = 4;
- private static final int DELAY_BEFORE_PREVIEW = 40;
- private static final int DELAY_AFTER_PREVIEW = 60;
+ private static final int DELAY_BEFORE_PREVIEW = 0;
+ private static final int DELAY_AFTER_PREVIEW = 70;
private int mVerticalCorrection;
private int mProximityThreshold;
@@ -202,13 +202,17 @@
private boolean mAbortKey;
private Key mInvalidatedKey;
private Rect mClipRegion = new Rect(0, 0, 0, 0);
-
+
+ // Variables for dealing with multiple pointers
+ private int mOldPointerCount = 1;
+ private float mOldPointerX;
+ private float mOldPointerY;
+
private Drawable mKeyBackground;
private static final int REPEAT_INTERVAL = 50; // ~20 keys per second
private static final int REPEAT_START_DELAY = 400;
- private static final int LONGPRESS_TIMEOUT = 800;
- // Deemed to be too short : ViewConfiguration.getLongPressTimeout();
+ private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static int MAX_NEARBY_KEYS = 12;
private int[] mDistances = new int[MAX_NEARBY_KEYS];
@@ -227,6 +231,8 @@
private Rect mDirtyRect = new Rect();
/** The keyboard bitmap for faster updates */
private Bitmap mBuffer;
+ /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
+ private boolean mKeyboardChanged;
/** The canvas for the above mutable keyboard bitmap */
private Canvas mCanvas;
@@ -340,6 +346,7 @@
mPaint.setAntiAlias(true);
mPaint.setTextSize(keyTextSize);
mPaint.setTextAlign(Align.CENTER);
+ mPaint.setAlpha(255);
mPadding = new Rect(0, 0, 0, 0);
mMiniKeyboardCache = new HashMap<Key,View>();
@@ -405,12 +412,14 @@
List<Key> keys = mKeyboard.getKeys();
mKeys = keys.toArray(new Key[keys.size()]);
requestLayout();
- // Release buffer, just in case the new keyboard has a different size.
- // It will be reallocated on the next draw.
- mBuffer = null;
+ // Hint to reallocate the buffer if the size changed
+ mKeyboardChanged = true;
invalidateAllKeys();
computeProximityThreshold(keyboard);
mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
+ // Switching to a different keyboard should abort any pending keys so that the key up
+ // doesn't get delivered to the old or new keyboard
+ mAbortKey = true; // Until the next ACTION_DOWN
}
/**
@@ -564,17 +573,21 @@
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (mDrawPending || mBuffer == null) {
+ if (mDrawPending || mBuffer == null || mKeyboardChanged) {
onBufferDraw();
}
canvas.drawBitmap(mBuffer, 0, 0, null);
}
-
+
private void onBufferDraw() {
- if (mBuffer == null) {
- mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
- mCanvas = new Canvas(mBuffer);
+ if (mBuffer == null || mKeyboardChanged) {
+ if (mBuffer == null || mKeyboardChanged &&
+ (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
+ mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBuffer);
+ }
invalidateAllKeys();
+ mKeyboardChanged = false;
}
final Canvas canvas = mCanvas;
canvas.clipRect(mDirtyRect, Op.REPLACE);
@@ -590,7 +603,6 @@
final Key[] keys = mKeys;
final Key invalidKey = mInvalidatedKey;
- paint.setAlpha(255);
paint.setColor(mKeyTextColor);
boolean drawSingleKey = false;
if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
@@ -611,7 +623,7 @@
}
int[] drawableState = key.getCurrentDrawableState();
keyBackground.setState(drawableState);
-
+
// Switch the character to uppercase if shift is pressed
String label = key.label == null? null : adjustCase(key.label).toString();
@@ -680,7 +692,6 @@
private int getKeyIndices(int x, int y, int[] allKeys) {
final Key[] keys = mKeys;
- final boolean shifted = mKeyboard.isShifted();
int primaryIndex = NOT_A_KEY;
int closestKey = NOT_A_KEY;
int closestKeyDist = mProximityThreshold + 1;
@@ -1011,15 +1022,48 @@
}
return false;
}
-
+
@Override
public boolean onTouchEvent(MotionEvent me) {
+ // Convert multi-pointer up/down events to single up/down events to
+ // deal with the typical multi-pointer behavior of two-thumb typing
+ int pointerCount = me.getPointerCount();
+ boolean result = false;
+ if (pointerCount != mOldPointerCount) {
+ long now = me.getEventTime();
+ if (pointerCount == 1) {
+ // Send a down event for the latest pointer
+ MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+ me.getX(), me.getY(), me.getMetaState());
+ result = onModifiedTouchEvent(down);
+ down.recycle();
+ } else {
+ // Send an up event for the last pointer
+ MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
+ mOldPointerX, mOldPointerY, me.getMetaState());
+ result = onModifiedTouchEvent(up);
+ up.recycle();
+ }
+ } else {
+ if (pointerCount == 1) {
+ mOldPointerX = me.getX();
+ mOldPointerY = me.getY();
+ result = onModifiedTouchEvent(me);
+ } else {
+ // Don't do anything when 2 pointers are down and moving.
+ result = true;
+ }
+ }
+ mOldPointerCount = pointerCount;
+ return result;
+ }
+
+ private boolean onModifiedTouchEvent(MotionEvent me) {
int touchX = (int) me.getX() - mPaddingLeft;
int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop;
int action = me.getAction();
long eventTime = me.getEventTime();
int keyIndex = getKeyIndices(touchX, touchY, null);
-
if (mGestureDetector.onTouchEvent(me)) {
showPreview(NOT_A_KEY);
mHandler.removeMessages(MSG_REPEAT);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1429bc1..a127df0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.os.Binder;
import android.os.RemoteException;
/**
@@ -114,15 +115,64 @@
public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
- public static final int TYPE_MOBILE = 0;
- public static final int TYPE_WIFI = 1;
+ /**
+ * The Default Mobile data connection. When active, all data traffic
+ * will use this connection by default. Should not coexist with other
+ * default connections.
+ */
+ public static final int TYPE_MOBILE = 0;
+ /**
+ * The Default WIFI data connection. When active, all data traffic
+ * will use this connection by default. Should not coexist with other
+ * default connections.
+ */
+ public static final int TYPE_WIFI = 1;
+ /**
+ * An MMS-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applications needing to talk to the carrier's Multimedia Messaging
+ * Service servers. It may coexist with default data connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_MMS = 2;
+ /**
+ * A SUPL-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applications needing to talk to the carrier's Secure User Plane
+ * Location servers for help locating the device. It may coexist with
+ * default data connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_SUPL = 3;
+ /**
+ * A DUN-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applicaitons performing a Dial Up Networking bridge so that
+ * the carrier is aware of DUN traffic. It may coexist with default data
+ * connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_DUN = 4;
+ /**
+ * A High Priority Mobile data connection. This connection is typically
+ * the same as {@link #TYPEMOBILE} but the routing setup is different.
+ * Only requesting processes will have access to the Mobile DNS servers
+ * and only IP's explicitly requested via {@link #requestRouteToHost}
+ * will route over this interface.
+ *{@hide}
+ */
+ public static final int TYPE_MOBILE_HIPRI = 5;
+ /** {@hide} */
+ public static final int MAX_RADIO_TYPE = TYPE_WIFI;
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
private IConnectivityManager mService;
static public boolean isNetworkTypeValid(int networkType) {
- return networkType == TYPE_WIFI || networkType == TYPE_MOBILE;
+ return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
}
public void setNetworkPreference(int preference) {
@@ -195,7 +245,8 @@
*/
public int startUsingNetworkFeature(int networkType, String feature) {
try {
- return mService.startUsingNetworkFeature(networkType, feature);
+ return mService.startUsingNetworkFeature(networkType, feature,
+ new Binder());
} catch (RemoteException e) {
return -1;
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index de68598..9f59cce 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.net.NetworkInfo;
+import android.os.IBinder;
/**
* Interface that answers queries about, and allows changing, the
@@ -39,7 +40,8 @@
boolean setRadio(int networkType, boolean turnOn);
- int startUsingNetworkFeature(int networkType, in String feature);
+ int startUsingNetworkFeature(int networkType, in String feature,
+ in IBinder binder);
int stopUsingNetworkFeature(int networkType, in String feature);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 1064fb6..da1115d 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -32,9 +32,6 @@
import android.util.Log;
import android.text.TextUtils;
-import java.util.List;
-import java.util.ArrayList;
-
/**
* Track the state of mobile data connectivity. This is done by
* receiving broadcast intents from the Phone process whenever
@@ -45,36 +42,47 @@
public class MobileDataStateTracker extends NetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private Phone.DataState mMobileDataState;
private ITelephony mPhoneService;
- private static final String[] sDnsPropNames = {
- "net.rmnet0.dns1",
- "net.rmnet0.dns2",
- "net.eth0.dns1",
- "net.eth0.dns2",
- "net.eth0.dns3",
- "net.eth0.dns4",
- "net.gprs.dns1",
- "net.gprs.dns2"
- };
- private List<String> mDnsServers;
- private String mInterfaceName;
- private int mDefaultGatewayAddr;
- private int mLastCallingPid = -1;
+
+ private String mApnType;
+ private boolean mEnabled;
/**
* Create a new MobileDataStateTracker
* @param context the application context of the caller
* @param target a message handler for getting callbacks about state changes
+ * @param netType the ConnectivityManager network type
+ * @param apnType the Phone apnType
+ * @param tag the name of this network
*/
- public MobileDataStateTracker(Context context, Handler target) {
- super(context, target, ConnectivityManager.TYPE_MOBILE,
- TelephonyManager.getDefault().getNetworkType(), "MOBILE",
- TelephonyManager.getDefault().getNetworkTypeName());
+ public MobileDataStateTracker(Context context, Handler target,
+ int netType, String apnType, String tag) {
+ super(context, target, netType,
+ TelephonyManager.getDefault().getNetworkType(), tag,
+ TelephonyManager.getDefault().getNetworkTypeName());
+ mApnType = apnType;
mPhoneService = null;
- mDnsServers = new ArrayList<String>();
+ if(netType == ConnectivityManager.TYPE_MOBILE) {
+ mEnabled = true;
+ } else {
+ mEnabled = false;
+ }
+
+ mDnsPropNames = new String[] {
+ "net.rmnet0.dns1",
+ "net.rmnet0.dns2",
+ "net.eth0.dns1",
+ "net.eth0.dns2",
+ "net.eth0.dns3",
+ "net.eth0.dns4",
+ "net.gprs.dns1",
+ "net.gprs.dns2",
+ "net.ppp0.dns1",
+ "net.ppp0.dns2"};
+
}
/**
@@ -93,31 +101,70 @@
mMobileDataState = Phone.DataState.DISCONNECTED;
}
- private static Phone.DataState getMobileDataState(Intent intent) {
+ private Phone.DataState getMobileDataState(Intent intent) {
String str = intent.getStringExtra(Phone.STATE_KEY);
- if (str != null)
- return Enum.valueOf(Phone.DataState.class, str);
- else
- return Phone.DataState.DISCONNECTED;
+ if (str != null) {
+ String apnTypeList =
+ intent.getStringExtra(Phone.DATA_APN_TYPES_KEY);
+ if (isApnTypeIncluded(apnTypeList)) {
+ return Enum.valueOf(Phone.DataState.class, str);
+ }
+ }
+ return Phone.DataState.DISCONNECTED;
+ }
+
+ private boolean isApnTypeIncluded(String typeList) {
+ /* comma seperated list - split and check */
+ if (typeList == null)
+ return false;
+
+ String[] list = typeList.split(",");
+ for(int i=0; i< list.length; i++) {
+ if (TextUtils.equals(list[i], mApnType) ||
+ TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) {
+ return true;
+ }
+ }
+ return false;
}
private class MobileDataStateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+ 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 reason =
+ intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
- boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
- if (DBG) Log.d(TAG, "Received " + intent.getAction() +
- " broadcast - state = " + state
- + ", unavailable = " + unavailable
- + ", reason = " + (reason == null ? "(unspecified)" : reason));
+
+ 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;
+ }
+
+
mNetworkInfo.setIsAvailable(!unavailable);
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);
@@ -136,12 +183,12 @@
if (mInterfaceName == null) {
Log.d(TAG, "CONNECTED event did not supply interface name.");
}
- setupDnsProperties();
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" +
@@ -154,40 +201,6 @@
}
}
- /**
- * Make sure that route(s) exist to the carrier DNS server(s).
- */
- public void addPrivateRoutes() {
- if (mInterfaceName != null) {
- for (String addrString : mDnsServers) {
- int addr = NetworkUtils.lookupHost(addrString);
- if (addr != -1) {
- NetworkUtils.addHostRoute(mInterfaceName, addr);
- }
- }
- }
- }
-
- public void removePrivateRoutes() {
- if(mInterfaceName != null) {
- NetworkUtils.removeHostRoutes(mInterfaceName);
- }
- }
-
- public void removeDefaultRoute() {
- if(mInterfaceName != null) {
- mDefaultGatewayAddr = NetworkUtils.getDefaultRoute(mInterfaceName);
- NetworkUtils.removeDefaultRoute(mInterfaceName);
- }
- }
-
- public void restoreDefaultRoute() {
- // 0 is not a valid address for a gateway
- if (mInterfaceName != null && mDefaultGatewayAddr != 0) {
- NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
- }
- }
-
private void getPhoneService(boolean forceRefresh) {
if ((mPhoneService == null) || forceRefresh) {
mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
@@ -219,15 +232,6 @@
}
/**
- * Return the IP addresses of the DNS servers available for the mobile data
- * network interface.
- * @return a list of DNS addresses, with no holes.
- */
- public String[] getNameServers() {
- return getNameServerList(sDnsPropNames);
- }
-
- /**
* {@inheritDoc}
* The mobile data network subtype indicates what generation network technology is in effect,
* e.g., GPRS, EDGE, UMTS, etc.
@@ -273,54 +277,19 @@
*/
@Override
public boolean teardown() {
- getPhoneService(false);
- /*
- * If the phone process has crashed in the past, we'll get a
- * RemoteException and need to re-reference the service.
- */
- for (int retry = 0; retry < 2; retry++) {
- if (mPhoneService == null) {
- Log.w(TAG,
- "Ignoring mobile data teardown request because could not acquire PhoneService");
- break;
- }
-
- try {
- return mPhoneService.disableDataConnectivity();
- } catch (RemoteException e) {
- if (retry == 0) getPhoneService(true);
- }
- }
-
- Log.w(TAG, "Failed to tear down mobile data connectivity");
- return false;
+ setTeardownRequested(true);
+ return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED);
}
/**
* Re-enable mobile data connectivity after a {@link #teardown()}.
*/
public boolean reconnect() {
- getPhoneService(false);
- /*
- * If the phone process has crashed in the past, we'll get a
- * RemoteException and need to re-reference the service.
- */
- for (int retry = 0; retry < 2; retry++) {
- if (mPhoneService == null) {
- Log.w(TAG,
- "Ignoring mobile data connect request because could not acquire PhoneService");
- break;
- }
-
- try {
- return mPhoneService.enableDataConnectivity();
- } catch (RemoteException e) {
- if (retry == 0) getPhoneService(true);
- }
- }
-
- Log.w(TAG, "Failed to set up mobile data connectivity");
- return false;
+ mEnabled = true;
+ setTeardownRequested(false);
+ mEnabled = (setEnableApn(mApnType, true) !=
+ Phone.APN_REQUEST_FAILED);
+ return mEnabled;
}
/**
@@ -374,14 +343,7 @@
* </ul>
*/
public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
- if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
- mLastCallingPid = callingPid;
- return setEnableApn(Phone.APN_TYPE_MMS, true);
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
- return setEnableApn(Phone.APN_TYPE_SUPL, true);
- } else {
- return -1;
- }
+ return -1;
}
/**
@@ -397,13 +359,7 @@
* the value {@code -1} always indicates failure.
*/
public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
- if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
- return setEnableApn(Phone.APN_TYPE_MMS, false);
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
- return setEnableApn(Phone.APN_TYPE_SUPL, false);
- } else {
- return -1;
- }
+ return -1;
}
/**
@@ -433,43 +389,6 @@
return sb.toString();
}
- private void setupDnsProperties() {
- mDnsServers.clear();
- // Set up per-process DNS server list on behalf of the MMS process
- int i = 1;
- if (mInterfaceName != null) {
- for (String propName : sDnsPropNames) {
- if (propName.indexOf(mInterfaceName) != -1) {
- String propVal = SystemProperties.get(propName);
- if (propVal != null && propVal.length() != 0 && !propVal.equals("0.0.0.0")) {
- mDnsServers.add(propVal);
- if (mLastCallingPid != -1) {
- SystemProperties.set("net.dns" + i + "." + mLastCallingPid, propVal);
- }
- ++i;
- }
- }
- }
- }
- if (i == 1) {
- Log.d(TAG, "DNS server addresses are not known.");
- } else if (mLastCallingPid != -1) {
- /*
- * Bump the property that tells the name resolver library
- * to reread the DNS server list from the properties.
- */
- String propVal = SystemProperties.get("net.dnschange");
- if (propVal.length() != 0) {
- try {
- int n = Integer.parseInt(propVal);
- SystemProperties.set("net.dnschange", "" + (n+1));
- } catch (NumberFormatException e) {
- }
- }
- }
- mLastCallingPid = -1;
- }
-
/**
* Internal method supporting the ENABLE_MMS feature.
* @param apnType the type of APN to be enabled or disabled (e.g., mms)
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 37087ac..418f511 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -27,6 +27,7 @@
import android.util.Config;
import android.util.Log;
+
/**
* Each subclass of this class keeps track of the state of connectivity
* of a network interface. All state information for a network should
@@ -40,11 +41,16 @@
protected NetworkInfo mNetworkInfo;
protected Context mContext;
protected Handler mTarget;
+ protected String mInterfaceName;
+ protected String[] mDnsPropNames;
+ private boolean mPrivateDnsRouteSet;
+ protected int mDefaultGatewayAddr;
+ private boolean mDefaultRouteSet;
private boolean mTeardownRequested;
- private static boolean DBG = Config.LOGV;
+ private static boolean DBG = Config.LOGV;
private static final String TAG = "NetworkStateTracker";
-
+
public static final int EVENT_STATE_CHANGED = 1;
public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2;
/**
@@ -56,6 +62,7 @@
public static final int EVENT_CONFIGURATION_CHANGED = 4;
public static final int EVENT_ROAMING_CHANGED = 5;
public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
+ public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
public NetworkStateTracker(Context context,
Handler target,
@@ -67,6 +74,7 @@
mContext = context;
mTarget = target;
mTeardownRequested = false;
+
this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName);
}
@@ -75,19 +83,21 @@
}
/**
- * Return the list of DNS servers associated with this network.
- * @return a list of the IP addresses of the DNS servers available
- * for the network.
- */
- public abstract String[] getNameServers();
-
- /**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
public abstract String getTcpBufferSizesPropName();
/**
+ * Return the IP addresses of the DNS servers available for the mobile data
+ * network interface.
+ * @return a list of DNS addresses, with no holes.
+ */
+ public String[] getNameServers() {
+ return getNameServerList(mDnsPropNames);
+ }
+
+ /**
* Return the IP addresses of the DNS servers available for this
* network interface.
* @param propertyNames the names of the system properties whose values
@@ -112,6 +122,50 @@
return dnsAddresses;
}
+ public void addPrivateDnsRoutes() {
+ if (DBG) Log.d(TAG, "addPrivateDnsRoutes for " + this +
+ "(" + mInterfaceName + ")");
+ if (mInterfaceName != null && !mPrivateDnsRouteSet) {
+ for (String addrString : getNameServers()) {
+ int addr = NetworkUtils.lookupHost(addrString);
+ if (addr != -1) {
+ NetworkUtils.addHostRoute(mInterfaceName, addr);
+ }
+ }
+ mPrivateDnsRouteSet = true;
+ }
+ }
+
+ public void removePrivateDnsRoutes() {
+ if (DBG) Log.d(TAG, "removePrivateDnsRoutes for " + this +
+ "(" + mInterfaceName + ")");
+ // TODO - we should do this explicitly but the NetUtils api doesnt
+ // support this yet - must remove all. No worse than before
+ if (mInterfaceName != null && mPrivateDnsRouteSet) {
+ NetworkUtils.removeHostRoutes(mInterfaceName);
+ mPrivateDnsRouteSet = false;
+ }
+ }
+
+ public void addDefaultRoute() {
+ if (DBG) Log.d(TAG, "addDefaultRoute for " + this + "(" +
+ mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr);
+ if ((mInterfaceName != null) && (mDefaultGatewayAddr != 0) &&
+ mDefaultRouteSet == false) {
+ NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
+ mDefaultRouteSet = true;
+ }
+ }
+
+ public void removeDefaultRoute() {
+ if (DBG) Log.d(TAG, "removeDefaultRoute for " + this + "(" +
+ mInterfaceName + ")");
+ if (mInterfaceName != null && mDefaultRouteSet == true) {
+ NetworkUtils.removeDefaultRoute(mInterfaceName);
+ mDefaultRouteSet = false;
+ }
+ }
+
/**
* Reads the network specific TCP buffer sizes from SystemProperties
* net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
@@ -209,6 +263,7 @@
* @param extraInfo optional {@code String} providing extra information about the state change
*/
public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) {
+ if (DBG) Log.d(TAG, "setDetailed state, old ="+mNetworkInfo.getDetailedState()+" and new state="+state);
if (state != mNetworkInfo.getDetailedState()) {
boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
String lastReason = mNetworkInfo.getReason();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 1153648..a3ae01b 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -25,6 +25,9 @@
* {@hide}
*/
public class NetworkUtils {
+ /** Bring the named network interface up. */
+ public native static int enableInterface(String interfaceName);
+
/** Bring the named network interface down. */
public native static int disableInterface(String interfaceName);
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 421d013..298be3b 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -374,7 +374,7 @@
/**
* Creates a Uri which parses the given encoded URI string.
*
- * @param uriString an RFC 3296-compliant, encoded URI
+ * @param uriString an RFC 2396-compliant, encoded URI
* @throws NullPointerException if uriString is null
* @return Uri for this given uri string
*/
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index f4a2a6a..f6159de 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -54,7 +54,7 @@
static Pattern sAddressPattern = Pattern.compile(
/* scheme */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
/* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
- /* host */ "([-A-Za-z0-9%]+(?:\\.[-A-Za-z0-9%]+)*)?" +
+ /* host */ "([-A-Za-z0-9%_]+(?:\\.[-A-Za-z0-9%_]+)*)?" +
/* port */ "(?:\\:([0-9]+))?" +
/* path */ "(\\/?.*)?");
diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
index 8e759e2..0b30e58 100644
--- a/core/java/android/net/http/ConnectionThread.java
+++ b/core/java/android/net/http/ConnectionThread.java
@@ -32,8 +32,8 @@
static final int WAIT_TICK = 1000;
// Performance probe
- long mStartThreadTime;
long mCurrentThreadTime;
+ long mTotalThreadTime;
private boolean mWaiting;
private volatile boolean mRunning = true;
@@ -69,12 +69,21 @@
*/
public void run() {
android.os.Process.setThreadPriority(
+ android.os.Process.THREAD_PRIORITY_DEFAULT +
android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
- mStartThreadTime = -1;
- mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ // these are used to get performance data. When it is not in the timing,
+ // mCurrentThreadTime is 0. When it starts timing, mCurrentThreadTime is
+ // first set to -1, it will be set to the current thread time when the
+ // next request starts.
+ mCurrentThreadTime = 0;
+ mTotalThreadTime = 0;
while (mRunning) {
+ if (mCurrentThreadTime == -1) {
+ mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ }
+
Request request;
/* Get a request to process */
@@ -86,14 +95,14 @@
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: Waiting for work");
mWaiting = true;
try {
- if (mStartThreadTime != -1) {
- mCurrentThreadTime = SystemClock
- .currentThreadTimeMillis();
- }
mRequestFeeder.wait();
} catch (InterruptedException e) {
}
mWaiting = false;
+ if (mCurrentThreadTime != 0) {
+ mCurrentThreadTime = SystemClock
+ .currentThreadTimeMillis();
+ }
}
} else {
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
@@ -123,6 +132,12 @@
mConnection.closeConnection();
}
mConnection = null;
+
+ if (mCurrentThreadTime > 0) {
+ long start = mCurrentThreadTime;
+ mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ mTotalThreadTime += mCurrentThreadTime - start;
+ }
}
}
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index df4fff0..1b6568e 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -67,9 +67,6 @@
/** Set if I'm using a proxy server */
HttpHost mProxyHost;
- /** True if request is .html, .js, .css */
- boolean mHighPriority;
-
/** True if request has been cancelled */
volatile boolean mCancelled = false;
@@ -102,26 +99,29 @@
* @param eventHandler request will make progress callbacks on
* this interface
* @param headers reqeust headers
- * @param highPriority true for .html, css, .cs
*/
Request(String method, HttpHost host, HttpHost proxyHost, String path,
InputStream bodyProvider, int bodyLength,
EventHandler eventHandler,
- Map<String, String> headers, boolean highPriority) {
+ Map<String, String> headers) {
mEventHandler = eventHandler;
mHost = host;
mProxyHost = proxyHost;
mPath = path;
- mHighPriority = highPriority;
mBodyProvider = bodyProvider;
mBodyLength = bodyLength;
- if (bodyProvider == null) {
+ if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
mHttpRequest = new BasicHttpRequest(method, getUri());
} else {
mHttpRequest = new BasicHttpEntityEnclosingRequest(
method, getUri());
- setBodyProvider(bodyProvider, bodyLength);
+ // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
+ // By using BasicHttpEntityEnclosingRequest, it will set up the
+ // correct content-length, content-type and content-encoding.
+ if (bodyProvider != null) {
+ setBodyProvider(bodyProvider, bodyLength);
+ }
}
addHeader(HOST_HEADER, getHostPort());
@@ -255,6 +255,8 @@
// process gzip content encoding
Header contentEncoding = entity.getContentEncoding();
InputStream nis = null;
+ byte[] buf = null;
+ int count = 0;
try {
if (contentEncoding != null &&
contentEncoding.getValue().equals("gzip")) {
@@ -265,9 +267,8 @@
/* accumulate enough data to make it worth pushing it
* up the stack */
- byte[] buf = mConnection.getBuf();
+ buf = mConnection.getBuf();
int len = 0;
- int count = 0;
int lowWater = buf.length / 2;
while (len != -1) {
len = nis.read(buf, count, buf.length - count);
@@ -284,6 +285,10 @@
/* InflaterInputStream throws an EOFException when the
server truncates gzipped content. Handle this case
as we do truncated non-gzipped content: no error */
+ if (count > 0) {
+ // if there is uncommited content, we should commit them
+ mEventHandler.data(buf, count);
+ }
if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
} catch(IOException e) {
// don't throw if we have a non-OK status code
@@ -346,7 +351,7 @@
* for debugging
*/
public String toString() {
- return (mHighPriority ? "P*" : "") + mPath;
+ return mPath;
}
@@ -412,8 +417,7 @@
}
return status >= HttpStatus.SC_OK
&& status != HttpStatus.SC_NO_CONTENT
- && status != HttpStatus.SC_NOT_MODIFIED
- && status != HttpStatus.SC_RESET_CONTENT;
+ && status != HttpStatus.SC_NOT_MODIFIED;
}
/**
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 6a97951..190ae7a 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -419,6 +419,6 @@
mRequest = mRequestQueue.queueRequest(
mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
mBodyProvider,
- mBodyLength, mRequest.mHighPriority).mRequest;
+ mBodyLength).mRequest;
}
}
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index 66d5722..e14af66 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -57,9 +57,6 @@
*/
private LinkedHashMap<HttpHost, LinkedList<Request>> mPending;
- /* Support for notifying a client when queue is empty */
- private boolean mClientWaiting = false;
-
/** true if connected */
boolean mNetworkConnected = true;
@@ -245,7 +242,9 @@
public void startTiming() {
for (int i = 0; i < mConnectionCount; i++) {
- mThreads[i].mStartThreadTime = mThreads[i].mCurrentThreadTime;
+ ConnectionThread rt = mThreads[i];
+ rt.mCurrentThreadTime = -1;
+ rt.mTotalThreadTime = 0;
}
mTotalRequest = 0;
mTotalConnection = 0;
@@ -255,12 +254,14 @@
int totalTime = 0;
for (int i = 0; i < mConnectionCount; i++) {
ConnectionThread rt = mThreads[i];
- totalTime += (rt.mCurrentThreadTime - rt.mStartThreadTime);
- rt.mStartThreadTime = -1;
+ if (rt.mCurrentThreadTime != -1) {
+ totalTime += rt.mTotalThreadTime;
+ }
+ rt.mCurrentThreadTime = 0;
}
Log.d("Http", "Http thread used " + totalTime + " ms " + " for "
+ mTotalRequest + " requests and " + mTotalConnection
- + " connections");
+ + " new connections");
}
void logState() {
@@ -434,16 +435,14 @@
* data. Callbacks will be made on the supplied instance.
* @param bodyProvider InputStream providing HTTP body, null if none
* @param bodyLength length of body, must be 0 if bodyProvider is null
- * @param highPriority If true, queues before low priority
- * requests if possible
*/
public RequestHandle queueRequest(
String url, String method,
Map<String, String> headers, EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength, boolean highPriority) {
+ InputStream bodyProvider, int bodyLength) {
WebAddress uri = new WebAddress(url);
return queueRequest(url, uri, method, headers, eventHandler,
- bodyProvider, bodyLength, highPriority);
+ bodyProvider, bodyLength);
}
/**
@@ -456,14 +455,11 @@
* data. Callbacks will be made on the supplied instance.
* @param bodyProvider InputStream providing HTTP body, null if none
* @param bodyLength length of body, must be 0 if bodyProvider is null
- * @param highPriority If true, queues before low priority
- * requests if possible
*/
public RequestHandle queueRequest(
String url, WebAddress uri, String method, Map<String, String> headers,
EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength,
- boolean highPriority) {
+ InputStream bodyProvider, int bodyLength) {
if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri);
@@ -478,9 +474,9 @@
// set up request
req = new Request(method, httpHost, mProxyHost, uri.mPath, bodyProvider,
- bodyLength, eventHandler, headers, highPriority);
+ bodyLength, eventHandler, headers);
- queueRequest(req, highPriority);
+ queueRequest(req, false);
mActivePool.mTotalRequest++;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d40ea6b..b0fc78e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -662,6 +662,25 @@
public static final native int getBinderDeathObjectCount();
/**
+ * Primes the register map cache.
+ *
+ * Only works for classes in the bootstrap class loader. Does not
+ * cause classes to be loaded if they're not already present.
+ *
+ * The classAndMethodDesc argument is a concatentation of the VM-internal
+ * class descriptor, method name, and method descriptor. Examples:
+ * Landroid/os/Looper;.loop:()V
+ * Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
+ *
+ * @param classAndMethodDesc the method to prepare
+ *
+ * @hide
+ */
+ public static final boolean cacheRegisterMap(String classAndMethodDesc) {
+ return VMDebug.cacheRegisterMap(classAndMethodDesc);
+ }
+
+ /**
* API for gathering and querying instruction counts.
*
* Example usage:
diff --git a/core/java/android/os/Exec.java b/core/java/android/os/Exec.java
deleted file mode 100644
index a50d5fe..0000000
--- a/core/java/android/os/Exec.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import java.io.FileDescriptor;
-
-/**
- * @hide
- * Tools for executing commands. Not for public consumption.
- */
-
-public class Exec
-{
- /**
- * @param cmd The command to execute
- * @param arg0 The first argument to the command, may be null
- * @param arg1 the second argument to the command, may be null
- * @return the file descriptor of the started process.
- *
- */
- public static FileDescriptor createSubprocess(
- String cmd, String arg0, String arg1) {
- return createSubprocess(cmd, arg0, arg1, null);
- }
-
- /**
- * @param cmd The command to execute
- * @param arg0 The first argument to the command, may be null
- * @param arg1 the second argument to the command, may be null
- * @param processId A one-element array to which the process ID of the
- * started process will be written.
- * @return the file descriptor of the started process.
- *
- */
- public static native FileDescriptor createSubprocess(
- String cmd, String arg0, String arg1, int[] processId);
-
- public static native void setPtyWindowSize(FileDescriptor fd,
- int row, int col, int xpixel, int ypixel);
- /**
- * Causes the calling thread to wait for the process associated with the
- * receiver to finish executing.
- *
- * @return The exit value of the Process being waited on
- *
- */
- public static native int waitFor(int processId);
-}
-
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index d9804ea..38d252e 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -25,22 +25,35 @@
import java.util.HashMap;
public abstract class FileObserver {
- public static final int ACCESS = 0x00000001; /* File was accessed */
- public static final int MODIFY = 0x00000002; /* File was modified */
- public static final int ATTRIB = 0x00000004; /* Metadata changed */
- public static final int CLOSE_WRITE = 0x00000008; /* Writtable file was closed */
- public static final int CLOSE_NOWRITE = 0x00000010; /* Unwrittable file closed */
- public static final int OPEN = 0x00000020; /* File was opened */
- public static final int MOVED_FROM = 0x00000040; /* File was moved from X */
- public static final int MOVED_TO = 0x00000080; /* File was moved to Y */
- public static final int CREATE = 0x00000100; /* Subfile was created */
- public static final int DELETE = 0x00000200; /* Subfile was deleted */
- public static final int DELETE_SELF = 0x00000400; /* Self was deleted */
- public static final int MOVE_SELF = 0x00000800; /* Self was moved */
+ /** File was accessed */
+ public static final int ACCESS = 0x00000001;
+ /** File was modified */
+ public static final int MODIFY = 0x00000002;
+ /** Metadata changed */
+ public static final int ATTRIB = 0x00000004;
+ /** Writable file was closed */
+ public static final int CLOSE_WRITE = 0x00000008;
+ /** Unwrittable file closed */
+ public static final int CLOSE_NOWRITE = 0x00000010;
+ /** File was opened */
+ public static final int OPEN = 0x00000020;
+ /** File was moved from X */
+ public static final int MOVED_FROM = 0x00000040;
+ /** File was moved to Y */
+ public static final int MOVED_TO = 0x00000080;
+ /** Subfile was created */
+ public static final int CREATE = 0x00000100;
+ /** Subfile was deleted */
+ public static final int DELETE = 0x00000200;
+ /** Self was deleted */
+ public static final int DELETE_SELF = 0x00000400;
+ /** Self was moved */
+ public static final int MOVE_SELF = 0x00000800;
+
public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
| CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
| DELETE_SELF | MOVE_SELF;
-
+
private static final String LOG_TAG = "FileObserver";
private static class ObserverThread extends Thread {
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
index fb121bb..aebcb3c 100755
--- a/core/java/android/os/IHardwareService.aidl
+++ b/core/java/android/os/IHardwareService.aidl
@@ -20,9 +20,9 @@
interface IHardwareService
{
// Vibrator support
- void vibrate(long milliseconds);
+ void vibrate(long milliseconds, IBinder token);
void vibratePattern(in long[] pattern, int repeat, IBinder token);
- void cancelVibrate();
+ void cancelVibrate(IBinder token);
// flashlight support
boolean getFlashlightEnabled();
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 5486920..188e7ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
void setPokeLock(int pokey, IBinder lock, String tag);
+ int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
diff --git a/core/java/android/os/LatencyTimer.java b/core/java/android/os/LatencyTimer.java
new file mode 100644
index 0000000..ed2f0f9
--- /dev/null
+++ b/core/java/android/os/LatencyTimer.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.os;
+
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * A class to help with measuring latency in your code.
+ *
+ * Suggested usage:
+ * 1) Instanciate a LatencyTimer as a class field.
+ * private [static] LatencyTimer mLt = new LatencyTimer(100, 1000);
+ * 2) At various points in the code call sample with a string and the time delta to some fixed time.
+ * The string should be unique at each point of the code you are measuring.
+ * mLt.sample("before processing event", System.nanoTime() - event.getEventTimeNano());
+ * processEvent(event);
+ * mLt.sample("after processing event ", System.nanoTime() - event.getEventTimeNano());
+ *
+ * @hide
+ */
+public final class LatencyTimer
+{
+ final String TAG = "LatencyTimer";
+ final int mSampleSize;
+ final int mScaleFactor;
+ volatile HashMap<String, long[]> store = new HashMap<String, long[]>();
+
+ /**
+ * Creates a LatencyTimer object
+ * @param sampleSize number of samples to collect before printing out the average
+ * @param scaleFactor divisor used to make each sample smaller to prevent overflow when
+ * (sampleSize * average sample value)/scaleFactor > Long.MAX_VALUE
+ */
+ public LatencyTimer(int sampleSize, int scaleFactor) {
+ if (scaleFactor == 0) {
+ scaleFactor = 1;
+ }
+ mScaleFactor = scaleFactor;
+ mSampleSize = sampleSize;
+ }
+
+ /**
+ * Add a sample delay for averaging.
+ * @param tag string used for printing out the result. This should be unique at each point of
+ * this called.
+ * @param delta time difference from an unique point of reference for a particular iteration
+ */
+ public void sample(String tag, long delta) {
+ long[] array = getArray(tag);
+
+ // array[mSampleSize] holds the number of used entries
+ final int index = (int) array[mSampleSize]++;
+ array[index] = delta;
+ if (array[mSampleSize] == mSampleSize) {
+ long totalDelta = 0;
+ for (long d : array) {
+ totalDelta += d/mScaleFactor;
+ }
+ array[mSampleSize] = 0;
+ Log.i(TAG, tag + " average = " + totalDelta / mSampleSize);
+ }
+ }
+
+ private long[] getArray(String tag) {
+ long[] data = store.get(tag);
+ if (data == null) {
+ synchronized(store) {
+ data = store.get(tag);
+ if (data == null) {
+ data = new long[mSampleSize + 1];
+ store.put(tag, data);
+ data[mSampleSize] = 0;
+ }
+ }
+ }
+ return data;
+ }
+}
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index c14925c..03542dd 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -52,7 +52,7 @@
private static native void native_write(FileDescriptor fd, int address, byte[] buffer,
int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
- private static native boolean native_is_ashmem_region(FileDescriptor fd) throws IOException;
+ private static native int native_get_mapped_size(FileDescriptor fd) throws IOException;
private FileDescriptor mFD; // ashmem file descriptor
private int mAddress; // address of ashmem memory
@@ -300,7 +300,20 @@
* @hide
*/
public static boolean isMemoryFile(FileDescriptor fd) throws IOException {
- return native_is_ashmem_region(fd);
+ return (native_get_mapped_size(fd) >= 0);
+ }
+
+ /**
+ * Returns the size of the memory file, rounded up to a page boundary, that
+ * the file descriptor refers to, or -1 if the file descriptor does not
+ * refer to a memory file.
+ *
+ * @throws IOException If <code>fd</code> is not a valid file descriptor.
+ *
+ * @hide
+ */
+ public static int getMappedSize(FileDescriptor fd) throws IOException {
+ return native_get_mapped_size(fd);
}
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index bfcf2fc..d5934102 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -114,12 +114,14 @@
private static final int WAKE_BIT_SCREEN_DIM = 4;
private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+ private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
| WAKE_BIT_CPU_WEAK
| WAKE_BIT_SCREEN_DIM
| WAKE_BIT_SCREEN_BRIGHT
- | WAKE_BIT_KEYBOARD_BRIGHT;
+ | WAKE_BIT_KEYBOARD_BRIGHT
+ | WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Wake lock that ensures that the CPU is running. The screen might
@@ -147,6 +149,16 @@
public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
/**
+ * Wake lock that turns the screen off when the proximity sensor activates.
+ * Since not all devices have proximity sensors, use
+ * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
+ * this wake lock mode is supported.
+ *
+ * {@hide}
+ */
+ public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
+
+ /**
* Normally wake locks don't actually wake the device, they just cause
* it to remain on once it's already on. Think of the video player
* app as the normal behavior. Notifications that pop up and want
@@ -196,6 +208,7 @@
case SCREEN_DIM_WAKE_LOCK:
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
+ case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException();
@@ -365,7 +378,33 @@
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
+ * that are supported on the device.
+ * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
+ * is supported:
+ *
+ * {@samplecode
+ * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ * int supportedFlags = pm.getSupportedWakeLockFlags();
+ * boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+ * == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
+ * }
+ *
+ * @return the set of supported WakeLock flags.
+ *
+ * {@hide}
+ */
+ public int getSupportedWakeLockFlags()
+ {
+ try {
+ return mService.getSupportedWakeLockFlags();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
private PowerManager()
{
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 4805193..980cff3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -739,7 +739,7 @@
public static final native void sendSignal(int pid, int signal);
/** @hide */
- public static final native int getFreeMemory();
+ public static final native long getFreeMemory();
/** @hide */
public static final native void readProcLines(String path,
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 584224f..b74af16 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -22,7 +22,7 @@
* Takes care of the grunt work of maintaining a list of remote interfaces,
* typically for the use of performing callbacks from a
* {@link android.app.Service} to its clients. In particular, this:
- *
+ *
* <ul>
* <li> Keeps track of a set of registered {@link IInterface} callbacks,
* taking care to identify them through their underlying unique {@link IBinder}
@@ -34,13 +34,13 @@
* multithreaded incoming calls, and a thread-safe way to iterate over a
* snapshot of the list without holding its lock.
* </ul>
- *
+ *
* <p>To use this class, simply create a single instance along with your
* service, and call its {@link #register} and {@link #unregister} methods
* as client register and unregister with your service. To call back on to
* the registered clients, use {@link #beginBroadcast},
* {@link #getBroadcastItem}, and {@link #finishBroadcast}.
- *
+ *
* <p>If a registered callback's process goes away, this class will take
* care of automatically removing it from the list. If you want to do
* additional work in this situation, you can create a subclass that
@@ -52,7 +52,7 @@
private Object[] mActiveBroadcast;
private int mBroadcastCount = -1;
private boolean mKilled = false;
-
+
private final class Callback implements IBinder.DeathRecipient {
final E mCallback;
final Object mCookie;
@@ -61,7 +61,7 @@
mCallback = callback;
mCookie = cookie;
}
-
+
public void binderDied() {
synchronized (mCallbacks) {
mCallbacks.remove(mCallback.asBinder());
@@ -69,7 +69,7 @@
onCallbackDied(mCallback, mCookie);
}
}
-
+
/**
* Simple version of {@link RemoteCallbackList#register(E, Object)}
* that does not take a cookie object.
@@ -86,19 +86,20 @@
* object is already in the list), then it will be left as-is.
* Registrations are not counted; a single call to {@link #unregister}
* will remove a callback after any number calls to register it.
- *
+ *
* @param callback The callback interface to be added to the list. Must
* not be null -- passing null here will cause a NullPointerException.
* Most services will want to check for null before calling this with
* an object given from a client, so that clients can't crash the
* service with bad data.
+ *
* @param cookie Optional additional data to be associated with this
* callback.
*
* @return Returns true if the callback was successfully added to the list.
* Returns false if it was not added, either because {@link #kill} had
* previously been called or the callback's process has gone away.
- *
+ *
* @see #unregister
* @see #kill
* @see #onCallbackDied
@@ -119,7 +120,7 @@
}
}
}
-
+
/**
* Remove from the list a callback that was previously added with
* {@link #register}. This uses the
@@ -127,14 +128,14 @@
* find the previous registration.
* Registrations are not counted; a single unregister call will remove
* a callback after any number calls to {@link #register} for it.
- *
+ *
* @param callback The callback to be removed from the list. Passing
* null here will cause a NullPointerException, so you will generally want
* to check for null before calling.
- *
+ *
* @return Returns true if the callback was found and unregistered. Returns
* false if the given callback was not found on the list.
- *
+ *
* @see #register
*/
public boolean unregister(E callback) {
@@ -147,13 +148,13 @@
return false;
}
}
-
+
/**
* Disable this callback list. All registered callbacks are unregistered,
* and the list is disabled so that future calls to {@link #register} will
* fail. This should be used when a Service is stopping, to prevent clients
* from registering callbacks after it is stopped.
- *
+ *
* @see #register
*/
public void kill() {
@@ -165,7 +166,7 @@
mKilled = true;
}
}
-
+
/**
* Old version of {@link #onCallbackDied(E, Object)} that
* does not provide a cookie.
@@ -190,7 +191,7 @@
public void onCallbackDied(E callback, Object cookie) {
onCallbackDied(callback);
}
-
+
/**
* Prepare to start making calls to the currently registered callbacks.
* This creates a copy of the callback list, which you can retrieve items
@@ -199,12 +200,12 @@
* same thread (usually by scheduling with {@link Handler}) or
* do your own synchronization. You must call {@link #finishBroadcast}
* when done.
- *
+ *
* <p>A typical loop delivering a broadcast looks like this:
- *
+ *
* <pre>
* int i = callbacks.beginBroadcast();
- * while (i > 0) {
+ * while (i > 0) {
* i--;
* try {
* callbacks.getBroadcastItem(i).somethingHappened();
@@ -214,11 +215,11 @@
* }
* }
* callbacks.finishBroadcast();</pre>
- *
+ *
* @return Returns the number of callbacks in the broadcast, to be used
* with {@link #getBroadcastItem} to determine the range of indices you
* can supply.
- *
+ *
* @see #getBroadcastItem
* @see #finishBroadcast
*/
@@ -244,26 +245,26 @@
return i;
}
}
-
+
/**
* Retrieve an item in the active broadcast that was previously started
* with {@link #beginBroadcast}. This can <em>only</em> be called after
* the broadcast is started, and its data is no longer valid after
* calling {@link #finishBroadcast}.
- *
+ *
* <p>Note that it is possible for the process of one of the returned
* callbacks to go away before you call it, so you will need to catch
* {@link RemoteException} when calling on to the returned object.
* The callback list itself, however, will take care of unregistering
* these objects once it detects that it is no longer valid, so you can
* handle such an exception by simply ignoring it.
- *
+ *
* @param index Which of the registered callbacks you would like to
* retrieve. Ranges from 0 to 1-{@link #beginBroadcast}.
- *
+ *
* @return Returns the callback interface that you can call. This will
* always be non-null.
- *
+ *
* @see #beginBroadcast
*/
public E getBroadcastItem(int index) {
@@ -279,12 +280,12 @@
public Object getBroadcastCookie(int index) {
return ((Callback)mActiveBroadcast[index]).mCookie;
}
-
+
/**
* Clean up the state of a broadcast previously initiated by calling
* {@link #beginBroadcast}. This must always be called when you are done
* with a broadcast.
- *
+ *
* @see #beginBroadcast
*/
public void finishBroadcast() {
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 2b57b39..2dd6749 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -30,7 +30,13 @@
* backwards or forwards unpredictably. This clock should only be used
* when correspondence with real-world dates and times is important, such
* as in a calendar or alarm clock application. Interval or elapsed
- * time measurements should use a different clock.
+ * time measurements should use a different clock. If you are using
+ * System.currentTimeMillis(), consider listening to the
+ * {@link android.content.Intent#ACTION_TIME_TICK ACTION_TIME_TICK},
+ * {@link android.content.Intent#ACTION_TIME_CHANGED ACTION_TIME_CHANGED}
+ * and {@link android.content.Intent#ACTION_TIMEZONE_CHANGED
+ * ACTION_TIMEZONE_CHANGED} {@link android.content.Intent Intent}
+ * broadcasts to find out when the time changes.
*
* <li> <p> {@link #uptimeMillis} is counted in milliseconds since the
* system was booted. This clock stops when the system enters deep
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index c3ae3c2..4a036ec 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -30,6 +30,9 @@
private static native String native_get(String key);
private static native String native_get(String key, String def);
+ private static native int native_get_int(String key, int def);
+ private static native long native_get_long(String key, long def);
+ private static native boolean native_get_boolean(String key, boolean def);
private static native void native_set(String key, String def);
/**
@@ -65,11 +68,10 @@
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static int getInt(String key, int def) {
- try {
- return Integer.parseInt(get(key));
- } catch (NumberFormatException e) {
- return def;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ return native_get_int(key, def);
}
/**
@@ -81,11 +83,10 @@
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static long getLong(String key, long def) {
- try {
- return Long.parseLong(get(key));
- } catch (NumberFormatException e) {
- return def;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ return native_get_long(key, def);
}
/**
@@ -102,27 +103,10 @@
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static boolean getBoolean(String key, boolean def) {
- String value = get(key);
- // Deal with these quick cases first: not found, 0 and 1
- if (value.equals("")) {
- return def;
- } else if (value.equals("0")) {
- return false;
- } else if (value.equals("1")) {
- return true;
- // now for slower (and hopefully less common) cases
- } else if (value.equalsIgnoreCase("n") ||
- value.equalsIgnoreCase("no") ||
- value.equalsIgnoreCase("false") ||
- value.equalsIgnoreCase("off")) {
- return false;
- } else if (value.equalsIgnoreCase("y") ||
- value.equalsIgnoreCase("yes") ||
- value.equalsIgnoreCase("true") ||
- value.equalsIgnoreCase("on")) {
- return true;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
- return def;
+ return native_get_boolean(key, def);
}
/**
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 0f75289..51dcff1 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -24,6 +24,7 @@
public class Vibrator
{
IHardwareService mService;
+ private final Binder mToken = new Binder();
/** @hide */
public Vibrator()
@@ -40,7 +41,7 @@
public void vibrate(long milliseconds)
{
try {
- mService.vibrate(milliseconds);
+ mService.vibrate(milliseconds, mToken);
} catch (RemoteException e) {
}
}
@@ -65,7 +66,7 @@
// anyway
if (repeat < pattern.length) {
try {
- mService.vibratePattern(pattern, repeat, new Binder());
+ mService.vibratePattern(pattern, repeat, mToken);
} catch (RemoteException e) {
}
} else {
@@ -79,7 +80,7 @@
public void cancel()
{
try {
- mService.cancelVibrate();
+ mService.cancelVibrate(mToken);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index 1a287c8..7920543 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -223,6 +223,7 @@
return true;
}
+ // This can be removed when the old CalendarSyncAdapter is removed.
public static boolean populateComponent(Cursor cursor,
ICalendar.Component component) {
@@ -292,6 +293,64 @@
return true;
}
+public static boolean populateComponent(ContentValues values,
+ ICalendar.Component component) {
+ long dtstart = -1;
+ if (values.containsKey(Calendar.Events.DTSTART)) {
+ dtstart = values.getAsLong(Calendar.Events.DTSTART);
+ }
+ String duration = values.getAsString(Calendar.Events.DURATION);
+ String tzid = values.getAsString(Calendar.Events.EVENT_TIMEZONE);
+ String rruleStr = values.getAsString(Calendar.Events.RRULE);
+ String rdateStr = values.getAsString(Calendar.Events.RDATE);
+ String exruleStr = values.getAsString(Calendar.Events.EXRULE);
+ String exdateStr = values.getAsString(Calendar.Events.EXDATE);
+ boolean allDay = values.getAsInteger(Calendar.Events.ALL_DAY) == 1;
+
+ if ((dtstart == -1) ||
+ (TextUtils.isEmpty(duration))||
+ ((TextUtils.isEmpty(rruleStr))&&
+ (TextUtils.isEmpty(rdateStr)))) {
+ // no recurrence.
+ return false;
+ }
+
+ ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
+ Time dtstartTime = null;
+ if (!TextUtils.isEmpty(tzid)) {
+ if (!allDay) {
+ dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
+ }
+ dtstartTime = new Time(tzid);
+ } else {
+ // use the "floating" timezone
+ dtstartTime = new Time(Time.TIMEZONE_UTC);
+ }
+
+ dtstartTime.set(dtstart);
+ // make sure the time is printed just as a date, if all day.
+ // TODO: android.pim.Time really should take care of this for us.
+ if (allDay) {
+ dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
+ dtstartTime.allDay = true;
+ dtstartTime.hour = 0;
+ dtstartTime.minute = 0;
+ dtstartTime.second = 0;
+ }
+
+ dtstartProp.setValue(dtstartTime.format2445());
+ component.addProperty(dtstartProp);
+ ICalendar.Property durationProp = new ICalendar.Property("DURATION");
+ durationProp.setValue(duration);
+ component.addProperty(durationProp);
+
+ addPropertiesForRuleStr(component, "RRULE", rruleStr);
+ addPropertyForDateStr(component, "RDATE", rdateStr);
+ addPropertiesForRuleStr(component, "EXRULE", exruleStr);
+ addPropertyForDateStr(component, "EXDATE", exdateStr);
+ return true;
+ }
+
private static void addPropertiesForRuleStr(ICalendar.Component component,
String propertyName,
String ruleStr) {
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
new file mode 100644
index 0000000..46725d3
--- /dev/null
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -0,0 +1,1244 @@
+/*
+ * 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.AbstractSyncableContentProvider;
+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.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+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";
+
+ /**
+ * @hide only for testing
+ */
+ static public class PhoneData {
+ public final int type;
+ public final String data;
+ public final String label;
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public PhoneData(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 PhoneData) {
+ return false;
+ }
+ PhoneData phoneData = (PhoneData)obj;
+ return (type == phoneData.type && data.equals(phoneData.data) &&
+ label.equals(phoneData.label) && isPrimary == phoneData.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 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.
+ public final int type;
+ public final String data;
+ // Used only when TYPE 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 ContactMethod(int kind, int type, String data, String label,
+ boolean isPrimary) {
+ this.kind = kind;
+ this.type = type;
+ this.data = data;
+ this.label = data;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ContactMethod) {
+ return false;
+ }
+ ContactMethod contactMethod = (ContactMethod)obj;
+ return (kind == contactMethod.kind && type == contactMethod.type &&
+ data.equals(contactMethod.data) && label.equals(contactMethod.label) &&
+ isPrimary == contactMethod.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("kind: %d, type: %d, data: %s, label: %s, isPrimary: %s",
+ kind, type, data, label, isPrimary);
+ }
+ }
+
+ /**
+ * @hide only for testing
+ */
+ static public class OrganizationData {
+ public final int type;
+ public final String companyName;
+ // can be changed in some VCard format.
+ public String positionName;
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public OrganizationData(int type, String companyName, String positionName,
+ boolean isPrimary) {
+ this.type = type;
+ this.companyName = companyName;
+ this.positionName = positionName;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof OrganizationData) {
+ return false;
+ }
+ OrganizationData organization = (OrganizationData)obj;
+ return (type == organization.type && companyName.equals(organization.companyName) &&
+ positionName.equals(organization.positionName) &&
+ isPrimary == organization.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, company: %s, position: %s, isPrimary: %s",
+ type, companyName, positionName, isPrimary);
+ }
+ }
+
+ static class Property {
+ private String mPropertyName;
+ private Map<String, Collection<String>> mParameterMap =
+ new HashMap<String, Collection<String>>();
+ private List<String> mPropertyValueList = new ArrayList<String>();
+ private byte[] mPropertyBytes;
+
+ public Property() {
+ clear();
+ }
+
+ public void setPropertyName(final String propertyName) {
+ mPropertyName = propertyName;
+ }
+
+ public void addParameter(final String paramName, final String paramValue) {
+ Collection<String> values;
+ if (mParameterMap.containsKey(paramName)) {
+ if (paramName.equals("TYPE")) {
+ values = new HashSet<String>();
+ } else {
+ values = new ArrayList<String>();
+ }
+ mParameterMap.put(paramName, values);
+ } else {
+ values = mParameterMap.get(paramName);
+ }
+ }
+
+ public void addToPropertyValueList(final String propertyValue) {
+ mPropertyValueList.add(propertyValue);
+ }
+
+ public void setPropertyBytes(final byte[] propertyBytes) {
+ mPropertyBytes = propertyBytes;
+ }
+
+ public final Collection<String> getParameters(String type) {
+ return mParameterMap.get(type);
+ }
+
+ public final List<String> getPropertyValueList() {
+ return mPropertyValueList;
+ }
+
+ public void clear() {
+ mPropertyName = null;
+ mParameterMap.clear();
+ mPropertyValueList.clear();
+ }
+ }
+
+ private String mName;
+ private String mPhoneticName;
+ // private String mPhotoType;
+ private byte[] mPhotoBytes;
+ private List<String> mNotes;
+ private List<PhoneData> mPhoneList;
+ private List<ContactMethod> mContactMethodList;
+ private List<OrganizationData> mOrganizationList;
+ private Map<String, List<String>> mExtensionMap;
+
+ private int mNameOrderType;
+
+ /* 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;
+
+ // 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.
+ private boolean mPrefIsSet_Address;
+ private boolean mPrefIsSet_Phone;
+ private boolean mPrefIsSet_Email;
+ private boolean mPrefIsSet_Organization;
+
+ public ContactStruct() {
+ mNameOrderType = VCardConfig.NAME_ORDER_TYPE_DEFAULT;
+ }
+
+ 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;
+ }
+
+ /**
+ * @hide only for test
+ */
+ public final byte[] getPhotoBytes() {
+ return mPhotoBytes;
+ }
+
+ /**
+ * @hide only for test
+ */
+ public final List<String> getNotes() {
+ return mNotes;
+ }
+
+ /**
+ * @hide only for test
+ */
+ public final List<PhoneData> getPhoneList() {
+ return mPhoneList;
+ }
+
+ /**
+ * @hide only for test
+ */
+ public final List<ContactMethod> getContactMethodList() {
+ return mContactMethodList;
+ }
+
+ /**
+ * @hide only for test
+ */
+ 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.
+ * @param data phone number
+ * @param type type col of content://contacts/phones
+ * @param label lable col of content://contacts/phones
+ */
+ private void addPhone(int type, String data, String label, boolean isPrimary){
+ if (mPhoneList == null) {
+ mPhoneList = new ArrayList<PhoneData>();
+ }
+ StringBuilder builder = new StringBuilder();
+ String trimed = data.trim();
+ int length = trimed.length();
+ for (int i = 0; i < length; i++) {
+ char ch = trimed.charAt(i);
+ if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
+ builder.append(ch);
+ }
+ }
+
+ PhoneData phoneData = new PhoneData(type,
+ PhoneNumberUtils.formatNumber(builder.toString()),
+ label, isPrimary);
+
+ 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>();
+ }
+ mContactMethodList.add(new ContactMethod(kind, type, data, label, isPrimary));
+ }
+
+ /**
+ * Add a Organization info to organizationList.
+ */
+ private void addOrganization(int type, String companyName, String positionName,
+ boolean isPrimary) {
+ if (mOrganizationList == null) {
+ mOrganizationList = new ArrayList<OrganizationData>();
+ }
+ mOrganizationList.add(new OrganizationData(type, companyName, positionName, isPrimary));
+ }
+
+ /**
+ * Set "position" value to the appropriate data. If there's more than one
+ * OrganizationData objects, the value is set to the last one. If there's no
+ * OrganizationData object, a new OrganizationData is created, whose company name is
+ * empty.
+ *
+ * TODO: incomplete logic. fix this:
+ *
+ * e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not
+ * know how to handle it in general cases...
+ * ----
+ * TITLE:Software Engineer
+ * ORG:Google
+ * ----
+ */
+ private void setPosition(String positionValue) {
+ if (mOrganizationList == null) {
+ mOrganizationList = new ArrayList<OrganizationData>();
+ }
+ int size = mOrganizationList.size();
+ if (size == 0) {
+ addOrganization(Contacts.OrganizationColumns.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) {
+ 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 (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("],");
+ }
+
+ 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 "";
+ }
+ }
+
+ public void addProperty(Property property) {
+ String propName = property.mPropertyName;
+ final Map<String, Collection<String>> paramMap = property.mParameterMap;
+ final List<String> propValueList = property.mPropertyValueList;
+ byte[] propBytes = property.mPropertyBytes;
+
+ if (propValueList.size() == 0) {
+ return;
+ }
+
+ String propValue = listToString(propValueList);
+
+ 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;
+ } else if (propName.equals("N")) {
+ mTmpNameFromNProperty = getNameFromNProperty(propValueList, mNameOrderType);
+ } else if (propName.equals("SORT-STRING")) {
+ mPhoneticName = 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();
+ }
+ } else {
+ addExtension(propName, paramMap, propValueList);
+ }
+ } else if (propName.equals("ADR")) {
+ boolean valuesAreAllEmpty = true;
+ for (String value : propValueList) {
+ if (value.length() > 0) {
+ valuesAreAllEmpty = false;
+ break;
+ }
+ }
+ if (valuesAreAllEmpty) {
+ return;
+ }
+
+ int kind = Contacts.KIND_POSTAL;
+ int type = -1;
+ String label = "";
+ boolean isPrimary = false;
+ Collection<String> typeCollection = paramMap.get("TYPE");
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals("PREF") && !mPrefIsSet_Address) {
+ // Only first "PREF" is considered.
+ mPrefIsSet_Address = true;
+ isPrimary = true;
+ } else if (typeString.equalsIgnoreCase("HOME")) {
+ type = Contacts.ContactMethodsColumns.TYPE_HOME;
+ label = "";
+ } else if (typeString.equalsIgnoreCase("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;
+ 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) {
+ // 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;
+ label = typeString;
+ }
+ }
+ }
+ // We use "HOME" as default
+ if (type < 0) {
+ type = Contacts.ContactMethodsColumns.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;
+ boolean isPrimary = false;
+
+ Collection<String> typeCollection = paramMap.get("TYPE");
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals("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());
+ if (iter.hasNext()) {
+ 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.
+ Collection<String> paramMapValue = paramMap.get("VALUE");
+ if (paramMapValue != null && paramMapValue.contains("URL")) {
+ // TODO: do something.
+ } 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();
+ }*/
+ }
+ } 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;
+ boolean isPrimary = false;
+ boolean isFax = false;
+ Collection<String> typeCollection = paramMap.get("TYPE");
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals("PREF") && !mPrefIsSet_Phone) {
+ // Only first "PREF" is considered.
+ mPrefIsSet_Phone = true;
+ 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;
+ }
+ }
+ }
+ if (type < 0) {
+ type = Contacts.PhonesColumns.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);
+ } 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);
+ } else if (propName.equals("URL")) {
+ addExtension(propName, paramMap, propValueList);
+ } 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;
+ } else {
+ // Unknown X- words and IANA token.
+ addExtension(propName, paramMap, propValueList);
+ }
+ }
+
+ public String displayString() {
+ if (mName.length() > 0) {
+ return mName;
+ }
+ 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 "";
+ }
+
+ /**
+ * 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();
+ }
+
+ // 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 there is no "PREF", we choose the first entries as primary.
+ if (!mPrefIsSet_Phone && mPhoneList != null && mPhoneList.size() > 0) {
+ 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_Email && mContactMethodList != null) {
+ for (ContactMethod contactMethod : mContactMethodList) {
+ if (contactMethod.kind == Contacts.KIND_EMAIL) {
+ contactMethod.isPrimary = true;
+ break;
+ }
+ }
+ }
+ 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();
+ try {
+ pushIntoContentProviderOrResolver(provider, myContactsGroupId);
+ successful = true;
+ } finally {
+ provider.endBatch(successful);
+ }
+ }
+
+ public boolean isIgnorable() {
+ return TextUtils.isEmpty(mName) &&
+ TextUtils.isEmpty(mPhoneticName) &&
+ (mPhoneList == null || mPhoneList.size() == 0) &&
+ (mContactMethodList == null || mContactMethodList.size() == 0);
+ }
+
+ private String listToString(List<String> list){
+ final int size = list.size();
+ if (size > 1) {
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+ for (String type : list) {
+ builder.append(type);
+ if (i < size - 1) {
+ builder.append(";");
+ }
+ }
+ return builder.toString();
+ } else if (size == 1) {
+ return list.get(0);
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/EntryCommitter.java b/core/java/android/pim/vcard/EntryCommitter.java
new file mode 100644
index 0000000..e26fac5
--- /dev/null
+++ b/core/java/android/pim/vcard/EntryCommitter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.AbstractSyncableContentProvider;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.IContentProvider;
+import android.provider.Contacts;
+import android.util.Log;
+
+/**
+ * EntryHandler implementation which commits the entry to Contacts Provider
+ */
+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 onEntryCreated(final ContactStruct contactStruct) {
+ long start = System.currentTimeMillis();
+ if (mProvider != null) {
+ contactStruct.pushIntoAbstractSyncableContentProvider(
+ mProvider, mMyContactsGroupId);
+ } else {
+ 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
new file mode 100644
index 0000000..4015cb5
--- /dev/null
+++ b/core/java/android/pim/vcard/EntryHandler.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Unlike VCardBuilderBase, this (and 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?
+ */
+ public void onFinal();
+
+ /**
+ * The method called when one VCard entry is successfully created
+ */
+ public void onEntryCreated(final ContactStruct entry);
+}
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
new file mode 100644
index 0000000..e1c4b33
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -0,0 +1,64 @@
+/*
+ * 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 java.util.List;
+
+public interface VCardBuilder {
+ void start();
+
+ void end();
+
+ /**
+ * BEGIN:VCARD
+ */
+ void startRecord(String type);
+
+ /** END:VXX */
+ void endRecord();
+
+ void startProperty();
+
+ void endProperty();
+
+ /**
+ * @param group
+ */
+ void propertyGroup(String group);
+
+ /**
+ * @param name
+ * N <br>
+ * N
+ */
+ void propertyName(String name);
+
+ /**
+ * @param type
+ * LANGUAGE \ ENCODING <br>
+ * ;LANGUage= \ ;ENCODING=
+ */
+ void propertyParamType(String type);
+
+ /**
+ * @param value
+ * FR-EN \ GBK <br>
+ * FR-EN \ GBK
+ */
+ void propertyParamValue(String value);
+
+ void propertyValues(List<String> values);
+}
diff --git a/core/java/android/pim/vcard/VCardBuilderCollection.java b/core/java/android/pim/vcard/VCardBuilderCollection.java
new file mode 100644
index 0000000..e3985b6
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardBuilderCollection.java
@@ -0,0 +1,99 @@
+/*
+ * 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 java.util.Collection;
+import java.util.List;
+
+public class VCardBuilderCollection implements VCardBuilder {
+
+ private final Collection<VCardBuilder> mVCardBuilderCollection;
+
+ public VCardBuilderCollection(Collection<VCardBuilder> vBuilderCollection) {
+ mVCardBuilderCollection = vBuilderCollection;
+ }
+
+ public Collection<VCardBuilder> getVCardBuilderBaseCollection() {
+ return mVCardBuilderCollection;
+ }
+
+ public void start() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.start();
+ }
+ }
+
+ public void end() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.end();
+ }
+ }
+
+ public void startRecord(String type) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.startRecord(type);
+ }
+ }
+
+ public void endRecord() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.endRecord();
+ }
+ }
+
+ public void startProperty() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.startProperty();
+ }
+ }
+
+
+ public void endProperty() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.endProperty();
+ }
+ }
+
+ public void propertyGroup(String group) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyGroup(group);
+ }
+ }
+
+ public void propertyName(String name) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyName(name);
+ }
+ }
+
+ public void propertyParamType(String type) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyParamType(type);
+ }
+ }
+
+ public void propertyParamValue(String value) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyParamValue(value);
+ }
+ }
+
+ public void propertyValues(List<String> values) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyValues(values);
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
new file mode 100644
index 0000000..fef9dba
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardConfig.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.pim.vcard;
+
+/**
+ * The class representing VCard related configurations
+ */
+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 =
+ LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
+
+ // 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;
+
+ protected static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
+
+ // 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;
+
+ /**
+ * @hide temporal. may be deleted
+ */
+ public static boolean showPerformanceLog() {
+ return (LOG_LEVEL & LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
+ }
+
+ private VCardConfig() {
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java
new file mode 100644
index 0000000..4025f6c
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardDataBuilder.java
@@ -0,0 +1,319 @@
+/*
+ * 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.util.CharsetUtils;
+import android.util.Log;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.net.QuotedPrintableCodec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * VBuilder for VCard. VCard may contain big photo images encoded by BASE64,
+ * If we store all VNode entries in memory like VDataBuilder.java,
+ * OutOfMemoryError may be thrown. Thus, this class push each VCard entry into
+ * ContentResolver immediately.
+ */
+public class VCardDataBuilder implements VCardBuilder {
+ static private String LOG_TAG = "VCardDataBuilder";
+
+ /**
+ * If there's no other information available, this class uses this charset for encoding
+ * byte arrays.
+ */
+ static public String TARGET_CHARSET = "UTF-8";
+
+ private ContactStruct.Property mCurrentProperty = new ContactStruct.Property();
+ private ContactStruct mCurrentContactStruct;
+ private String mParamType;
+
+ /**
+ * The charset using which VParser parses the text.
+ */
+ private String mSourceCharset;
+
+ /**
+ * The charset with which byte array is encoded to String.
+ */
+ private String mTargetCharset;
+ private boolean mStrictLineBreakParsing;
+
+ private int mNameOrderType;
+
+ // Just for testing.
+ private long mTimePushIntoContentResolver;
+
+ private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
+
+ public VCardDataBuilder() {
+ this(null, null, false, VCardConfig.NAME_ORDER_TYPE_DEFAULT);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(int nameOrderType) {
+ this(null, null, false, nameOrderType);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(String charset,
+ boolean strictLineBreakParsing,
+ int nameOrderType) {
+ this(null, charset, strictLineBreakParsing, nameOrderType);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(String sourceCharset,
+ String targetCharset,
+ boolean strictLineBreakParsing,
+ int nameOrderType) {
+ if (sourceCharset != null) {
+ mSourceCharset = sourceCharset;
+ } else {
+ mSourceCharset = VCardConfig.DEFAULT_CHARSET;
+ }
+ if (targetCharset != null) {
+ mTargetCharset = targetCharset;
+ } else {
+ mTargetCharset = TARGET_CHARSET;
+ }
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ mNameOrderType = nameOrderType;
+ }
+
+ public void addEntryHandler(EntryHandler entryHandler) {
+ mEntryHandlers.add(entryHandler);
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onFinal();
+ }
+ }
+
+ /**
+ * Assume that VCard is not nested. In other words, this code does not accept
+ */
+ public void startRecord(String type) {
+ // TODO: add the method clear() instead of using null for reducing GC?
+ if (mCurrentContactStruct != null) {
+ // This means startRecord() is called inside startRecord() - endRecord() block.
+ // TODO: should throw some Exception
+ Log.e(LOG_TAG, "Nested VCard code is not supported now.");
+ }
+ if (!type.equalsIgnoreCase("VCARD")) {
+ // TODO: add test case for this
+ Log.e(LOG_TAG, "This is not VCARD!");
+ }
+
+ mCurrentContactStruct = new ContactStruct(mNameOrderType);
+ }
+
+ public void endRecord() {
+ mCurrentContactStruct.consolidateFields();
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onEntryCreated(mCurrentContactStruct);
+ }
+ mCurrentContactStruct = null;
+ }
+
+ public void startProperty() {
+ mCurrentProperty.clear();
+ }
+
+ public void endProperty() {
+ mCurrentContactStruct.addProperty(mCurrentProperty);
+ }
+
+ public void propertyName(String name) {
+ mCurrentProperty.setPropertyName(name);
+ }
+
+ public void propertyGroup(String group) {
+ // ContactStruct does not support Group.
+ }
+
+ public void propertyParamType(String type) {
+ if (mParamType != null) {
+ Log.e(LOG_TAG,
+ "propertyParamType() is called more than once " +
+ "before propertyParamValue() is called");
+ }
+ mParamType = type;
+ }
+
+ public void propertyParamValue(String value) {
+ if (mParamType == null) {
+ mParamType = "TYPE";
+ }
+ mCurrentProperty.addParameter(mParamType, value);
+ mParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetCharset) {
+ if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
+ return originalString;
+ }
+ Charset charset = Charset.forName(mSourceCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return null;
+ }
+ }
+
+ private String handleOneValue(String value, String targetCharset, String encoding) {
+ if (encoding != null) {
+ if (encoding.equals("BASE64") || encoding.equals("B")) {
+ mCurrentProperty.setPropertyBytes(Base64.decodeBase64(value.getBytes()));
+ return value;
+ } else if (encoding.equals("QUOTED-PRINTABLE")) {
+ // "= " -> " ", "=\t" -> "\t".
+ // Previous code had done this replacement. Keep on the safe side.
+ StringBuilder builder = new StringBuilder();
+ int length = value.length();
+ for (int i = 0; i < length; i++) {
+ char ch = value.charAt(i);
+ if (ch == '=' && i < length - 1) {
+ char nextCh = value.charAt(i + 1);
+ if (nextCh == ' ' || nextCh == '\t') {
+
+ builder.append(nextCh);
+ i++;
+ continue;
+ }
+ }
+ builder.append(ch);
+ }
+ String quotedPrintable = builder.toString();
+
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ builder = new StringBuilder();
+ length = quotedPrintable.length();
+ ArrayList<String> list = new ArrayList<String>();
+ for (int i = 0; i < length; i++) {
+ char ch = quotedPrintable.charAt(i);
+ if (ch == '\n') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else if (ch == '\r') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ if (i < length - 1) {
+ char nextCh = quotedPrintable.charAt(i + 1);
+ if (nextCh == '\n') {
+ i++;
+ }
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ String finalLine = builder.toString();
+ if (finalLine.length() > 0) {
+ list.add(finalLine);
+ }
+ lines = list.toArray(new String[0]);
+ }
+
+ builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes;
+ try {
+ bytes = builder.toString().getBytes(mSourceCharset);
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
+ bytes = builder.toString().getBytes();
+ }
+
+ try {
+ bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
+ } catch (DecoderException e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
+ return "";
+ }
+
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return new String(bytes);
+ }
+ }
+ // Unknown encoding. Fall back to default.
+ }
+ return encodeString(value, targetCharset);
+ }
+
+ public void propertyValues(List<String> values) {
+ if (values == null || values.size() == 0) {
+ return;
+ }
+
+ final Collection<String> charsetCollection = mCurrentProperty.getParameters("CHARSET");
+ 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);
+
+ if (targetCharset == null || targetCharset.length() == 0) {
+ targetCharset = mTargetCharset;
+ }
+
+ for (String value : values) {
+ mCurrentProperty.addToPropertyValueList(
+ handleOneValue(value, targetCharset, encoding));
+ }
+ }
+
+ public void showPerformanceInfo() {
+ Log.d(LOG_TAG, "time for insert ContactStruct to database: " +
+ mTimePushIntoContentResolver + " ms");
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardEntryCounter.java b/core/java/android/pim/vcard/VCardEntryCounter.java
new file mode 100644
index 0000000..f99b46c
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardEntryCounter.java
@@ -0,0 +1,60 @@
+/*
+ * 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 java.util.List;
+
+public class VCardEntryCounter implements VCardBuilder {
+ private int mCount;
+
+ public int getCount() {
+ return mCount;
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ public void startRecord(String type) {
+ }
+
+ public void endRecord() {
+ mCount++;
+ }
+
+ public void startProperty() {
+ }
+
+ public void endProperty() {
+ }
+
+ public void propertyGroup(String group) {
+ }
+
+ public void propertyName(String name) {
+ }
+
+ public void propertyParamType(String type) {
+ }
+
+ public void propertyParamValue(String value) {
+ }
+
+ public void propertyValues(List<String> values) {
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
new file mode 100644
index 0000000..b5e5049
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -0,0 +1,90 @@
+/*
+ * 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.pim.vcard.exception.VCardException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class VCardParser {
+
+ protected boolean mCanceled;
+
+ /**
+ * Parses the given stream and send the VCard data into VCardBuilderBase object.
+ *
+ * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
+ * local encoding to it. For example, Japanese phone career uses Shift_JIS, which is
+ * formally allowed in VCard 2.1, but not recommended in VCard 3.0. In VCard 2.1,
+ * In some exreme case, some VCard may have different charsets in one VCard (though
+ * we do not see any device which emits such kind of malicious data)
+ *
+ * In order to avoid "misunderstanding" charset as much as possible, this method
+ * use "ISO-8859-1" for reading the stream. When charset is specified in some property
+ * (with "CHARSET=..." attribute), the string is decoded to raw bytes and encoded to
+ * the charset. This method assumes that "ISO-8859-1" has 1 to 1 mapping in all 8bit
+ * characters, which is not completely sure. In some cases, this "decoding-encoding"
+ * scheme may fail. To avoid the case,
+ *
+ * We recommend you to use VCardSourceDetector and detect which kind of source the
+ * VCard comes from and explicitly specify a charset using the result.
+ *
+ * @param is The source to parse.
+ * @param builder The VCardBuilderBase object which used to construct data. If you want to
+ * include multiple VCardBuilderBase objects in this field, consider using
+ * {#link VCardBuilderCollection} class.
+ * @return Returns true for success. Otherwise returns false.
+ * @throws IOException, VCardException
+ */
+ public abstract boolean parse(InputStream is, VCardBuilder builder)
+ throws IOException, VCardException;
+
+ /**
+ * The method variants which accept charset.
+ *
+ * RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
+ * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
+ * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
+ * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification
+ * (e.g. W53K).
+ *
+ * @param is The source to parse.
+ * @param charset Charset to be used.
+ * @param builder The VCardBuilderBase object.
+ * @return Returns true when successful. Otherwise returns false.
+ * @throws IOException, VCardException
+ */
+ public abstract boolean parse(InputStream is, String charset, VCardBuilder builder)
+ throws IOException, VCardException;
+
+ /**
+ * The method variants which tells this object the operation is already canceled.
+ * XXX: Is this really necessary?
+ * @hide
+ */
+ public abstract void parse(InputStream is, String charset,
+ VCardBuilder builder, boolean canceled)
+ throws IOException, VCardException;
+
+ /**
+ * Cancel parsing.
+ * Actual cancel is done after the end of the current one vcard entry parsing.
+ */
+ public void cancel() {
+ mCanceled = true;
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
new file mode 100644
index 0000000..17a138f
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -0,0 +1,948 @@
+/*
+ * 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.pim.vcard.exception.VCardException;
+import android.pim.vcard.exception.VCardNestedException;
+import android.pim.vcard.exception.VCardNotSupportedException;
+import android.pim.vcard.exception.VCardVersionException;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * 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";
+
+ /** Store the known-type */
+ private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
+ Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
+ "PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
+ "MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
+ "ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
+ "MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
+ "CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
+ "PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
+ "WAVE", "AIFF", "PCM", "X509", "PGP"));
+
+ /** Store the known-value */
+ private static final HashSet<String> sKnownValueSet = new HashSet<String>(
+ Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
+
+ /** Store the property names available in vCard 2.1 */
+ private static final HashSet<String> sAvailablePropertyNameV21 =
+ new HashSet<String>(Arrays.asList(
+ "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "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...
+ private static final HashSet<String> sAvailableEncodingV21 =
+ new HashSet<String>(Arrays.asList(
+ "7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
+
+ // Used only for parsing END:VCARD.
+ private String mPreviousLine;
+
+ /** The builder to build parsed data */
+ protected VCardBuilder mBuilder = null;
+
+ /** The encoding type */
+ protected String mEncoding = null;
+
+ protected final String sDefaultEncoding = "8BIT";
+
+ // Should not directly read a line from this. Use getLine() instead.
+ protected BufferedReader mReader;
+
+ // In some cases, vCard is nested. Currently, we only consider the most interior vCard data.
+ // See v21_foma_1.vcf in test directory for more information.
+ private int mNestCount;
+
+ // In order to reduce warning message as much as possible, we hold the value which made Logger
+ // emit a warning message.
+ protected HashSet<String> mWarningValueMap = new HashSet<String>();
+
+ // Just for debugging
+ private long mTimeTotal;
+ private long mTimeStartRecord;
+ private long mTimeEndRecord;
+ 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;
+
+ /**
+ * Create a new VCard parser.
+ */
+ public VCardParser_V21() {
+ super();
+ }
+
+ public VCardParser_V21(VCardSourceDetector detector) {
+ super();
+ if (detector != null && detector.getType() == VCardSourceDetector.TYPE_FOMA) {
+ mNestCount = 1;
+ }
+ }
+
+ /**
+ * Parse the file at the given position
+ * vcard_file = [wsls] vcard [wsls]
+ */
+ protected void parseVCardFile() throws IOException, VCardException {
+ boolean firstReading = true;
+ while (true) {
+ if (mCanceled) {
+ break;
+ }
+ if (!parseOneVCard(firstReading)) {
+ break;
+ }
+ firstReading = false;
+ }
+
+ if (mNestCount > 0) {
+ boolean useCache = true;
+ for (int i = 0; i < mNestCount; i++) {
+ readEndVCard(useCache, true);
+ useCache = false;
+ }
+ }
+ }
+
+ protected String getVersion() {
+ return "2.1";
+ }
+
+ /**
+ * @return true when the propertyName is a valid property name.
+ */
+ protected boolean isValidPropertyName(String propertyName) {
+ if (!(sAvailablePropertyNameV21.contains(propertyName.toUpperCase()) ||
+ propertyName.startsWith("X-")) &&
+ !mWarningValueMap.contains(propertyName)) {
+ mWarningValueMap.add(propertyName);
+ Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
+ }
+ return true;
+ }
+
+ /**
+ * @return true when the encoding is a valid encoding.
+ */
+ protected boolean isValidEncoding(String encoding) {
+ return sAvailableEncodingV21.contains(encoding.toUpperCase());
+ }
+
+ /**
+ * @return String. It may be null, or its length may be 0
+ * @throws IOException
+ */
+ protected String getLine() throws IOException {
+ return mReader.readLine();
+ }
+
+ /**
+ * @return String with it's length > 0
+ * @throws IOException
+ * @throws VCardException when the stream reached end of line
+ */
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.trim().length() > 0) {
+ return line;
+ }
+ }
+ }
+
+ /**
+ * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
+ * items *CRLF
+ * "END" [ws] ":" [ws] "VCARD"
+ */
+ private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException {
+ boolean allowGarbage = false;
+ if (firstReading) {
+ if (mNestCount > 0) {
+ for (int i = 0; i < mNestCount; i++) {
+ if (!readBeginVCard(allowGarbage)) {
+ return false;
+ }
+ allowGarbage = true;
+ }
+ }
+ }
+
+ if (!readBeginVCard(allowGarbage)) {
+ return false;
+ }
+ long start;
+ if (mBuilder != null) {
+ start = System.currentTimeMillis();
+ mBuilder.startRecord("VCARD");
+ mTimeStartRecord += System.currentTimeMillis() - start;
+ }
+ start = System.currentTimeMillis();
+ parseItems();
+ mTimeParseItems += System.currentTimeMillis() - start;
+ readEndVCard(true, false);
+ if (mBuilder != null) {
+ start = System.currentTimeMillis();
+ mBuilder.endRecord();
+ mTimeEndRecord += System.currentTimeMillis() - start;
+ }
+ return true;
+ }
+
+ /**
+ * @return True when successful. False when reaching the end of line
+ * @throws IOException
+ * @throws VCardException
+ */
+ protected boolean readBeginVCard(boolean allowGarbage)
+ throws IOException, VCardException {
+ String line;
+ do {
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ return false;
+ } else if (line.trim().length() > 0) {
+ break;
+ }
+ }
+ String[] strArray = line.split(":", 2);
+ int length = strArray.length;
+
+ // 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")) {
+ return true;
+ } else if (!allowGarbage) {
+ if (mNestCount > 0) {
+ mPreviousLine = line;
+ return false;
+ } else {
+ throw new VCardException(
+ "Expected String \"BEGIN:VCARD\" did not come "
+ + "(Instead, \"" + line + "\" came)");
+ }
+ }
+ } while(allowGarbage);
+
+ throw new VCardException("Reached where must not be reached.");
+ }
+
+ /**
+ * The arguments useCache and allowGarbase are usually true and false accordingly when
+ * this function is called outside this function itself.
+ *
+ * @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine()
+ * is used.
+ * @param allowGarbage When true, ignore non "END:VCARD" line.
+ * @throws IOException
+ * @throws VCardException
+ */
+ protected void readEndVCard(boolean useCache, boolean allowGarbage)
+ throws IOException, VCardException {
+ String line;
+ do {
+ if (useCache) {
+ // Though vCard specification does not allow lower cases,
+ // some data may have them, so we allow it.
+ line = mPreviousLine;
+ } else {
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException("Expected END:VCARD was not found.");
+ } else if (line.trim().length() > 0) {
+ break;
+ }
+ }
+ }
+
+ String[] strArray = line.split(":", 2);
+ if (strArray.length == 2 &&
+ strArray[0].trim().equalsIgnoreCase("END") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD")) {
+ return;
+ } else if (!allowGarbage) {
+ throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
+ }
+ useCache = false;
+ } while (allowGarbage);
+ }
+
+ /**
+ * items = *CRLF item
+ * / item
+ */
+ protected void parseItems() throws IOException, VCardException {
+ /* items *CRLF item / item */
+ boolean ended = false;
+
+ if (mBuilder != null) {
+ long start = System.currentTimeMillis();
+ mBuilder.startProperty();
+ mTimeStartProperty += System.currentTimeMillis() - start;
+ }
+ ended = parseItem();
+ if (mBuilder != null && !ended) {
+ long start = System.currentTimeMillis();
+ mBuilder.endProperty();
+ mTimeEndProperty += System.currentTimeMillis() - start;
+ }
+
+ while (!ended) {
+ // follow VCARD ,it wont reach endProperty
+ if (mBuilder != null) {
+ long start = System.currentTimeMillis();
+ mBuilder.startProperty();
+ mTimeStartProperty += System.currentTimeMillis() - start;
+ }
+ ended = parseItem();
+ if (mBuilder != null && !ended) {
+ long start = System.currentTimeMillis();
+ mBuilder.endProperty();
+ mTimeEndProperty += System.currentTimeMillis() - start;
+ }
+ }
+ }
+
+ /**
+ * 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;
+
+ String line = getNonEmptyLine();
+ long start = System.currentTimeMillis();
+
+ String[] propertyNameAndValue = separateLineAndHandleGroup(line);
+ if (propertyNameAndValue == null) {
+ return true;
+ }
+ if (propertyNameAndValue.length != 2) {
+ throw new VCardException("Invalid line \"" + line + "\"");
+ }
+ String propertyName = propertyNameAndValue[0].toUpperCase();
+ String propertyValue = propertyNameAndValue[1];
+
+ mTimeParseItem1 += System.currentTimeMillis() - start;
+
+ if (propertyName.equals("ADR") ||
+ propertyName.equals("ORG") ||
+ propertyName.equals("N")) {
+ start = System.currentTimeMillis();
+ handleMultiplePropertyValue(propertyName, propertyValue);
+ mTimeParseItem3 += System.currentTimeMillis() - start;
+ return false;
+ } else if (propertyName.equals("AGENT")) {
+ handleAgent(propertyValue);
+ return false;
+ } else if (isValidPropertyName(propertyName)) {
+ if (propertyName.equals("BEGIN")) {
+ if (propertyValue.equals("VCARD")) {
+ throw new VCardNestedException("This vCard has nested vCard data in it.");
+ } else {
+ throw new VCardException("Unknown BEGIN type: " + propertyValue);
+ }
+ } 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;
+ return false;
+ }
+
+ throw new VCardException("Unknown property name: \"" +
+ propertyName + "\"");
+ }
+
+ static private final int STATE_GROUP_OR_PROPNAME = 0;
+ static private final int STATE_PARAMS = 1;
+ // vCard 3.1 specification allows double-quoted param-value, while vCard 2.1 does not.
+ // This is just for safety.
+ static private final int STATE_PARAMS_IN_DQUOTE = 2;
+
+ protected String[] separateLineAndHandleGroup(String line) throws VCardException {
+ int length = line.length();
+ int state = STATE_GROUP_OR_PROPNAME;
+ int nameIndex = 0;
+
+ String[] propertyNameAndValue = new String[2];
+
+ for (int i = 0; i < length; i++) {
+ char ch = line.charAt(i);
+ switch (state) {
+ case STATE_GROUP_OR_PROPNAME:
+ if (ch == ':') {
+ String propertyName = line.substring(nameIndex, i);
+ if (propertyName.equalsIgnoreCase("END")) {
+ mPreviousLine = line;
+ return null;
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyName(propertyName);
+ }
+ propertyNameAndValue[0] = propertyName;
+ if (i < length - 1) {
+ propertyNameAndValue[1] = line.substring(i + 1);
+ } else {
+ propertyNameAndValue[1] = "";
+ }
+ return propertyNameAndValue;
+ } else if (ch == '.') {
+ String groupName = line.substring(nameIndex, i);
+ if (mBuilder != null) {
+ mBuilder.propertyGroup(groupName);
+ }
+ nameIndex = i + 1;
+ } else if (ch == ';') {
+ String propertyName = line.substring(nameIndex, i);
+ if (propertyName.equalsIgnoreCase("END")) {
+ mPreviousLine = line;
+ return null;
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyName(propertyName);
+ }
+ propertyNameAndValue[0] = propertyName;
+ nameIndex = i + 1;
+ state = STATE_PARAMS;
+ }
+ break;
+ case STATE_PARAMS:
+ if (ch == '"') {
+ state = STATE_PARAMS_IN_DQUOTE;
+ } else if (ch == ';') {
+ handleParams(line.substring(nameIndex, i));
+ nameIndex = i + 1;
+ } else if (ch == ':') {
+ handleParams(line.substring(nameIndex, i));
+ if (i < length - 1) {
+ propertyNameAndValue[1] = line.substring(i + 1);
+ } else {
+ propertyNameAndValue[1] = "";
+ }
+ return propertyNameAndValue;
+ }
+ break;
+ case STATE_PARAMS_IN_DQUOTE:
+ if (ch == '"') {
+ state = STATE_PARAMS;
+ }
+ break;
+ }
+ }
+
+ throw new VCardException("Invalid line: \"" + line + "\"");
+ }
+
+
+ /**
+ * params = ";" [ws] paramlist
+ * paramlist = paramlist [ws] ";" [ws] param
+ * / param
+ * param = "TYPE" [ws] "=" [ws] ptypeval
+ * / "VALUE" [ws] "=" [ws] pvalueval
+ * / "ENCODING" [ws] "=" [ws] pencodingval
+ * / "CHARSET" [ws] "=" [ws] charsetval
+ * / "LANGUAGE" [ws] "=" [ws] langval
+ * / "X-" word [ws] "=" [ws] word
+ * / knowntype
+ */
+ protected void handleParams(String params) throws VCardException {
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ String paramName = strArray[0].trim();
+ String paramValue = strArray[1].trim();
+ if (paramName.equals("TYPE")) {
+ handleType(paramValue);
+ } else if (paramName.equals("VALUE")) {
+ handleValue(paramValue);
+ } else if (paramName.equals("ENCODING")) {
+ handleEncoding(paramValue);
+ } else if (paramName.equals("CHARSET")) {
+ handleCharset(paramValue);
+ } else if (paramName.equals("LANGUAGE")) {
+ handleLanguage(paramValue);
+ } else if (paramName.startsWith("X-")) {
+ handleAnyParam(paramName, paramValue);
+ } else {
+ throw new VCardException("Unknown type \"" + paramName + "\"");
+ }
+ } else {
+ handleType(strArray[0]);
+ }
+ }
+
+ /**
+ * ptypeval = knowntype / "X-" word
+ */
+ protected void handleType(String ptypeval) {
+ String upperTypeValue = ptypeval;
+ if (!(sKnownTypeSet.contains(upperTypeValue) || upperTypeValue.startsWith("X-")) &&
+ !mWarningValueMap.contains(ptypeval)) {
+ mWarningValueMap.add(ptypeval);
+ Log.w(LOG_TAG, "Type unsupported by vCard 2.1: " + ptypeval);
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("TYPE");
+ mBuilder.propertyParamValue(upperTypeValue);
+ }
+ }
+
+ /**
+ * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
+ */
+ protected void handleValue(String pvalueval) throws VCardException {
+ if (sKnownValueSet.contains(pvalueval.toUpperCase()) ||
+ pvalueval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("VALUE");
+ mBuilder.propertyParamValue(pvalueval);
+ }
+ } else {
+ throw new VCardException("Unknown value \"" + pvalueval + "\"");
+ }
+ }
+
+ /**
+ * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
+ */
+ protected void handleEncoding(String pencodingval) throws VCardException {
+ if (isValidEncoding(pencodingval) ||
+ pencodingval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("ENCODING");
+ mBuilder.propertyParamValue(pencodingval);
+ }
+ mEncoding = pencodingval;
+ } else {
+ throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
+ }
+ }
+
+ /**
+ * vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
+ * but some vCard contains other charset, so we allow them.
+ */
+ protected void handleCharset(String charsetval) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("CHARSET");
+ mBuilder.propertyParamValue(charsetval);
+ }
+ }
+
+ /**
+ * See also Section 7.1 of RFC 1521
+ */
+ protected void handleLanguage(String langval) throws VCardException {
+ String[] strArray = langval.split("-");
+ if (strArray.length != 2) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ String tmp = strArray[0];
+ int length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ }
+ tmp = strArray[1];
+ length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("LANGUAGE");
+ mBuilder.propertyParamValue(langval);
+ }
+ }
+
+ /**
+ * Mainly for "X-" type. This accepts any kind of type without check.
+ */
+ protected void handleAnyParam(String paramName, String paramValue) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType(paramName);
+ mBuilder.propertyParamValue(paramValue);
+ }
+ }
+
+ protected void handlePropertyValue(
+ String propertyName, String propertyValue) throws
+ IOException, VCardException {
+ if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
+ long start = System.currentTimeMillis();
+ String result = getQuotedPrintable(propertyValue);
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ mTimeHandlePropertyValue2 += System.currentTimeMillis() - start;
+ } else if (mEncoding.equalsIgnoreCase("BASE64") ||
+ mEncoding.equalsIgnoreCase("B")) {
+ long start = System.currentTimeMillis();
+ // It is very rare, but some BASE64 data may be so big that
+ // OutOfMemoryError occurs. To ignore such cases, use try-catch.
+ try {
+ String result = getBase64(propertyValue);
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ } catch (OutOfMemoryError error) {
+ Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
+ if (mBuilder != null) {
+ mBuilder.propertyValues(null);
+ }
+ }
+ mTimeHandlePropertyValue3 += System.currentTimeMillis() - start;
+ } else {
+ if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
+ || mEncoding.equalsIgnoreCase("8BIT")
+ || mEncoding.toUpperCase().startsWith("X-"))) {
+ Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\".");
+ }
+
+ long start = System.currentTimeMillis();
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(maybeUnescapeText(propertyValue));
+ mBuilder.propertyValues(v);
+ }
+ mTimeHandlePropertyValue1 += System.currentTimeMillis() - start;
+ }
+ }
+
+ protected String getQuotedPrintable(String firstString) throws IOException, VCardException {
+ // Specifically, there may be some padding between = and CRLF.
+ // See the following:
+ //
+ // qp-line := *(qp-segment transport-padding CRLF)
+ // qp-part transport-padding
+ // qp-segment := qp-section *(SPACE / TAB) "="
+ // ; Maximum length of 76 characters
+ //
+ // e.g. (from RFC 2045)
+ // Now's the time =
+ // for all folk to come=
+ // to the aid of their country.
+ if (firstString.trim().endsWith("=")) {
+ // remove "transport-padding"
+ int pos = firstString.length() - 1;
+ while(firstString.charAt(pos) != '=') {
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString.substring(0, pos + 1));
+ builder.append("\r\n");
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing quoted-printable String");
+ }
+ if (line.trim().endsWith("=")) {
+ // remove "transport-padding"
+ pos = line.length() - 1;
+ while(line.charAt(pos) != '=') {
+ }
+ builder.append(line.substring(0, pos + 1));
+ builder.append("\r\n");
+ } else {
+ builder.append(line);
+ break;
+ }
+ }
+ return builder.toString();
+ } else {
+ return firstString;
+ }
+ }
+
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ }
+ builder.append(line);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Mainly for "ADR", "ORG", and "N"
+ * We do not care the number of strnosemi here.
+ *
+ * addressparts = 0*6(strnosemi ";") strnosemi
+ * ; PO Box, Extended Addr, Street, Locality, Region,
+ * Postal Code, Country Name
+ * orgparts = *(strnosemi ";") strnosemi
+ * ; First is Organization Name,
+ * remainder are Organization Units.
+ * nameparts = 0*4(strnosemi ";") strnosemi
+ * ; Family, Given, Middle, Prefix, Suffix.
+ * ; Example:Public;John;Q.;Reverend Dr.;III, Esq.
+ * strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi
+ * ; To include a semicolon in this string, it must be escaped
+ * ; with a "\" character.
+ *
+ * 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.
+ 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();
+ for (int i = 0; i < length; i++) {
+ char ch = propertyValue.charAt(i);
+ if (ch == '\\' && i < length - 1) {
+ char nextCh = propertyValue.charAt(i + 1);
+ String unescapedString = maybeUnescape(nextCh);
+ if (unescapedString != null) {
+ builder.append(unescapedString);
+ i++;
+ } else {
+ builder.append(ch);
+ }
+ } else if (ch == ';') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else {
+ builder.append(ch);
+ }
+ }
+ list.add(builder.toString());
+ mBuilder.propertyValues(list);
+ }
+ }
+
+ /**
+ * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
+ *
+ * item = ...
+ * / [groups "."] "AGENT"
+ * [params] ":" vcard CRLF
+ * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
+ * items *CRLF "END" [ws] ":" [ws] "VCARD"
+ *
+ */
+ protected void handleAgent(String propertyValue) throws VCardException {
+ 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 ||
+ strArray[0].trim().equalsIgnoreCase("BEGIN") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD"))) {
+ throw new VCardException("BEGIN:VCARD != \"" + propertyValue + "\"");
+ }
+ parseItems();
+ readEndVCard();
+ */
+ }
+
+ /**
+ * For vCard 3.0.
+ */
+ protected String maybeUnescapeText(String text) {
+ return text;
+ }
+
+ /**
+ * 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) {
+ // Original vCard 2.1 specification does not allow transformation
+ // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
+ // this class allowed them, so keep it as is.
+ if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
+ return String.valueOf(ch);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean parse(InputStream is, VCardBuilder builder)
+ throws IOException, VCardException {
+ return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
+ }
+
+ @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);
+ }
+ }
+
+ mBuilder = builder;
+
+ long start = System.currentTimeMillis();
+ if (mBuilder != null) {
+ mBuilder.start();
+ }
+ parseVCardFile();
+ if (mBuilder != null) {
+ mBuilder.end();
+ }
+ mTimeTotal += System.currentTimeMillis() - start;
+
+ if (VCardConfig.showPerformanceLog()) {
+ showPerformanceInfo();
+ }
+
+ return true;
+ }
+
+ @Override
+ public void parse(InputStream is, String charset, VCardBuilder builder, boolean canceled)
+ throws IOException, VCardException {
+ mCanceled = canceled;
+ parse(is, charset, builder);
+ }
+
+ private void showPerformanceInfo() {
+ Log.d(LOG_TAG, "total parsing time: " + mTimeTotal + " ms");
+ if (mReader instanceof CustomBufferedReader) {
+ 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");
+ }
+
+ private boolean isLetter(char ch) {
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
+ return true;
+ }
+ return false;
+ }
+}
+
+class CustomBufferedReader extends BufferedReader {
+ private long mTime;
+
+ public CustomBufferedReader(Reader in) {
+ super(in);
+ }
+
+ @Override
+ public String readLine() throws IOException {
+ long start = System.currentTimeMillis();
+ String ret = super.readLine();
+ long end = System.currentTimeMillis();
+ mTime += end - start;
+ return ret;
+ }
+
+ public long getTotalmillisecond() {
+ return mTime;
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java
new file mode 100644
index 0000000..634d9f5
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser_V30.java
@@ -0,0 +1,306 @@
+/*
+ * 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.pim.vcard.exception.VCardException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * This class is used to parse vcard3.0. <br>
+ * 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 HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
+ Arrays.asList(
+ "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
+ "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
+ "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
+ "SORT-STRING", "CATEGORIES", "PRODID")); // 3.0
+
+ // Although "7bit" and "BASE64" is not allowed in vCard 3.0, we allow it for safety.
+ private static final HashSet<String> sAcceptableEncodingV30 = new HashSet<String>(
+ Arrays.asList("7BIT", "8BIT", "BASE64", "B"));
+
+ // Although RFC 2426 specifies some property must not have parameters, we allow it,
+ // since there may be some careers which violates the RFC...
+ private static final HashSet<String> acceptablePropsWithoutParam = new HashSet<String>();
+
+ private String mPreviousLine;
+
+ @Override
+ protected String getVersion() {
+ return "3.0";
+ }
+
+ @Override
+ protected boolean isValidPropertyName(String propertyName) {
+ if (!(sAcceptablePropsWithParam.contains(propertyName) ||
+ acceptablePropsWithoutParam.contains(propertyName) ||
+ propertyName.startsWith("X-")) &&
+ !mWarningValueMap.contains(propertyName)) {
+ mWarningValueMap.add(propertyName);
+ Log.w(LOG_TAG, "Property name unsupported by vCard 3.0: " + propertyName);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean isValidEncoding(String encoding) {
+ return sAcceptableEncodingV30.contains(encoding.toUpperCase());
+ }
+
+ @Override
+ protected String getLine() throws IOException {
+ if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ } else {
+ return mReader.readLine();
+ }
+ }
+
+ /**
+ * vCard 3.0 requires that the line with space at the beginning of the line
+ * must be combined with previous line.
+ */
+ @Override
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ StringBuilder builder = null;
+ while (true) {
+ line = mReader.readLine();
+ if (line == null) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.length() == 0) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
+ if (builder != null) {
+ // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
+ // Following is the excerpts from it.
+ //
+ // DESCRIPTION:This is a long description that exists on a long line.
+ //
+ // Can be represented as:
+ //
+ // DESCRIPTION:This is a long description
+ // that exists on a long line.
+ //
+ // It could also be represented as:
+ //
+ // DESCRIPTION:This is a long descrip
+ // tion that exists o
+ // n a long line.
+ builder.append(line.substring(1));
+ } else if (mPreviousLine != null) {
+ builder = new StringBuilder();
+ builder.append(mPreviousLine);
+ mPreviousLine = null;
+ builder.append(line.substring(1));
+ } else {
+ throw new VCardException("Space exists at the beginning of the line");
+ }
+ } else {
+ if (mPreviousLine == null) {
+ mPreviousLine = line;
+ if (builder != null) {
+ return builder.toString();
+ }
+ } else {
+ String ret = mPreviousLine;
+ mPreviousLine = line;
+ return ret;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF
+ * 1*(contentline)
+ * ;A vCard object MUST include the VERSION, FN and N types.
+ * [group "."] "END" ":" "VCARD" 1*CRLF
+ */
+ @Override
+ protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
+ // TODO: vCard 3.0 supports group.
+ return super.readBeginVCard(allowGarbage);
+ }
+
+ @Override
+ protected void readEndVCard(boolean useCache, boolean allowGarbage)
+ throws IOException, VCardException {
+ // TODO: vCard 3.0 supports group.
+ super.readEndVCard(useCache, allowGarbage);
+ }
+
+ /**
+ * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
+ */
+ @Override
+ protected void handleParams(String params) throws VCardException {
+ try {
+ super.handleParams(params);
+ } catch (VCardException e) {
+ // maybe IANA type
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ handleAnyParam(strArray[0], strArray[1]);
+ } else {
+ // Must not come here in the current implementation.
+ throw new VCardException(
+ "Unknown params value: " + params);
+ }
+ }
+ }
+
+ @Override
+ protected void handleAnyParam(String paramName, String paramValue) {
+ // vCard 3.0 accept comma-separated multiple values, but
+ // current PropertyNode does not accept it.
+ // For now, we do not split the values.
+ //
+ // TODO: fix this.
+ super.handleAnyParam(paramName, paramValue);
+ }
+
+ /**
+ * vCard 3.0 defines
+ *
+ * param = param-name "=" param-value *("," param-value)
+ * param-name = iana-token / x-name
+ * param-value = ptext / quoted-string
+ * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
+ */
+ @Override
+ protected void handleType(String ptypevalues) {
+ String[] ptypeArray = ptypevalues.split(",");
+ mBuilder.propertyParamType("TYPE");
+ for (String value : ptypeArray) {
+ int length = value.length();
+ if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
+ mBuilder.propertyParamValue(value.substring(1, value.length() - 1));
+ } else {
+ mBuilder.propertyParamValue(value);
+ }
+ }
+ }
+
+ @Override
+ protected void handleAgent(String propertyValue) throws VCardException {
+ // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0.
+ //
+ // e.g.
+ // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
+ // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
+ // ET:jfriday@host.com\nEND:VCARD\n
+ //
+ // TODO: fix this.
+ //
+ // issue:
+ // vCard 3.0 also allows this as an example.
+ //
+ // AGENT;VALUE=uri:
+ // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
+ //
+ // This is not VCARD. Should we support this?
+ throw new VCardException("AGENT in vCard 3.0 is not supported yet.");
+ }
+
+ /**
+ * vCard 3.0 does not require two CRLF at the last of BASE64 data.
+ * It only requires that data should be MIME-encoded.
+ */
+ @Override
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
+ mPreviousLine = line;
+ break;
+ }
+ builder.append(line);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
+ * ; \\ encodes \, \n or \N encodes newline
+ * ; \; encodes ;, \, encodes ,
+ *
+ * Note: Apple escape ':' into '\:' while does not escape '\'
+ */
+ @Override
+ protected String maybeUnescapeText(String text) {
+ StringBuilder builder = new StringBuilder();
+ int length = text.length();
+ for (int i = 0; i < length; i++) {
+ char ch = text.charAt(i);
+ if (ch == '\\' && i < length - 1) {
+ char next_ch = text.charAt(++i);
+ if (next_ch == 'n' || next_ch == 'N') {
+ builder.append("\r\n");
+ } else {
+ builder.append(next_ch);
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ return builder.toString();
+ }
+
+ @Override
+ protected String maybeUnescape(char ch) {
+ if (ch == 'n' || ch == 'N') {
+ return "\r\n";
+ } else {
+ return String.valueOf(ch);
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java
new file mode 100644
index 0000000..7e2be2b
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardSourceDetector.java
@@ -0,0 +1,137 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Class which tries to detects the source of the vCard from its properties.
+ * Currently this implementation is very premature.
+ * @hide
+ */
+public class VCardSourceDetector implements VCardBuilder {
+ // Should only be used in package.
+ static final int TYPE_UNKNOWN = 0;
+ static final int TYPE_APPLE = 1;
+ static final int TYPE_JAPANESE_MOBILE_PHONE = 2; // Used in Japanese mobile phones.
+ static final int TYPE_FOMA = 3; // Used in some Japanese FOMA mobile phones.
+ static final int TYPE_WINDOWS_MOBILE_JP = 4;
+ // TODO: Excel, etc.
+
+ private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
+ "X-ABADR", "X-ABUID"));
+
+ private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-GNO", "X-GN", "X-REDUCTION"));
+
+ private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
+
+ // Note: these signes appears before the signs of the other type (e.g. "X-GN").
+ // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
+ private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
+ "X-SD-DESCRIPTION"));
+ private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
+
+ private int mType = TYPE_UNKNOWN;
+ // Some mobile phones (like FOMA) tells us the charset of the data.
+ private boolean mNeedParseSpecifiedCharset;
+ private String mSpecifiedCharset;
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ public void startRecord(String type) {
+ }
+
+ public void startProperty() {
+ mNeedParseSpecifiedCharset = false;
+ }
+
+ public void endProperty() {
+ }
+
+ public void endRecord() {
+ }
+
+ public void propertyGroup(String group) {
+ }
+
+ public void propertyName(String name) {
+ if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
+ mType = TYPE_FOMA;
+ mNeedParseSpecifiedCharset = true;
+ return;
+ }
+ if (mType != TYPE_UNKNOWN) {
+ return;
+ }
+ if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
+ mType = TYPE_WINDOWS_MOBILE_JP;
+ } else if (FOMA_SIGNS.contains(name)) {
+ mType = TYPE_FOMA;
+ } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
+ mType = TYPE_JAPANESE_MOBILE_PHONE;
+ } else if (APPLE_SIGNS.contains(name)) {
+ mType = TYPE_APPLE;
+ }
+ }
+
+ public void propertyParamType(String type) {
+ }
+
+ public void propertyParamValue(String value) {
+ }
+
+ public void propertyValues(List<String> values) {
+ if (mNeedParseSpecifiedCharset && values.size() > 0) {
+ mSpecifiedCharset = values.get(0);
+ }
+ }
+
+ int getType() {
+ return mType;
+ }
+
+ /**
+ * Return charset String guessed from the source's properties.
+ * This method must be called after parsing target file(s).
+ * @return Charset String. Null is returned if guessing the source fails.
+ */
+ public String getEstimatedCharset() {
+ if (mSpecifiedCharset != null) {
+ return mSpecifiedCharset;
+ }
+ switch (mType) {
+ case TYPE_WINDOWS_MOBILE_JP:
+ case TYPE_FOMA:
+ case TYPE_JAPANESE_MOBILE_PHONE:
+ return "SHIFT_JIS";
+ case TYPE_APPLE:
+ return "UTF-8";
+ default:
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/exception/VCardException.java b/core/java/android/pim/vcard/exception/VCardException.java
new file mode 100644
index 0000000..e557219
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.exception;
+
+public class VCardException extends java.lang.Exception {
+ /**
+ * Constructs a VCardException object
+ */
+ public VCardException() {
+ super();
+ }
+
+ /**
+ * Constructs a VCardException object
+ *
+ * @param message the error message
+ */
+ public VCardException(String message) {
+ super(message);
+ }
+
+}
diff --git a/core/java/android/pim/vcard/exception/VCardNestedException.java b/core/java/android/pim/vcard/exception/VCardNestedException.java
new file mode 100644
index 0000000..503c2fb
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardNestedException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.exception;
+
+/**
+ * VCardException thrown when VCard is nested without VCardParser's being notified.
+ */
+public class VCardNestedException extends VCardNotSupportedException {
+ public VCardNestedException() {
+ super();
+ }
+ public VCardNestedException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/pim/vcard/exception/VCardNotSupportedException.java b/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
new file mode 100644
index 0000000..616aa7763
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.exception;
+
+/**
+ * The exception which tells that the input VCard is probably valid from the view of
+ * specification but not supported in the current framework for now.
+ *
+ * This is a kind of a good news from the view of development.
+ * It may be good to ask users to send a report with the VCard example
+ * for the future development.
+ */
+public class VCardNotSupportedException extends VCardException {
+ public VCardNotSupportedException() {
+ super();
+ }
+ public VCardNotSupportedException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/exception/VCardVersionException.java b/core/java/android/pim/vcard/exception/VCardVersionException.java
new file mode 100644
index 0000000..9fe8b7f
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardVersionException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.exception;
+
+/**
+ * VCardException used only when the version of the vCard is different.
+ */
+public class VCardVersionException extends VCardException {
+ public VCardVersionException() {
+ super();
+ }
+ public VCardVersionException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/pim/vcard/exception/package.html b/core/java/android/pim/vcard/exception/package.html
new file mode 100644
index 0000000..26b8a32
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+{@hide}
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/package.html b/core/java/android/pim/vcard/package.html
new file mode 100644
index 0000000..26b8a32
--- /dev/null
+++ b/core/java/android/pim/vcard/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+{@hide}
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 6beb06d..b46f180 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -31,8 +31,9 @@
* The chosen ringtone's URI will be persisted as a string.
* <p>
* If the user chooses the "Default" item, the saved string will be one of
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI}. If the user chooses the "Silent"
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent"
* item, the saved string will be an empty string.
*
* @attr ref android.R.styleable#RingtonePreference_ringtoneType
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 20702a1..db25cfa 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -22,11 +22,13 @@
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.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -35,7 +37,7 @@
* @hide
*/
public class VolumePreference extends SeekBarPreference implements
- PreferenceManager.OnActivityStopListener {
+ PreferenceManager.OnActivityStopListener, View.OnKeyListener {
private static final String TAG = "VolumePreference";
@@ -65,6 +67,30 @@
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
getPreferenceManager().registerOnActivityStopListener(this);
+
+ // grab focus and key events so that pressing the volume buttons in the
+ // dialog doesn't also show the normal volume adjust toast.
+ view.setOnKeyListener(this);
+ view.setFocusableInTouchMode(true);
+ view.requestFocus();
+ }
+
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(-1);
+ }
+ return true;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(1);
+ }
+ return true;
+ default:
+ return false;
+ }
}
@Override
@@ -147,11 +173,19 @@
System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
false, mVolumeObserver);
- mRingtone = RingtoneManager.getRingtone(mContext,
- mStreamType == AudioManager.STREAM_NOTIFICATION
- ? Settings.System.DEFAULT_NOTIFICATION_URI
- : Settings.System.DEFAULT_RINGTONE_URI);
- mRingtone.setStreamType(mStreamType);
+ Uri defaultUri = null;
+ if (mStreamType == AudioManager.STREAM_RING) {
+ defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+ } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
+ defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else {
+ defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+ }
+
+ mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
+ if (mRingtone != null) {
+ mRingtone.setStreamType(mStreamType);
+ }
}
public void stop() {
@@ -208,5 +242,12 @@
return mSeekBar;
}
+ public void changeVolumeBy(int amount) {
+ mSeekBar.incrementProgressBy(amount);
+ if (mRingtone != null && !mRingtone.isPlaying()) {
+ sample();
+ }
+ postSetVolume(mSeekBar.getProgress());
+ }
}
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 1ba5e25..92bc814 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -107,7 +107,8 @@
public static final String[] HISTORY_PROJECTION = new String[] {
BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS,
BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE,
- BookmarkColumns.FAVICON };
+ BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL,
+ BookmarkColumns.TOUCH_ICON };
/* these indices dependent on HISTORY_PROJECTION */
public static final int HISTORY_PROJECTION_ID_INDEX = 0;
@@ -117,6 +118,14 @@
public static final int HISTORY_PROJECTION_BOOKMARK_INDEX = 4;
public static final int HISTORY_PROJECTION_TITLE_INDEX = 5;
public static final int HISTORY_PROJECTION_FAVICON_INDEX = 6;
+ /**
+ * @hide
+ */
+ public static final int HISTORY_PROJECTION_THUMBNAIL_INDEX = 7;
+ /**
+ * @hide
+ */
+ public static final int HISTORY_PROJECTION_TOUCH_ICON_INDEX = 8;
/* columns needed to determine whether to truncate history */
public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] {
@@ -513,6 +522,14 @@
public static final String TITLE = "title";
public static final String CREATED = "created";
public static final String FAVICON = "favicon";
+ /**
+ * @hide
+ */
+ public static final String THUMBNAIL = "thumbnail";
+ /**
+ * @hide
+ */
+ public static final String TOUCH_ICON = "touch_icon";
}
public static class SearchColumns implements BaseColumns {
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 4a709f6..fab3f3d 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -32,6 +32,7 @@
import android.text.format.Time;
import android.util.Config;
import android.util.Log;
+import android.accounts.Account;
import com.android.internal.database.ArrayListCursor;
import com.google.android.gdata.client.AndroidGDataClient;
import com.google.android.gdata.client.AndroidXmlParserFactory;
@@ -80,6 +81,11 @@
public interface CalendarsColumns
{
/**
+ * A string that uniquely identifies this contact to its source
+ */
+ public static final String SOURCE_ID = "sourceid";
+
+ /**
* The color of the calendar
* <P>Type: INTEGER (color value)</P>
*/
@@ -124,6 +130,12 @@
* <p>Type: INTEGER (boolean)</p>
*/
public static final String SYNC_EVENTS = "sync_events";
+
+ /**
+ * Sync state data.
+ * <p>Type: String (blob)</p>
+ */
+ public static final String SYNC_STATE = "sync_state";
}
/**
@@ -157,11 +169,12 @@
* @param account the account whose rows should be deleted
* @return the count of rows that were deleted
*/
- public static int deleteCalendarsForAccount(ContentResolver cr,
- String account) {
+ public static int deleteCalendarsForAccount(ContentResolver cr, Account account) {
// delete all calendars that match this account
- return Calendar.Calendars.delete(cr, Calendar.Calendars._SYNC_ACCOUNT + "=?",
- new String[] {account});
+ return Calendar.Calendars.delete(cr,
+ Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
+ + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
+ new String[] {account.name, account.type});
}
/**
@@ -170,9 +183,6 @@
public static final Uri CONTENT_URI =
Uri.parse("content://calendar/calendars");
- public static final Uri LIVE_CONTENT_URI =
- Uri.parse("content://calendar/calendars?update=1");
-
/**
* The default sort order for this table
*/
@@ -207,6 +217,13 @@
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HIDDEN = "hidden";
+
+ /**
+ * The owner account for this calendar, based on the calendar feed.
+ * This will be different from the _SYNC_ACCOUNT for delegated calendars.
+ * <P>Type: String</P>
+ */
+ public static final String OWNER_ACCOUNT = "ownerAccount";
}
public interface AttendeesColumns {
@@ -448,6 +465,14 @@
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String LAST_DATE = "lastDate";
+
+ /**
+ * Whether the event has attendee information. True if the event
+ * has full attendee data, false if the event has information about
+ * self only.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String HAS_ATTENDEE_DATA = "hasAttendeeData";
}
/**
@@ -694,6 +719,8 @@
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://calendar/instances/when");
+ public static final Uri CONTENT_BY_DAY_URI =
+ Uri.parse("content://calendar/instances/whenbyday");
/**
* The default sort order for this table.
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index afe219c..b54ad5d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -73,7 +73,7 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
/**
- * The type of the the phone number.
+ * The type of the call (incoming, outgoing or missed).
* <P>Type: INTEGER (int)</P>
*/
public static final String TYPE = "type";
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 84fe184..c0dbf4d 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -30,6 +30,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
+import android.accounts.Account;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -39,7 +40,7 @@
*/
public class Contacts {
private static final String TAG = "Contacts";
-
+
public static final String AUTHORITY = "contacts";
/**
@@ -75,6 +76,12 @@
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>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The key of this setting.
* <P>Type: TEXT</P>
*/
@@ -134,6 +141,7 @@
selectString = (account == null)
? "_sync_account is null AND key=?"
: "_sync_account=? AND key=?";
+// : "_sync_account=? AND _sync_account_type=? AND key=?";
selectArgs = (account == null)
? new String[]{key}
: new String[]{account, key};
@@ -158,7 +166,8 @@
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
// Some day when we add multiple accounts to the UI this should honor the account
// that was asked for.
- //values.put(_SYNC_ACCOUNT, account);
+ //values.put(_SYNC_ACCOUNT, account.mName);
+ //values.put(_SYNC_ACCOUNT_TYPE, account.mType);
values.put(KEY, key);
values.put(VALUE, value);
cr.update(Settings.CONTENT_URI, values, null, null);
@@ -182,7 +191,7 @@
* <p>Type: TEXT</P>
*/
public static final String PHONETIC_NAME = "phonetic_name";
-
+
/**
* The display name. If name is not null name, else if number is not null number,
* else if email is not null email.
@@ -197,7 +206,7 @@
* @hide Used only in Contacts application for now.
*/
public static final String SORT_STRING = "sort_string";
-
+
/**
* Notes about the person.
* <P>Type: TEXT</P>
@@ -239,7 +248,7 @@
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
- public static final String PHOTO_VERSION = "photo_version";
+ public static final String PHOTO_VERSION = "photo_version";
}
/**
@@ -278,14 +287,14 @@
* additional path segment after this URI. This matches any people with
* at least one E-mail or IM {@link ContactMethods} that match the
* filter.
- *
+ *
* Not exposed because we expect significant changes in the contacts
* schema and do not want to have to support this.
* @hide
*/
public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
Uri.parse("content://contacts/people/with_email_or_im_filter");
-
+
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
@@ -370,13 +379,13 @@
if (groupId == 0) {
throw new IllegalStateException("Failed to find the My Contacts group");
}
-
+
return addToGroup(resolver, personId, groupId);
}
/**
* Adds a person to a group referred to by name.
- *
+ *
* @param resolver the resolver to use
* @param personId the person to add to the group
* @param groupName the name of the group to add the contact to
@@ -400,13 +409,13 @@
if (groupId == 0) {
throw new IllegalStateException("Failed to find the My Contacts group");
}
-
+
return addToGroup(resolver, personId, groupId);
}
/**
* Adds a person to a group.
- *
+ *
* @param resolver the resolver to use
* @param personId the person to add to the group
* @param groupId the group to add the person to
@@ -418,14 +427,14 @@
values.put(GroupMembership.GROUP_ID, groupId);
return resolver.insert(GroupMembership.CONTENT_URI, values);
}
-
+
private static final String[] GROUPS_PROJECTION = new String[] {
Groups._ID,
};
/**
* Creates a new contacts and adds it to the "My Contacts" group.
- *
+ *
* @param resolver the ContentResolver to use
* @param values the values to use when creating the contact
* @return the URI of the contact, or null if the operation fails
@@ -463,7 +472,7 @@
values.put(Photos.DATA, data);
cr.update(photoUri, values, null, null);
}
-
+
/**
* Opens an InputStream for the person's photo and returns the photo as a Bitmap.
* If the person's photo isn't present returns the placeholderImageResource instead.
@@ -730,7 +739,7 @@
CharSequence display = "";
if (type != People.Phones.TYPE_CUSTOM) {
- CharSequence[] labels = labelArray != null? labelArray
+ CharSequence[] labels = labelArray != null? labelArray
: context.getResources().getTextArray(
com.android.internal.R.array.phoneTypes);
try {
@@ -750,7 +759,7 @@
CharSequence label) {
return getDisplayLabel(context, type, label, null);
}
-
+
/**
* The content:// style URL for this table
*/
@@ -846,6 +855,12 @@
public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
/**
+ * The account type of the group.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+
+ /**
* The row id of the person.
* <P>Type: TEXT</P>
*/
@@ -969,7 +984,7 @@
throw new IllegalArgumentException(
"the value is not a valid encoded protocol, " + encodedString);
}
-
+
/**
* This looks up the provider name defined in
* {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
@@ -1022,13 +1037,7 @@
}
} else {
if (!TextUtils.isEmpty(label)) {
- if (label.toString().equals(MOBILE_EMAIL_TYPE_NAME)) {
- display =
- context.getString(
- com.android.internal.R.string.mobileEmailTypeName);
- } else {
- display = label;
- }
+ display = label;
}
}
break;
@@ -1188,7 +1197,7 @@
/**
* Gets the resource ID for the proper presence icon.
- *
+ *
* @param status the status to get the icon for
* @return the resource ID for the proper presence icon
*/
@@ -1196,17 +1205,17 @@
switch (status) {
case Contacts.People.AVAILABLE:
return com.android.internal.R.drawable.presence_online;
-
+
case Contacts.People.IDLE:
case Contacts.People.AWAY:
return com.android.internal.R.drawable.presence_away;
-
+
case Contacts.People.DO_NOT_DISTURB:
return com.android.internal.R.drawable.presence_busy;
-
+
case Contacts.People.INVISIBLE:
return com.android.internal.R.drawable.presence_invisible;
-
+
case Contacts.People.OFFLINE:
default:
return com.android.internal.R.drawable.presence_offline;
@@ -1229,7 +1238,7 @@
*/
public interface OrganizationColumns {
/**
- * The type of the the phone number.
+ * The type of the organizations.
* <P>Type: INTEGER (one of the constants below)</P>
*/
public static final String TYPE = "type";
@@ -1446,28 +1455,27 @@
* This is the intent that is fired when a search suggestion is clicked on.
*/
public static final String SEARCH_SUGGESTION_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED;
/**
- * This is the intent that is fired when a search suggestion for dialing a number
+ * This is the intent that is fired when a search suggestion for dialing a number
* is clicked on.
*/
public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED;
/**
* This is the intent that is fired when a search suggestion for creating a contact
* is clicked on.
*/
public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED;
/**
* 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.
*/
- public static final String ATTACH_IMAGE =
- "com.android.contacts.action.ATTACH_IMAGE";
+ public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE;
/**
* Takes as input a data URI with a mailto: or tel: scheme. If a single
@@ -1493,7 +1501,7 @@
* prompting the user when the contact doesn't exist.
*/
public static final String SHOW_OR_CREATE_CONTACT =
- "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+ ContactsContract.Intents.SHOW_OR_CREATE_CONTACT;
/**
* Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
@@ -1502,9 +1510,8 @@
* <p>
* Type: BOOLEAN
*/
- public static final String EXTRA_FORCE_CREATE =
- "com.android.contacts.action.FORCE_CREATE";
-
+ public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE;
+
/**
* Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
* description to be shown when prompting user about creating a new
@@ -1513,7 +1520,16 @@
* Type: STRING
*/
public static final String EXTRA_CREATE_DESCRIPTION =
- "com.android.contacts.action.CREATE_DESCRIPTION";
+ ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * dialog location using screen coordinates. When not specified, the
+ * dialog will be centered.
+ *
+ * @hide pending API council review
+ */
+ public static final String EXTRA_TARGET_RECT = ContactsContract.Intents.EXTRA_TARGET_RECT;
/**
* Intents related to the Contacts app UI.
@@ -1522,43 +1538,42 @@
/**
* The action for the default contacts list tab.
*/
- public static final String LIST_DEFAULT =
- "com.android.contacts.action.LIST_DEFAULT";
+ public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
/**
* The action for the contacts list tab.
*/
public static final String LIST_GROUP_ACTION =
- "com.android.contacts.action.LIST_GROUP";
+ ContactsContract.Intents.UI.LIST_GROUP_ACTION;
/**
* When in LIST_GROUP_ACTION mode, this is the group to display.
*/
- public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
-
+ public static final String GROUP_NAME_EXTRA_KEY =
+ ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
/**
* The action for the all contacts list tab.
*/
public static final String LIST_ALL_CONTACTS_ACTION =
- "com.android.contacts.action.LIST_ALL_CONTACTS";
+ ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
/**
* The action for the contacts with phone numbers list tab.
*/
public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
- "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+ ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
/**
* The action for the starred contacts list tab.
*/
public static final String LIST_STARRED_ACTION =
- "com.android.contacts.action.LIST_STARRED";
+ ContactsContract.Intents.UI.LIST_STARRED_ACTION;
/**
* The action for the frequent contacts list tab.
*/
public static final String LIST_FREQUENT_ACTION =
- "com.android.contacts.action.LIST_FREQUENT";
+ ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
/**
* The action for the "strequent" contacts list tab. It first lists the starred
@@ -1566,15 +1581,15 @@
* order of the number of times they have been contacted.
*/
public static final String LIST_STREQUENT_ACTION =
- "com.android.contacts.action.LIST_STREQUENT";
+ ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
/**
* A key for to be used as an intent extra to set the activity
* title to a custom String value.
*/
public static final String TITLE_EXTRA_KEY =
- "com.android.contacts.extra.TITLE_EXTRA";
-
+ ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
+
/**
* Activity Action: Display a filtered list of contacts
* <p>
@@ -1583,15 +1598,15 @@
* <p>
* Output: Nothing.
*/
- public static final String FILTER_CONTACTS_ACTION =
- "com.android.contacts.action.FILTER_CONTACTS";
-
+ public static final String FILTER_CONTACTS_ACTION =
+ ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
+
/**
* Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
* intents to supply the text on which to filter.
*/
- public static final String FILTER_TEXT_EXTRA_KEY =
- "com.android.contacts.extra.FILTER_TEXT";
+ public static final String FILTER_TEXT_EXTRA_KEY =
+ ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
}
/**
@@ -1600,170 +1615,179 @@
*/
public static final class Insert {
/** The action code to use when adding a contact */
- public static final String ACTION = Intent.ACTION_INSERT;
-
+ public static final String ACTION = ContactsContract.Intents.Insert.ACTION;
/**
* If present, forces a bypass of quick insert mode.
*/
- public static final String FULL_MODE = "full_mode";
-
+ public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE;
/**
* The extra field for the contact name.
* <P>Type: String</P>
*/
- public static final String NAME = "name";
+ public static final String NAME = ContactsContract.Intents.Insert.NAME;
/**
* The extra field for the contact phonetic name.
* <P>Type: String</P>
*/
- public static final String PHONETIC_NAME = "phonetic_name";
+ public static final String PHONETIC_NAME =
+ ContactsContract.Intents.Insert.PHONETIC_NAME;
/**
* The extra field for the contact company.
* <P>Type: String</P>
*/
- public static final String COMPANY = "company";
+ public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY;
/**
* The extra field for the contact job title.
* <P>Type: String</P>
*/
- public static final String JOB_TITLE = "job_title";
+ public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE;
/**
* The extra field for the contact notes.
* <P>Type: String</P>
*/
- public static final String NOTES = "notes";
+ public static final String NOTES = ContactsContract.Intents.Insert.NOTES;
/**
* The extra field for the contact phone number.
* <P>Type: String</P>
*/
- public static final String PHONE = "phone";
+ public static final String PHONE = ContactsContract.Intents.Insert.PHONE;
/**
* The extra field for the contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String PHONE_TYPE = "phone_type";
+ public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE;
/**
* The extra field for the phone isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String PHONE_ISPRIMARY = "phone_isprimary";
+ public static final String PHONE_ISPRIMARY =
+ ContactsContract.Intents.Insert.PHONE_ISPRIMARY;
/**
* The extra field for an optional second contact phone number.
* <P>Type: String</P>
*/
- public static final String SECONDARY_PHONE = "secondary_phone";
+ public static final String SECONDARY_PHONE =
+ ContactsContract.Intents.Insert.SECONDARY_PHONE;
/**
* The extra field for an optional second contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+ public static final String SECONDARY_PHONE_TYPE =
+ ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE;
/**
* The extra field for an optional third contact phone number.
* <P>Type: String</P>
*/
- public static final String TERTIARY_PHONE = "tertiary_phone";
+ public static final String TERTIARY_PHONE =
+ ContactsContract.Intents.Insert.TERTIARY_PHONE;
/**
* The extra field for an optional third contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+ public static final String TERTIARY_PHONE_TYPE =
+ ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE;
/**
* The extra field for the contact email address.
* <P>Type: String</P>
*/
- public static final String EMAIL = "email";
+ public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL;
/**
* The extra field for the contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String EMAIL_TYPE = "email_type";
+ public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE;
/**
* The extra field for the email isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String EMAIL_ISPRIMARY = "email_isprimary";
+ public static final String EMAIL_ISPRIMARY =
+ ContactsContract.Intents.Insert.EMAIL_ISPRIMARY;
/**
* The extra field for an optional second contact email address.
* <P>Type: String</P>
*/
- public static final String SECONDARY_EMAIL = "secondary_email";
+ public static final String SECONDARY_EMAIL =
+ ContactsContract.Intents.Insert.SECONDARY_EMAIL;
/**
* The extra field for an optional second contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+ public static final String SECONDARY_EMAIL_TYPE =
+ ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE;
/**
* The extra field for an optional third contact email address.
* <P>Type: String</P>
*/
- public static final String TERTIARY_EMAIL = "tertiary_email";
+ public static final String TERTIARY_EMAIL =
+ ContactsContract.Intents.Insert.TERTIARY_EMAIL;
/**
* The extra field for an optional third contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+ public static final String TERTIARY_EMAIL_TYPE =
+ ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE;
/**
* The extra field for the contact postal address.
* <P>Type: String</P>
*/
- public static final String POSTAL = "postal";
+ public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL;
/**
* The extra field for the contact postal address type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String POSTAL_TYPE = "postal_type";
+ public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE;
/**
* The extra field for the postal isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+ public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY;
/**
* The extra field for an IM handle.
* <P>Type: String</P>
*/
- public static final String IM_HANDLE = "im_handle";
+ public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE;
/**
* The extra field for the IM protocol
* <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
* or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
*/
- public static final String IM_PROTOCOL = "im_protocol";
+ public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL;
/**
* The extra field for the IM isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String IM_ISPRIMARY = "im_isprimary";
+ 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
new file mode 100644
index 0000000..11cb87f
--- /dev/null
+++ b/core/java/android/provider/ContactsContract.java
@@ -0,0 +1,1854 @@
+/*
+ * 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.provider;
+
+import android.content.Intent;
+import android.content.ContentProviderClient;
+import android.content.ContentProviderOperation;
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.accounts.Account;
+import android.os.RemoteException;
+
+/**
+ * The contract between the contacts provider and applications. Contains definitions
+ * for the supported URIs and columns.
+ *
+ * @hide
+ */
+public final class ContactsContract {
+ /** The authority for the contacts provider */
+ public static final String AUTHORITY = "com.android.contacts";
+ /** A content:// style uri to the authority for the contacts provider */
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ public interface SyncStateColumns extends SyncStateContract.Columns {
+ }
+
+ public static final class SyncState {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private SyncState() {}
+
+ public static final String CONTENT_DIRECTORY =
+ SyncStateContract.Constants.CONTENT_DIRECTORY;
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, CONTENT_DIRECTORY);
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#get
+ */
+ public static byte[] get(ContentProviderClient provider, Account account)
+ throws RemoteException {
+ return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#set
+ */
+ public static void set(ContentProviderClient provider, Account account, byte[] data)
+ throws RemoteException {
+ SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#newSetOperation
+ */
+ public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
+ return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
+ }
+ }
+
+ /**
+ * Generic columns for use by sync adapters. The specific functions of
+ * these columns are private to the sync adapter. Other clients of the API
+ * should not attempt to either read or write this column.
+ */
+ private interface BaseSyncColumns {
+
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC1 = "sync1";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC2 = "sync2";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC3 = "sync3";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC4 = "sync4";
+ }
+
+ /**
+ * Columns that appear when each row of a table belongs to a specific
+ * account, including sync information that an account may need.
+ */
+ private interface SyncColumns extends BaseSyncColumns {
+ /**
+ * 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";
+
+ /**
+ * String that uniquely identifies this row to its source account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SOURCE_ID = "sourceid";
+
+ /**
+ * Version number that is updated whenever this row or its related data
+ * changes.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String VERSION = "version";
+
+ /**
+ * Flag indicating that {@link #VERSION} has changed, and this row needs
+ * to be synchronized by its owning account.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DIRTY = "dirty";
+ }
+
+ public interface ContactOptionsColumns {
+ /**
+ * The number of times a person has been contacted
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TIMES_CONTACTED = "times_contacted";
+
+ /**
+ * The last time a person was contacted.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_TIME_CONTACTED = "last_time_contacted";
+
+ /**
+ * Is the contact starred?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String STARRED = "starred";
+
+ /**
+ * A custom ringtone associated with a person. Not always present.
+ * <P>Type: TEXT (URI to the ringtone)</P>
+ */
+ public static final String CUSTOM_RINGTONE = "custom_ringtone";
+
+ /**
+ * Whether the person should always be sent to voicemail. Not always
+ * present.
+ * <P>Type: INTEGER (0 for false, 1 for true)</P>
+ */
+ public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
+ }
+
+ private interface ContactsColumns {
+ /**
+ * The display name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * Reference to the row in the data table holding the photo.
+ * <P>Type: INTEGER REFERENCES data(_id)</P>
+ */
+ public static final String PHOTO_ID = "photo_id";
+
+ /**
+ * Lookup value that reflects the {@link Groups#GROUP_VISIBLE} state of
+ * any {@link 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.
+ */
+ public static final String PRESENCE_STATUS = Presence.PRESENCE_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>
+ */
+ public static final String HAS_PHONE_NUMBER = "has_phone_number";
+ }
+
+ /**
+ * Constants for the contacts table, which contains a record per group
+ * of raw contact representing the same person.
+ */
+ public static class Contacts implements BaseColumns, ContactsColumns,
+ ContactOptionsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Contacts() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
+
+ /**
+ * The content:// style URI for this table joined with useful data from
+ * {@link Data}.
+ */
+ public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "contacts_summary");
+
+ /**
+ * The content:// style URI used for "type-to-filter" functionality on the
+ * {@link #CONTENT_SUMMARY_URI} URI. The filter string will be used to match
+ * various parts of the contact name. The filter argument should be passed
+ * as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_SUMMARY_FILTER_URI = Uri.withAppendedPath(
+ CONTENT_SUMMARY_URI, "filter");
+
+ /**
+ * The content:// style URI for this table joined with useful data from
+ * {@link Data}, filtered to include only starred contacts
+ * and the most frequently contacted contacts.
+ */
+ public static final Uri CONTENT_SUMMARY_STREQUENT_URI = Uri.withAppendedPath(
+ CONTENT_SUMMARY_URI, "strequent");
+
+ /**
+ * The content:// style URI used for "type-to-filter" functionality on the
+ * {@link #CONTENT_SUMMARY_STREQUENT_URI} URI. The filter string will be used to match
+ * various parts of the contact name. The filter argument should be passed
+ * as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_SUMMARY_STREQUENT_FILTER_URI = Uri.withAppendedPath(
+ CONTENT_SUMMARY_STREQUENT_URI, "filter");
+
+ public static final Uri CONTENT_SUMMARY_GROUP_URI = Uri.withAppendedPath(
+ CONTENT_SUMMARY_URI, "group");
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
+
+ /**
+ * A sub-directory of a single contact that contains all of the constituent raw contact
+ * {@link Data} rows.
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Data() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "data";
+ }
+
+ /**
+ * A sub-directory of a single contact aggregate that contains all aggregation suggestions
+ * (other contacts). The aggregation suggestions are computed based on approximate
+ * data matches with this contact.
+ */
+ public static final class AggregationSuggestions implements BaseColumns, ContactsColumns {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private AggregationSuggestions() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "suggestions";
+
+ /**
+ * An optional query parameter that can be supplied to limit the number of returned
+ * suggestions.
+ * <p>
+ * Type: INTEGER
+ *
+ * @deprecated Please use the "limit" parameter
+ */
+ @Deprecated
+ public static final String MAX_SUGGESTIONS = "max_suggestions";
+ }
+ }
+
+ private interface RawContactsColumns {
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this
+ * data belongs to.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * Flag indicating that this {@link RawContacts} entry and its children has
+ * been restricted to specific platform apps.
+ * <P>Type: INTEGER (boolean)</P>
+ *
+ * @hide until finalized in future platform release
+ */
+ public static final String IS_RESTRICTED = "is_restricted";
+
+ /**
+ * The aggregation mode for this contact.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String AGGREGATION_MODE = "aggregation_mode";
+
+ /**
+ * The "deleted" flag: "0" by default, "1" if the row has been marked
+ * for deletion. When {@link android.content.ContentResolver#delete} is
+ * called on a raw contact, it is marked for deletion and removed from its
+ * aggregate contact. The sync adaptor deletes the raw contact on the server and
+ * then calls ContactResolver.delete once more, this time passing the
+ * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DELETED = "deleted";
+ }
+
+ /**
+ * Constants for the raw_contacts table, which contains the base contact
+ * information per sync source. Sync adapters and contact management apps
+ * are the primary consumers of this API.
+ */
+ public static final class RawContacts implements BaseColumns, RawContactsColumns,
+ ContactOptionsColumns, SyncColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private RawContacts() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
+
+ /**
+ * The content:// style URL for filtering people by email address. The
+ * filter argument should be passed as an additional path segment after
+ * this URI.
+ *
+ * @hide
+ */
+ @Deprecated
+ public static final Uri CONTENT_FILTER_EMAIL_URI =
+ Uri.withAppendedPath(CONTENT_URI, "filter_email");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
+
+ /**
+ * Query parameter that can be passed with the {@link #CONTENT_URI} URI
+ * to the {@link android.content.ContentResolver#delete} method to
+ * indicate that the raw contact can be deleted physically, rather than
+ * merely marked as deleted.
+ */
+ public static final String DELETE_PERMANENTLY = "delete_permanently";
+
+ /**
+ * Aggregation mode: aggregate asynchronously.
+ */
+ public static final int AGGREGATION_MODE_DEFAULT = 0;
+
+ /**
+ * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
+ */
+ public static final int AGGREGATION_MODE_IMMEDITATE = 1;
+
+ /**
+ * 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;
+
+ /**
+ * A sub-directory of a single raw contact that contains all of their {@link Data} rows.
+ * To access this directory append
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Data() {
+ }
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "data";
+ }
+ }
+
+ private interface DataColumns {
+ /**
+ * The package name to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The MIME type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * A reference to the {@link RawContacts#_ID}
+ * that this data belongs to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+
+ /**
+ * Whether this is the primary entry of its kind for the raw contact it belongs to
+ * <P>Type: INTEGER (if set, non-0 means true)</P>
+ */
+ public static final String IS_PRIMARY = "is_primary";
+
+ /**
+ * Whether this is the primary entry of its kind for the aggregate
+ * contact it belongs to. Any data record that is "super primary" must
+ * also be "primary".
+ * <P>Type: INTEGER (if set, non-0 means true)</P>
+ */
+ public static final String IS_SUPER_PRIMARY = "is_super_primary";
+
+ /**
+ * The version of this data record. This is a read-only value. The data column is
+ * guaranteed to not change without the version going up. This value is monotonically
+ * increasing.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_VERSION = "data_version";
+
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA1 = "data1";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA2 = "data2";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA3 = "data3";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA4 = "data4";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA5 = "data5";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA6 = "data6";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA7 = "data7";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA8 = "data8";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA9 = "data9";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA10 = "data10";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA11 = "data11";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA12 = "data12";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA13 = "data13";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA14 = "data14";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA15 = "data15";
+
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC1 = "data_sync1";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC2 = "data_sync2";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC3 = "data_sync3";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC4 = "data_sync4";
+
+ /**
+ * An optional insert, update or delete URI parameter that determines if
+ * the corresponding raw contact should be marked as dirty. The default
+ * value is true.
+ */
+ public static final String MARK_AS_DIRTY = "mark_as_dirty";
+ }
+
+ /**
+ * Constants for the data table, which contains data points tied to a raw contact.
+ * For example, a phone number or email address. Each row in this table contains a type
+ * definition and some generic columns. Each data type can define the meaning for each of
+ * the generic columns.
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Data() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of data.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
+ }
+
+ /**
+ * 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}.
+ */
+ public static final class PhoneLookup implements BaseColumns, DataColumns, ContactsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private PhoneLookup() {}
+
+ /**
+ * The content:// style URI for this table. Append the phone number you want to lookup
+ * to this URI and query it to perform a lookup. For example:
+ *
+ * {@code
+ * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, phoneNumber);
+ * }
+ */
+ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "phone_lookup");
+ }
+
+ /**
+ * Additional data mixed in with {@link Im.CommonPresenceColumns} to link
+ * back to specific {@link ContactsContract.Contacts#_ID} entries.
+ */
+ private interface PresenceColumns {
+
+ /**
+ * The unique ID for a row.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String _ID = "presence_id";
+
+ /**
+ * Reference to the {@link RawContacts#_ID} this presence references.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String RAW_CONTACT_ID = "presence_raw_contact_id";
+
+ /**
+ * Reference to the {@link Data#_ID} entry that owns this presence.
+ * <P>Type: INTEGER</P>
+ */
+ 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>
+ */
+ 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: TEXT</P>
+ */
+ public static final String IM_HANDLE = "im_handle";
+
+ /**
+ * The IM account for the local user that the presence data came from.
+ * <P>Type: TEXT</P>
+ */
+ public static final String IM_ACCOUNT = "im_account";
+ }
+
+ public static final class Presence implements PresenceColumns, Im.CommonPresenceColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Presence() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "presence");
+
+ /**
+ * Gets the resource ID for the proper presence icon.
+ *
+ * @param status the status to get the icon for
+ * @return the resource ID for the proper presence icon
+ */
+ public static final int getPresenceIconResourceId(int status) {
+ switch (status) {
+ case AVAILABLE:
+ return android.R.drawable.presence_online;
+ case IDLE:
+ case AWAY:
+ return android.R.drawable.presence_away;
+ case DO_NOT_DISTURB:
+ return android.R.drawable.presence_busy;
+ case INVISIBLE:
+ return android.R.drawable.presence_invisible;
+ case OFFLINE:
+ default:
+ return android.R.drawable.presence_offline;
+ }
+ }
+
+ /**
+ * Returns the precedence of the status code the higher number being the higher precedence.
+ *
+ * @param status The status code.
+ * @return An integer representing the precedence, 0 being the lowest.
+ */
+ public static final int getPresencePrecedence(int status) {
+ // Keep this function here incase we want to enforce a different precedence than the
+ // natural order of the status constants.
+ return status;
+ }
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * presence details.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-presence";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * presence detail.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im-presence";
+ }
+
+ /**
+ * Container for definitions of common data types stored in the {@link Data} table.
+ */
+ public static final class CommonDataKinds {
+ /**
+ * The {@link Data#RES_PACKAGE} value for common data that should be
+ * shown using a default style.
+ */
+ public static final String PACKAGE_COMMON = "common";
+
+ /**
+ * Columns common across the specific types.
+ */
+ private interface BaseCommonColumns {
+ /**
+ * The package name to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The MIME type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * The {@link RawContacts#_ID} that this data belongs to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+ }
+
+ /**
+ * The base types that all "Typed" data kinds support.
+ */
+ public interface BaseTypes {
+
+ /**
+ * A custom type. The custom label should be supplied by user.
+ */
+ public static int TYPE_CUSTOM = 0;
+ }
+
+ /**
+ * Columns common across the specific types.
+ */
+ private interface CommonColumns extends BaseTypes{
+ /**
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "data1";
+
+ /**
+ * The data for the contact method.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA = "data2";
+
+ /**
+ * The user defined label for the the contact method.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "data3";
+ }
+
+ /**
+ * Parts of the name.
+ */
+ public static final class StructuredName implements BaseCommonColumns {
+ private StructuredName() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
+
+ /**
+ * The given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GIVEN_NAME = "data1";
+
+ /**
+ * The family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String FAMILY_NAME = "data2";
+
+ /**
+ * The contact's honorific prefix, e.g. "Sir"
+ * <P>Type: TEXT</P>
+ */
+ public static final String PREFIX = "data3";
+
+ /**
+ * The contact's middle name
+ * <P>Type: TEXT</P>
+ */
+ public static final String MIDDLE_NAME = "data4";
+
+ /**
+ * The contact's honorific suffix, e.g. "Jr"
+ */
+ public static final String SUFFIX = "data5";
+
+ /**
+ * The phonetic version of the given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_GIVEN_NAME = "data6";
+
+ /**
+ * The phonetic version of the additional name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_MIDDLE_NAME = "data7";
+
+ /**
+ * The phonetic version of the family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_FAMILY_NAME = "data8";
+
+ /**
+ * The name that should be used to display the contact.
+ * <i>Unstructured component of the name should be consistent with
+ * its structured representation.</i>
+ * <p>
+ * Type: TEXT
+ */
+ public static final String DISPLAY_NAME = "data9";
+ }
+
+ /**
+ * A nickname.
+ */
+ public static final class Nickname implements CommonColumns, BaseCommonColumns {
+ private Nickname() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
+
+ public static final int TYPE_DEFAULT = 1;
+ public static final int TYPE_OTHER_NAME = 2;
+ public static final int TYPE_MAINDEN_NAME = 3;
+ public static final int TYPE_SHORT_NAME = 4;
+ public static final int TYPE_INITIALS = 5;
+
+ /**
+ * The name itself
+ */
+ public static final String NAME = DATA;
+ }
+
+ /**
+ * Common data definition for telephone numbers.
+ */
+ public static final class Phone implements BaseCommonColumns, CommonColumns {
+ private Phone() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * phones.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "phones");
+
+ /**
+ * The content:// style URI for filtering data records of the
+ * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data. The filter argument should
+ * be passed as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
+ "filter");
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_MOBILE = 2;
+ public static final int TYPE_WORK = 3;
+ public static final int TYPE_FAX_WORK = 4;
+ public static final int TYPE_FAX_HOME = 5;
+ public static final int TYPE_PAGER = 6;
+ public static final int TYPE_OTHER = 7;
+ public static final int TYPE_CALLBACK = 8;
+ public static final int TYPE_CAR = 9;
+ public static final int TYPE_COMPANY_MAIN = 10;
+ public static final int TYPE_ISDN = 11;
+ public static final int TYPE_MAIN = 12;
+ public static final int TYPE_OTHER_FAX = 13;
+ public static final int TYPE_RADIO = 14;
+ public static final int TYPE_TELEX = 15;
+ public static final int TYPE_TTY_TDD = 16;
+ public static final int TYPE_WORK_MOBILE = 17;
+ public static final int TYPE_WORK_PAGER = 18;
+ public static final int TYPE_ASSISTANT = 19;
+
+ /**
+ * The phone number as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NUMBER = DATA;
+ }
+
+ /**
+ * Common data definition for email addresses.
+ */
+ public static final class Email implements BaseCommonColumns, CommonColumns {
+ private Email() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link Email#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "emails");
+
+ /**
+ * The content:// style URL for filtering data rows by email address. The
+ * filter argument should be passed as an additional path segment after
+ * this URI.
+ */
+ public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI,
+ "filter");
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ /**
+ * The display name for the email address
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "data4";
+ }
+
+ /**
+ * Common data definition for postal addresses.
+ */
+ public static final class StructuredPostal implements BaseCommonColumns, CommonColumns {
+ private StructuredPostal() {
+ }
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address";
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * postal addresses.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link StructuredPostal#CONTENT_ITEM_TYPE} MIME type.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "postals");
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ /**
+ * The full, unstructured postal address. <i>This field must be
+ * consistent with any structured data.</i>
+ * <p>
+ * Type: TEXT
+ */
+ public static final String FORMATTED_ADDRESS = DATA;
+
+ /**
+ * The agent who actually receives the mail. Used in work addresses.
+ * Also for 'in care of' or 'c/o'.
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String AGENT = "data4";
+
+ /**
+ * Used in places where houses or buildings have names (and not
+ * necessarily numbers), eg. "The Pillars".
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String HOUSENAME = "data5";
+
+ /**
+ * Can be street, avenue, road, etc. This element also includes the
+ * house number and room/apartment/flat/floor number.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String STREET = "data6";
+
+ /**
+ * Covers actual P.O. boxes, drawers, locked bags, etc. This is
+ * usually but not always mutually exclusive with street.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String POBOX = "data7";
+
+ /**
+ * This is used to disambiguate a street address when a city
+ * contains more than one street with the same name, or to specify a
+ * small place whose mail is routed through a larger postal town. In
+ * China it could be a county or a minor city.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String NEIGHBORHOOD = "data8";
+
+ /**
+ * Can be city, village, town, borough, etc. This is the postal town
+ * and not necessarily the place of residence or place of business.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String CITY = "data9";
+
+ /**
+ * Handles administrative districts such as U.S. or U.K. counties
+ * that are not used for mail addressing purposes. Subregion is not
+ * intended for delivery addresses.
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String SUBREGION = "data10";
+
+ /**
+ * A state, province, county (in Ireland), Land (in Germany),
+ * departement (in France), etc.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String REGION = "data11";
+
+ /**
+ * Postal code. Usually country-wide, but sometimes specific to the
+ * city (e.g. "2" in "Dublin 2, Ireland" addresses).
+ * <p>
+ * Type: TEXT
+ */
+ public static final String POSTCODE = "data12";
+
+ /**
+ * The name or code of the country.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String COUNTRY = "data13";
+ }
+
+ /**
+ * Common data definition for IM addresses.
+ */
+ public static final class Im implements BaseCommonColumns, CommonColumns {
+ private Im() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ 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>
+ */
+ public static final int PROTOCOL_CUSTOM = -1;
+ public static final int PROTOCOL_AIM = 0;
+ public static final int PROTOCOL_MSN = 1;
+ public static final int PROTOCOL_YAHOO = 2;
+ public static final int PROTOCOL_SKYPE = 3;
+ public static final int PROTOCOL_QQ = 4;
+ public static final int PROTOCOL_GOOGLE_TALK = 5;
+ public static final int PROTOCOL_ICQ = 6;
+ public static final int PROTOCOL_JABBER = 7;
+ public static final int PROTOCOL_NETMEETING = 8;
+ }
+
+ /**
+ * Common data definition for organizations.
+ */
+ public static final class Organization implements BaseCommonColumns, CommonColumns {
+ private Organization() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
+
+ public static final int TYPE_WORK = 1;
+ public static final int TYPE_OTHER = 2;
+
+ /**
+ * The company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String COMPANY = DATA;
+
+ /**
+ * The position title at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE = "data4";
+
+ /**
+ * The department at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DEPARTMENT = "data5";
+
+ /**
+ * The job description at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String JOB_DESCRIPTION = "data6";
+
+ /**
+ * The symbol of this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SYMBOL = "data7";
+
+ /**
+ * The phonetic name of this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_NAME = "data8";
+ }
+
+ /**
+ * Common data definition for miscellaneous information.
+ */
+ public static final class Miscellaneous implements BaseCommonColumns {
+ private Miscellaneous() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/misc";
+
+ /**
+ * The birthday as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String BIRTHDAY = "data1";
+
+ /**
+ * The nickname as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NICKNAME = "data2";
+ }
+
+ /**
+ * Common data definition for relations.
+ */
+ public static final class Relation implements BaseCommonColumns, CommonColumns {
+ private Relation() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
+
+ public static final int TYPE_ASSISTANT = 1;
+ public static final int TYPE_BROTHER = 2;
+ public static final int TYPE_CHILD = 3;
+ public static final int TYPE_DOMESTIC_PARTNER = 4;
+ public static final int TYPE_FATHER = 5;
+ public static final int TYPE_FRIEND = 6;
+ public static final int TYPE_MANAGER = 7;
+ public static final int TYPE_MOTHER = 8;
+ public static final int TYPE_PARENT = 9;
+ public static final int TYPE_PARTNER = 10;
+ public static final int TYPE_REFERRED_BY = 11;
+ public static final int TYPE_RELATIVE = 12;
+ public static final int TYPE_SISTER = 13;
+ public static final int TYPE_SPOUSE = 14;
+
+ /**
+ * The name of the relative as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NAME = DATA;
+ }
+
+ /**
+ * Common data definition for events.
+ */
+ public static final class Event implements BaseCommonColumns, CommonColumns {
+ private Event() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/event";
+
+ public static final int TYPE_ANNIVERSARY = 1;
+ public static final int TYPE_OTHER = 2;
+
+ /**
+ * The event start date as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String START_DATE = DATA;
+ }
+
+ /**
+ * Photo of the contact.
+ */
+ public static final class Photo implements BaseCommonColumns {
+ private Photo() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
+
+ /**
+ * Thumbnail photo of the raw contact. This is the raw bytes of an image
+ * that could be inflated using {@link BitmapFactory}.
+ * <p>
+ * Type: BLOB
+ */
+ public static final String PHOTO = "data1";
+ }
+
+ /**
+ * Notes about the contact.
+ */
+ public static final class Note implements BaseCommonColumns {
+ private Note() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
+
+ /**
+ * The note text.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NOTE = "data1";
+ }
+
+ /**
+ * Group Membership.
+ */
+ public static final class GroupMembership implements BaseCommonColumns {
+ private GroupMembership() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE =
+ "vnd.android.cursor.item/group_membership";
+
+ /**
+ * The row id of the group that this group membership refers to. Exactly one of
+ * this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String GROUP_ROW_ID = "data1";
+
+ /**
+ * The sourceid of the group that this group membership refers to. Exactly one of
+ * this or {@link #GROUP_ROW_ID} must be set when inserting a row.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GROUP_SOURCE_ID = "group_sourceid";
+ }
+
+ /**
+ * Website related to the contact.
+ */
+ public static final class Website implements BaseCommonColumns, CommonColumns {
+ private Website() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
+
+ public static final int TYPE_HOMEPAGE = 1;
+ public static final int TYPE_BLOG = 2;
+ public static final int TYPE_PROFILE = 3;
+ public static final int TYPE_HOME = 4;
+ public static final int TYPE_WORK = 5;
+ public static final int TYPE_FTP = 6;
+ public static final int TYPE_OTHER = 7;
+
+ /**
+ * The website URL string.
+ * <P>Type: TEXT</P>
+ */
+ public static final String URL = "data1";
+ }
+ }
+
+ public interface GroupsColumns {
+ /**
+ * The display title of this group.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * The package name to use when creating {@link Resources} objects for
+ * this group. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The display title of this group to load as a resource from
+ * {@link #RES_PACKAGE}, which may be localized.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE_RES = "title_res";
+
+ /**
+ * Notes about the group.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String NOTES = "notes";
+
+ /**
+ * The ID of this group if it is a System Group, i.e. a group that has a special meaning
+ * to the sync adapter, null otherwise.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SYSTEM_ID = "system_id";
+
+ /**
+ * The total number of {@link Contacts} that have
+ * {@link GroupMembership} in this group. Read-only value that is only
+ * present when querying {@link Groups#CONTENT_SUMMARY_URI}.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SUMMARY_COUNT = "summ_count";
+
+ /**
+ * The total number of {@link Contacts} that have both
+ * {@link GroupMembership} in this group, and also have phone numbers.
+ * Read-only value that is only present when querying
+ * {@link Groups#CONTENT_SUMMARY_URI}.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SUMMARY_WITH_PHONES = "summ_phones";
+
+ /**
+ * Flag indicating if the contacts belonging to this group should be
+ * visible in any user interface.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String GROUP_VISIBLE = "group_visible";
+
+ /**
+ * The "deleted" flag: "0" by default, "1" if the row has been marked
+ * for deletion. When {@link android.content.ContentResolver#delete} is
+ * called on a raw contact, it is marked for deletion and removed from its
+ * aggregate contact. The sync adaptor deletes the raw contact on the server and
+ * then calls ContactResolver.delete once more, this time passing the
+ * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+ * <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";
+ }
+
+ /**
+ * Constants for the groups table.
+ */
+ public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Groups() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups");
+
+ /**
+ * The content:// style URI for this table joined with details data from
+ * {@link Data}.
+ */
+ public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "groups_summary");
+
+ /**
+ * The MIME type of a directory of groups.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
+
+ /**
+ * The MIME type of a single group.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
+
+ /**
+ * Query parameter that can be passed with the {@link #CONTENT_URI} URI
+ * to the {@link android.content.ContentResolver#delete} method to
+ * indicate that the raw contact can be deleted physically, rather than
+ * merely marked as deleted.
+ */
+ public static final String DELETE_PERMANENTLY = "delete_permanently";
+
+ /**
+ * An optional update or insert URI parameter that determines if the
+ * group should be marked as dirty. The default value is true.
+ */
+ public static final String MARK_AS_DIRTY = "mark_as_dirty";
+ }
+
+ /**
+ * Constants for the contact aggregation exceptions table, which contains
+ * aggregation rules overriding those used by automatic aggregation. This type only
+ * supports query and update. Neither insert nor delete are supported.
+ */
+ public static final class AggregationExceptions implements BaseColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private AggregationExceptions() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "aggregation_exceptions");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of data.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of an aggregation exception
+ */
+ public static final String CONTENT_ITEM_TYPE =
+ "vnd.android.cursor.item/aggregation_exception";
+
+ /**
+ * The type of exception: {@link #TYPE_KEEP_IN}, {@link #TYPE_KEEP_OUT} or
+ * {@link #TYPE_AUTOMATIC}.
+ *
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "type";
+
+ /**
+ * Allows the provider to automatically decide whether the aggregate
+ * contact should include a particular raw contact or not.
+ */
+ public static final int TYPE_AUTOMATIC = 0;
+
+ /**
+ * Makes sure that the specified raw contact is included in the
+ * specified aggregate contact.
+ */
+ public static final int TYPE_KEEP_IN = 1;
+
+ /**
+ * Makes sure that the specified raw contact is NOT included in the
+ * specified aggregate contact.
+ */
+ public static final int TYPE_KEEP_OUT = 2;
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the
+ * aggregate contact that the rule applies to.
+ */
+ public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+ }
+
+ /**
+ * Contains helper classes used to create or manage {@link android.content.Intent Intents}
+ * that involve contacts.
+ */
+ public static final class Intents {
+ /**
+ * This is the intent that is fired when a search suggestion is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+
+ /**
+ * This is the intent that is fired when a search suggestion for dialing a number
+ * is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+
+ /**
+ * This is the intent that is fired when a search suggestion for creating a contact
+ * is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+
+ /**
+ * 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.
+ */
+ public static final String ATTACH_IMAGE =
+ "com.android.contacts.action.ATTACH_IMAGE";
+
+ /**
+ * Takes as input a data URI with a mailto: or tel: scheme. If a single
+ * contact exists with the given data it will be shown. If no contact
+ * exists, a dialog will ask the user if they want to create a new
+ * contact with the provided details filled in. If multiple contacts
+ * share the data the user will be prompted to pick which contact they
+ * want to view.
+ * <p>
+ * For <code>mailto:</code> URIs, the scheme specific portion must be a
+ * raw email address, such as one built using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * For <code>tel:</code> URIs, the scheme specific portion is compared
+ * to existing numbers using the standard caller ID lookup algorithm.
+ * The number must be properly encoded, for example using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * Any extras from the {@link Insert} class will be passed along to the
+ * create activity if there are no contacts to show.
+ * <p>
+ * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
+ * prompting the user when the contact doesn't exist.
+ */
+ public static final String SHOW_OR_CREATE_CONTACT =
+ "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+
+ /**
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
+ * contact if no matching contact found. Otherwise, default behavior is
+ * to prompt user with dialog before creating.
+ * <p>
+ * Type: BOOLEAN
+ */
+ public static final String EXTRA_FORCE_CREATE =
+ "com.android.contacts.action.FORCE_CREATE";
+
+ /**
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
+ * description to be shown when prompting user about creating a new
+ * contact.
+ * <p>
+ * Type: STRING
+ */
+ public static final String EXTRA_CREATE_DESCRIPTION =
+ "com.android.contacts.action.CREATE_DESCRIPTION";
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * dialog location using screen coordinates. When not specified, the
+ * dialog will be centered.
+ */
+ public static final String EXTRA_TARGET_RECT = "target_rect";
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * desired dialog style, usually a variation on size. One of
+ * {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
+ */
+ public static final String EXTRA_MODE = "mode";
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a small-sized dialog.
+ */
+ public static final int MODE_SMALL = 1;
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a medium-sized dialog.
+ */
+ public static final int MODE_MEDIUM = 2;
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a large-sized dialog.
+ */
+ public static final int MODE_LARGE = 3;
+
+ /**
+ * Intents related to the Contacts app UI.
+ */
+ public static final class UI {
+ /**
+ * The action for the default contacts list tab.
+ */
+ public static final String LIST_DEFAULT =
+ "com.android.contacts.action.LIST_DEFAULT";
+
+ /**
+ * The action for the contacts list tab.
+ */
+ public static final String LIST_GROUP_ACTION =
+ "com.android.contacts.action.LIST_GROUP";
+
+ /**
+ * When in LIST_GROUP_ACTION mode, this is the group to display.
+ */
+ public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
+
+ /**
+ * The action for the all contacts list tab.
+ */
+ public static final String LIST_ALL_CONTACTS_ACTION =
+ "com.android.contacts.action.LIST_ALL_CONTACTS";
+
+ /**
+ * The action for the contacts with phone numbers list tab.
+ */
+ public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
+ "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+
+ /**
+ * The action for the starred contacts list tab.
+ */
+ public static final String LIST_STARRED_ACTION =
+ "com.android.contacts.action.LIST_STARRED";
+
+ /**
+ * The action for the frequent contacts list tab.
+ */
+ public static final String LIST_FREQUENT_ACTION =
+ "com.android.contacts.action.LIST_FREQUENT";
+
+ /**
+ * The action for the "strequent" contacts list tab. It first lists the starred
+ * contacts in alphabetical order and then the frequent contacts in descending
+ * order of the number of times they have been contacted.
+ */
+ public static final String LIST_STREQUENT_ACTION =
+ "com.android.contacts.action.LIST_STREQUENT";
+
+ /**
+ * A key for to be used as an intent extra to set the activity
+ * title to a custom String value.
+ */
+ public static final String TITLE_EXTRA_KEY =
+ "com.android.contacts.extra.TITLE_EXTRA";
+
+ /**
+ * Activity Action: Display a filtered list of contacts
+ * <p>
+ * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
+ * filtering
+ * <p>
+ * Output: Nothing.
+ */
+ public static final String FILTER_CONTACTS_ACTION =
+ "com.android.contacts.action.FILTER_CONTACTS";
+
+ /**
+ * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
+ * intents to supply the text on which to filter.
+ */
+ public static final String FILTER_TEXT_EXTRA_KEY =
+ "com.android.contacts.extra.FILTER_TEXT";
+ }
+
+ /**
+ * Convenience class that contains string constants used
+ * to create contact {@link android.content.Intent Intents}.
+ */
+ public static final class Insert {
+ /** The action code to use when adding a contact */
+ public static final String ACTION = Intent.ACTION_INSERT;
+
+ /**
+ * If present, forces a bypass of quick insert mode.
+ */
+ public static final String FULL_MODE = "full_mode";
+
+ /**
+ * The extra field for the contact name.
+ * <P>Type: String</P>
+ */
+ public static final String NAME = "name";
+
+ // TODO add structured name values here.
+
+ /**
+ * The extra field for the contact phonetic name.
+ * <P>Type: String</P>
+ */
+ public static final String PHONETIC_NAME = "phonetic_name";
+
+ /**
+ * The extra field for the contact company.
+ * <P>Type: String</P>
+ */
+ public static final String COMPANY = "company";
+
+ /**
+ * The extra field for the contact job title.
+ * <P>Type: String</P>
+ */
+ public static final String JOB_TITLE = "job_title";
+
+ /**
+ * The extra field for the contact notes.
+ * <P>Type: String</P>
+ */
+ public static final String NOTES = "notes";
+
+ /**
+ * The extra field for the contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String PHONE = "phone";
+
+ /**
+ * The extra field for the contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String PHONE_TYPE = "phone_type";
+
+ /**
+ * The extra field for the phone isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String PHONE_ISPRIMARY = "phone_isprimary";
+
+ /**
+ * The extra field for an optional second contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String SECONDARY_PHONE = "secondary_phone";
+
+ /**
+ * The extra field for an optional second contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+
+ /**
+ * The extra field for an optional third contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String TERTIARY_PHONE = "tertiary_phone";
+
+ /**
+ * The extra field for an optional third contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+
+ /**
+ * The extra field for the contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String EMAIL = "email";
+
+ /**
+ * The extra field for the contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String EMAIL_TYPE = "email_type";
+
+ /**
+ * The extra field for the email isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String EMAIL_ISPRIMARY = "email_isprimary";
+
+ /**
+ * The extra field for an optional second contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String SECONDARY_EMAIL = "secondary_email";
+
+ /**
+ * The extra field for an optional second contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+
+ /**
+ * The extra field for an optional third contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String TERTIARY_EMAIL = "tertiary_email";
+
+ /**
+ * The extra field for an optional third contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+
+ /**
+ * The extra field for the contact postal address.
+ * <P>Type: String</P>
+ */
+ public static final String POSTAL = "postal";
+
+ /**
+ * The extra field for the contact postal address type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String POSTAL_TYPE = "postal_type";
+
+ /**
+ * The extra field for the postal isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+
+ /**
+ * The extra field for an IM handle.
+ * <P>Type: String</P>
+ */
+ public static final String IM_HANDLE = "im_handle";
+
+ /**
+ * The extra field for the IM protocol
+ * <P>Type: the result of {@link CommonDataKinds.Im#encodePredefinedImProtocol(int)}
+ * or {@link CommonDataKinds.Im#encodeCustomImProtocol(String)}.</P>
+ */
+ public static final String IM_PROTOCOL = "im_protocol";
+
+ /**
+ * The extra field for the IM isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String IM_ISPRIMARY = "im_isprimary";
+ }
+ }
+
+}
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 4c58e0d..790fe5c 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -63,7 +63,7 @@
* that had initiated a download when that download completes. The
* download's content: uri is specified in the intent's data.
*/
- public static final String DOWNLOAD_COMPLETED_ACTION =
+ public static final String ACTION_DOWNLOAD_COMPLETED =
"android.intent.action.DOWNLOAD_COMPLETED";
/**
@@ -76,7 +76,7 @@
* Note: this is not currently sent for downloads that have completed
* successfully.
*/
- public static final String NOTIFICATION_CLICKED_ACTION =
+ public static final String ACTION_NOTIFICATION_CLICKED =
"android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
/**
@@ -84,14 +84,14 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String URI = "uri";
+ public static final String COLUMN_URI = "uri";
/**
* The name of the column containing application-specific data.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String APP_DATA = "entity";
+ public static final String COLUMN_APP_DATA = "entity";
/**
* The name of the column containing the flags that indicates whether
@@ -104,7 +104,7 @@
* <P>Type: BOOLEAN</P>
* <P>Owner can Init</P>
*/
- public static final String NO_INTEGRITY = "no_integrity";
+ public static final String COLUMN_NO_INTEGRITY = "no_integrity";
/**
* The name of the column containing the filename that the initiating
@@ -113,7 +113,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String FILENAME_HINT = "hint";
+ public static final String COLUMN_FILE_NAME_HINT = "hint";
/**
* The name of the column containing the filename where the downloaded data
@@ -128,7 +128,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String MIMETYPE = "mimetype";
+ public static final String COLUMN_MIME_TYPE = "mimetype";
/**
* The name of the column containing the flag that controls the destination
@@ -136,7 +136,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Init</P>
*/
- public static final String DESTINATION = "destination";
+ public static final String COLUMN_DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
@@ -145,7 +145,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String VISIBILITY = "visibility";
+ public static final String COLUMN_VISIBILITY = "visibility";
/**
* The name of the column containing the current control state of the download.
@@ -154,7 +154,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String CONTROL = "control";
+ public static final String COLUMN_CONTROL = "control";
/**
* The name of the column containing the current status of the download.
@@ -163,7 +163,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String STATUS = "status";
+ public static final String COLUMN_STATUS = "status";
/**
* The name of the column containing the date at which some interesting
@@ -172,7 +172,7 @@
* <P>Type: BIGINT</P>
* <P>Owner can Read</P>
*/
- public static final String LAST_MODIFICATION = "lastmod";
+ public static final String COLUMN_LAST_MODIFICATION = "lastmod";
/**
* The name of the column containing the package name of the application
@@ -181,7 +181,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String NOTIFICATION_PACKAGE = "notificationpackage";
+ public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
/**
* The name of the column containing the component name of the class that
@@ -191,7 +191,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String NOTIFICATION_CLASS = "notificationclass";
+ public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
/**
* If extras are specified when requesting a download they will be provided in the intent that
@@ -199,7 +199,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String NOTIFICATION_EXTRAS = "notificationextras";
+ public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
/**
* The name of the column contain the values of the cookie to be used for
@@ -208,7 +208,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String COOKIE_DATA = "cookiedata";
+ public static final String COLUMN_COOKIE_DATA = "cookiedata";
/**
* The name of the column containing the user agent that the initiating
@@ -216,7 +216,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String USER_AGENT = "useragent";
+ public static final String COLUMN_USER_AGENT = "useragent";
/**
* The name of the column containing the referer (sic) that the initiating
@@ -224,7 +224,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String REFERER = "referer";
+ public static final String COLUMN_REFERER = "referer";
/**
* The name of the column containing the total size of the file being
@@ -232,7 +232,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String TOTAL_BYTES = "total_bytes";
+ public static final String COLUMN_TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
@@ -240,7 +240,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String CURRENT_BYTES = "current_bytes";
+ public static final String COLUMN_CURRENT_BYTES = "current_bytes";
/**
* The name of the column where the initiating application can provide the
@@ -252,7 +252,7 @@
* <P>Type: INTEGER</P>
* <P>Owner can Init</P>
*/
- public static final String OTHER_UID = "otheruid";
+ public static final String COLUMN_OTHER_UID = "otheruid";
/**
* The name of the column where the initiating application can provided the
@@ -261,7 +261,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String TITLE = "title";
+ public static final String COLUMN_TITLE = "title";
/**
* The name of the column where the initiating application can provide the
@@ -270,7 +270,7 @@
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String DESCRIPTION = "description";
+ public static final String COLUMN_DESCRIPTION = "description";
/*
* Lists the destinations that an application can specify for a download.
diff --git a/core/java/android/provider/DrmStore.java b/core/java/android/provider/DrmStore.java
index db71854..c438ac4 100644
--- a/core/java/android/provider/DrmStore.java
+++ b/core/java/android/provider/DrmStore.java
@@ -35,7 +35,7 @@
/**
* The DRM provider contains forward locked DRM content.
- *
+ *
* @hide
*/
public final class DrmStore
@@ -43,13 +43,13 @@
private static final String TAG = "DrmStore";
public static final String AUTHORITY = "drm";
-
+
/**
* This is in the Manifest class of the drm provider, but that isn't visible
* in the framework.
*/
private static final String ACCESS_DRM_PERMISSION = "android.permission.ACCESS_DRM";
-
+
/**
* Fields for DRM database
*/
@@ -82,18 +82,18 @@
}
public interface Images extends Columns {
-
+
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/images");
}
-
+
public interface Audio extends Columns {
-
+
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/audio");
}
/**
* Utility function for inserting a file into the DRM content provider.
- *
+ *
* @param cr The content resolver to use
* @param file The file to insert
* @param title The title for the content (or null)
@@ -101,12 +101,46 @@
*/
public static final Intent addDrmFile(ContentResolver cr, File file, String title) {
FileInputStream fis = null;
- OutputStream os = null;
Intent result = null;
try {
fis = new FileInputStream(file);
- DrmRawContent content = new DrmRawContent(fis, (int) file.length(),
+ if (title == null) {
+ title = file.getName();
+ int lastDot = title.lastIndexOf('.');
+ if (lastDot > 0) {
+ title = title.substring(0, lastDot);
+ }
+ }
+ result = addDrmFile(cr, fis, title);
+ } catch (Exception e) {
+ Log.e(TAG, "pushing file failed", e);
+ } finally {
+ try {
+ if (fis != null)
+ fis.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Utility function for inserting a file stream into the DRM content provider.
+ *
+ * @param cr The content resolver to use
+ * @param fileStream The FileInputStream to insert
+ * @param title The title for the content (or null)
+ * @return uri to the DRM record or null
+ */
+ public static final Intent addDrmFile(ContentResolver cr, FileInputStream fis, String title) {
+ OutputStream os = null;
+ Intent result = null;
+
+ try {
+ DrmRawContent content = new DrmRawContent(fis, (int) fis.available(),
DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
String mimeType = content.getContentType();
@@ -126,14 +160,6 @@
if (contentUri != null) {
ContentValues values = new ContentValues(3);
- // compute title from file name, if it is not specified
- if (title == null) {
- title = file.getName();
- int lastDot = title.lastIndexOf('.');
- if (lastDot > 0) {
- title = title.substring(0, lastDot);
- }
- }
values.put(DrmStore.Columns.TITLE, title);
values.put(DrmStore.Columns.SIZE, size);
values.put(DrmStore.Columns.MIME_TYPE, mimeType);
@@ -162,7 +188,7 @@
if (os != null)
os.close();
} catch (IOException e) {
- Log.e(TAG, "IOException in DrmTest.onCreate()", e);
+ Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
}
}
@@ -172,7 +198,7 @@
/**
* Utility function to enforce any permissions required to access DRM
* content.
- *
+ *
* @param context A context used for checking calling permission.
*/
public static void enforceAccessDrmPermission(Context context) {
@@ -181,5 +207,5 @@
throw new SecurityException("Requires DRM permission");
}
}
-
+
}
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index c4b29ae..5702e7c 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -83,7 +83,7 @@
public static final String LABEL_OUTBOX = "^^out";
public static final String AUTHORITY = "gmail-ls";
- private static final String TAG = "gmail-ls";
+ private static final String TAG = "Gmail";
private static final String AUTHORITY_PLUS_CONVERSATIONS =
"content://" + AUTHORITY + "/conversations/";
private static final String AUTHORITY_PLUS_LABELS =
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index 19ad158..b1cf648 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -871,14 +871,22 @@
}
/**
- * The common columns for both one-to-one chat messages or group chat messages.
+ * The common columns for messages table
*/
- public interface BaseMessageColumns {
+ public interface MessageColumns {
/**
- * The user this message belongs to
- * <P>Type: TEXT</P>
+ * The thread_id column stores the contact id of the contact the message belongs to.
+ * For groupchat messages, the thread_id stores the group id, which is the contact id
+ * of the temporary group contact created for the groupchat. So there should be no
+ * collision between groupchat message thread id and regular message thread id.
*/
- String CONTACT = "contact";
+ String THREAD_ID = "thread_id";
+
+ /**
+ * The nickname. This is used for groupchat messages to indicate the participant's
+ * nickname. For non groupchat messages, this field should be left empty.
+ */
+ String NICKNAME = "nickname";
/**
* The body
@@ -917,68 +925,193 @@
* <P>Type: STRING</P>
*/
String PACKET_ID = "packet_id";
- }
-
- /**
- * Columns from the Messages table.
- */
- public interface MessagesColumns extends BaseMessageColumns{
- /**
- * The provider id
- * <P> Type: INTEGER </P>
- */
- String PROVIDER = "provider";
/**
- * The account id
- * <P> Type: INTEGER </P>
+ * Is groupchat message or not
+ * <P>Type: INTEGER</P>
*/
- String ACCOUNT = "account";
+ String IS_GROUP_CHAT = "is_muc";
}
/**
* This table contains messages.
*/
- public static final class Messages implements BaseColumns, MessagesColumns {
+ public static final class Messages implements BaseColumns, MessageColumns {
/**
* no public constructor since this is a utility class
*/
private Messages() {}
/**
- * Gets the Uri to query messages by contact.
+ * Gets the Uri to query messages by thread id.
*
- * @param providerId the provider id of the contact.
+ * @param threadId the thread id of the message.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByThreadId(long threadId) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_THREAD_ID.buildUpon();
+ ContentUris.appendId(builder, threadId);
+ return builder.build();
+ }
+
+ /**
+ * @deprecated
+ *
+ * Gets the Uri to query messages by account and contact.
+ *
* @param accountId the account id of the contact.
* @param username the user name of the contact.
* @return the Uri
*/
- public static final Uri getContentUriByContact(long providerId,
- long accountId, String username) {
- Uri.Builder builder = CONTENT_URI_MESSAGES_BY.buildUpon();
- ContentUris.appendId(builder, providerId);
+ public static final Uri getContentUriByContact(long accountId, String username) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT.buildUpon();
ContentUris.appendId(builder, accountId);
builder.appendPath(username);
return builder.build();
}
/**
+ * Gets the Uri to query messages by provider.
+ *
+ * @param providerId the service provider id.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByProvider(long providerId) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_PROVIDER.buildUpon();
+ ContentUris.appendId(builder, providerId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by account.
+ *
+ * @param accountId the account id.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByAccount(long accountId) {
+ Uri.Builder builder = CONTENT_URI_BY_ACCOUNT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by thread id.
+ *
+ * @param threadId the thread id of the message.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByThreadId(long threadId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID.buildUpon();
+ ContentUris.appendId(builder, threadId);
+ return builder.build();
+ }
+
+ /**
+ * @deprecated
+ *
+ * Gets the Uri to query off the record messages by account and contact.
+ *
+ * @param accountId the account id of the contact.
+ * @param username the user name of the contact.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByContact(long accountId, String username) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ builder.appendPath(username);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by provider.
+ *
+ * @param providerId the service provider id.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByProvider(long providerId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_PROVIDER.buildUpon();
+ ContentUris.appendId(builder, providerId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by account.
+ *
+ * @param accountId the account id.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByAccount(long accountId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ return builder.build();
+ }
+
+ /**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI =
- Uri.parse("content://im/messages");
+ Uri.parse("content://im/messages");
/**
- * The content:// style URL for messages by provider and account
+ * The content:// style URL for messages by thread id
*/
- public static final Uri CONTENT_URI_MESSAGES_BY =
- Uri.parse("content://im/messagesBy");
+ public static final Uri CONTENT_URI_MESSAGES_BY_THREAD_ID =
+ Uri.parse("content://im/messagesByThreadId");
+
+ /**
+ * The content:// style URL for messages by account and contact
+ */
+ public static final Uri CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT =
+ Uri.parse("content://im/messagesByAcctAndContact");
+
+ /**
+ * The content:// style URL for messages by provider
+ */
+ public static final Uri CONTENT_URI_MESSAGES_BY_PROVIDER =
+ Uri.parse("content://im/messagesByProvider");
+
+ /**
+ * The content:// style URL for messages by account
+ */
+ public static final Uri CONTENT_URI_BY_ACCOUNT =
+ Uri.parse("content://im/messagesByAccount");
+
+ /**
+ * The content:// style url for off the record messages
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI =
+ Uri.parse("content://im/otrMessages");
+
+ /**
+ * The content:// style url for off the record messages by thread id
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID =
+ Uri.parse("content://im/otrMessagesByThreadId");
+
+ /**
+ * The content:// style url for off the record messages by account and contact
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT =
+ Uri.parse("content://im/otrMessagesByAcctAndContact");
+
+ /**
+ * The content:// style URL for off the record messages by provider
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PROVIDER =
+ Uri.parse("content://im/otrMessagesByProvider");
+
+ /**
+ * The content:// style URL for off the record messages by account
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT =
+ Uri.parse("content://im/otrMessagesByAccount");
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-messages";
+ public static final String CONTENT_TYPE =
+ "vnd.android.cursor.dir/im-messages";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
@@ -992,6 +1125,11 @@
*/
public static final String DEFAULT_SORT_ORDER = "date ASC";
+ /**
+ * The "contact" column. This is not a real column in the messages table, but a
+ * temoprary column created when querying for messages (joined with the contacts table)
+ */
+ public static final String CONTACT = "contact";
}
/**
@@ -1119,67 +1257,6 @@
}
/**
- * Columns from the GroupMessages table
- */
- public interface GroupMessageColumns extends BaseMessageColumns {
- /**
- * The group this message belongs to
- * <p>Type: TEXT</p>
- */
- String GROUP = "groupId";
- }
-
- /**
- * This table contains group messages.
- */
- public final static class GroupMessages implements BaseColumns,
- GroupMessageColumns {
- private GroupMessages() {}
-
- /**
- * Gets the Uri to query group messages by group.
- *
- * @param groupId the group id.
- * @return the Uri
- */
- public static final Uri getContentUriByGroup(long groupId) {
- Uri.Builder builder = CONTENT_URI_GROUP_MESSAGES_BY.buildUpon();
- ContentUris.appendId(builder, groupId);
- return builder.build();
- }
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://im/groupMessages");
-
- /**
- * The content:// style URL for group messages by provider and account
- */
- public static final Uri CONTENT_URI_GROUP_MESSAGES_BY =
- Uri.parse("content://im/groupMessagesBy");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * group messages.
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-groupMessages";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * group message.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/im-groupMessages";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "date ASC";
- }
-
- /**
* Columns from the Avatars table
*/
public interface AvatarsColumns {
@@ -1534,6 +1611,18 @@
/** specifies whether or not to show mobile indicator to friends */
public static final String SETTING_SHOW_MOBILE_INDICATOR = "mobile_indicator";
+ /** specifies whether or not to show as away when device is idle */
+ public static final String SETTING_SHOW_AWAY_ON_IDLE = "show_away_on_idle";
+
+ /** specifies whether or not to upload heartbeat stat upon login */
+ public static final String SETTING_UPLOAD_HEARTBEAT_STAT = "upload_heartbeat_stat";
+
+ /** 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
@@ -1742,6 +1831,47 @@
showMobileIndicator);
}
+ /**
+ * A convenience method to set whether or not to show as away when device is idle.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param showAway Whether or not to show as away when device is idle.
+ */
+ public static void setShowAwayOnIdle(ContentResolver contentResolver,
+ long providerId, boolean showAway) {
+ putBooleanValue(contentResolver, providerId, SETTING_SHOW_AWAY_ON_IDLE, showAway);
+ }
+
+ /**
+ * A convenience method to set whether or not to upload heartbeat stat.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param uploadStat Whether or not to upload heartbeat stat.
+ */
+ public static void setUploadHeartbeatStat(ContentResolver contentResolver,
+ long providerId, boolean uploadStat) {
+ putBooleanValue(contentResolver, providerId, SETTING_UPLOAD_HEARTBEAT_STAT, uploadStat);
+ }
+
+ /**
+ * A convenience method to set the heartbeat interval last received from the server.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param interval The heartbeat interval last received from the server.
+ */
+ public static void setHeartbeatInterval(ContentResolver contentResolver,
+ long providerId, long interval) {
+ 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;
@@ -1872,6 +2002,79 @@
}
/**
+ * Set whether or not to show as away when device is idle.
+ *
+ * @param showAway whether or not to show as away when device is idle.
+ */
+ public void setShowAwayOnIdle(boolean showAway) {
+ ProviderSettings.setShowAwayOnIdle(mContentResolver, mProviderId, showAway);
+ }
+
+ /**
+ * Get whether or not to show as away when device is idle.
+ *
+ * @return Whether or not to show as away when device is idle.
+ */
+ public boolean getShowAwayOnIdle() {
+ return getBoolean(SETTING_SHOW_AWAY_ON_IDLE,
+ true /* by default show as away on idle*/);
+ }
+
+ /**
+ * Set whether or not to upload heartbeat stat.
+ *
+ * @param uploadStat whether or not to upload heartbeat stat.
+ */
+ public void setUploadHeartbeatStat(boolean uploadStat) {
+ ProviderSettings.setUploadHeartbeatStat(mContentResolver, mProviderId, uploadStat);
+ }
+
+ /**
+ * Get whether or not to upload heartbeat stat.
+ *
+ * @return Whether or not to upload heartbeat stat.
+ */
+ public boolean getUploadHeartbeatStat() {
+ return getBoolean(SETTING_UPLOAD_HEARTBEAT_STAT,
+ false /* by default do not upload */);
+ }
+
+ /**
+ * Set the last received heartbeat interval from the server.
+ *
+ * @param interval the last received heartbeat interval from the server.
+ */
+ public void setHeartbeatInterval(long interval) {
+ ProviderSettings.setHeartbeatInterval(mContentResolver, mProviderId, interval);
+ }
+
+ /**
+ * Get the last received heartbeat interval from the server.
+ *
+ * @return the last received heartbeat interval from the server.
+ */
+ public long getHeartbeatInterval() {
+ return getLong(SETTING_HEARTBEAT_INTERVAL, 0L /* an invalid default interval */);
+ }
+
+ /**
+ * 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.
*
@@ -1909,21 +2112,77 @@
ContentValues values = getValues(name);
return values != null ? values.getAsInteger(VALUE) : def;
}
+
+ /**
+ * Convenience function for retrieving a single settings value
+ * as a Long.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def The value to return if the setting is not defined.
+ * @return The setting's current value or 'def' if it is not defined.
+ */
+ private long getLong(String name, long def) {
+ ContentValues values = getValues(name);
+ return values != null ? values.getAsLong(VALUE) : def;
+ }
}
}
+
+ /**
+ * Columns for IM branding resource map cache table. This table caches the result of
+ * loading the branding resources to speed up IM landing page start.
+ */
+ public interface BrandingResourceMapCacheColumns {
+ /**
+ * The provider ID
+ * <P>Type: INTEGER</P>
+ */
+ String PROVIDER_ID = "provider_id";
+ /**
+ * The application resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String APP_RES_ID = "app_res_id";
+ /**
+ * The plugin resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String PLUGIN_RES_ID = "plugin_res_id";
+ }
+
+ /**
+ * The table for caching the result of loading IM branding resources.
+ */
+ public static final class BrandingResourceMapCache
+ implements BaseColumns, BrandingResourceMapCacheColumns {
+ /**
+ * The content:// style URL for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+ }
+
+
+
+ /**
+ * //TODO: move these to MCS specific provider.
+ * The following are MCS stuff, and should really live in a separate provider specific to
+ * MCS code.
+ */
+
/**
* Columns from OutgoingRmq table
*/
public interface OutgoingRmqColumns {
String RMQ_ID = "rmq_id";
- String TYPE = "type";
String TIMESTAMP = "ts";
String DATA = "data";
+ String PROTOBUF_TAG = "type";
}
/**
+ * //TODO: we should really move these to their own provider and database.
* The table for storing outgoing rmq packets.
*/
public static final class OutgoingRmq implements BaseColumns, OutgoingRmqColumns {
@@ -1986,6 +2245,7 @@
}
/**
+ * //TODO: move these out into their own provider and database
* The table for storing the last client rmq id sent to the server.
*/
public static final class LastRmqId implements BaseColumns, LastRmqIdColumns {
@@ -2046,35 +2306,21 @@
}
/**
- * Columns for IM branding resource map cache table. This table caches the result of
- * loading the branding resources to speed up IM landing page start.
+ * Columns for the s2dRmqIds table, which stores the server-to-device message
+ * persistent ids. These are used in the RMQ2 protocol, where in the login request, the
+ * client selective acks these s2d ids to the server.
*/
- public interface BrandingResourceMapCacheColumns {
- /**
- * The provider ID
- * <P>Type: INTEGER</P>
- */
- String PROVIDER_ID = "provider_id";
- /**
- * The application resource ID
- * <P>Type: INTEGER</P>
- */
- String APP_RES_ID = "app_res_id";
- /**
- * The plugin resource ID
- * <P>Type: INTEGER</P>
- */
- String PLUGIN_RES_ID = "plugin_res_id";
+ public interface ServerToDeviceRmqIdsColumn {
+ String RMQ_ID = "rmq_id";
}
- /**
- * The table for caching the result of loading IM branding resources.
- */
- public static final class BrandingResourceMapCache
- implements BaseColumns, BrandingResourceMapCacheColumns {
+ public static final class ServerToDeviceRmqIds implements BaseColumns,
+ ServerToDeviceRmqIdsColumn {
+
/**
* The content:// style URL for this table.
*/
- public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+ public static final Uri CONTENT_URI = Uri.parse("content://im/s2dids");
}
+
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9a9ddc9..d3e4c4c 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);
@@ -879,6 +877,17 @@
public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
/**
+ * A comma separated list of radios that should to be disabled when airplane mode
+ * is on, but can be manually reenabled by the user. For example, if RADIO_WIFI is
+ * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi
+ * will be turned off when entering airplane mode, but the user will be able to reenable
+ * Wifi in the Settings app.
+ *
+ * {@hide}
+ */
+ public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
+
+ /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -1182,6 +1191,22 @@
public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
/**
+ * Persistent store for the system-wide default alarm alert.
+ *
+ * @see #RINGTONE
+ * @see #DEFAULT_ALARM_ALERT_URI
+ */
+ public static final String ALARM_ALERT = "alarm_alert";
+
+ /**
+ * A {@link Uri} that will point to the current default alarm alert at
+ * any given time.
+ *
+ * @see #DEFAULT_ALARM_ALERT_URI
+ */
+ public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
+
+ /**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
@@ -1968,6 +1993,12 @@
public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
/**
+ * Whether assisted GPS should be enabled or not.
+ * @hide
+ */
+ public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
+
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
@@ -2695,7 +2726,14 @@
* Controls how many attempts Gmail will try to upload an uphill operations before it
* abandons the operation. Defaults to 20.
*/
- public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
+ public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_num_retry_uphill_op";
+
+ /**
+ * How much time in seconds Gmail will try to upload an uphill operations before it
+ * abandons the operation. Defaults to 36400 (one day).
+ */
+ public static final String GMAIL_WAIT_TIME_RETRY_UPHILL_OP =
+ "gmail_wait_time_retry_uphill_op";
/**
* Controls if the protocol buffer version of the protocol will use a multipart request for
@@ -2804,6 +2842,12 @@
"gtalk_nosync_heartbeat_ping_interval_ms";
/**
+ * The maximum heartbeat interval used while on the WIFI network.
+ */
+ public static final String GTALK_SERVICE_WIFI_MAX_HEARTBEAT_INTERVAL_MS =
+ "gtalk_wifi_max_heartbeat_ping_interval_ms";
+
+ /**
* How long we wait to receive a heartbeat ping acknowledgement (or another packet)
* from the GTalk server, before deeming the connection dead.
*/
@@ -2856,6 +2900,71 @@
public static final String GTALK_USE_BARE_JID_TIMEOUT_MS = "gtalk_use_barejid_timeout_ms";
/**
+ * This is the threshold of retry number when there is an authentication expired failure
+ * for Google Talk. In some situation, e.g. when a Google Apps account is disabled chat
+ * service, the connection keeps failing. This threshold controls when we should stop
+ * the retrying.
+ */
+ public static final String GTALK_MAX_RETRIES_FOR_AUTH_EXPIRED =
+ "gtalk_max_retries_for_auth_expired";
+
+ /**
+ * a boolean setting indicating whether the GTalkService should use RMQ2 protocol or not.
+ */
+ public static final String GTALK_USE_RMQ2_PROTOCOL =
+ "gtalk_use_rmq2";
+
+ /**
+ * a boolean setting indicating whether the GTalkService should support both RMQ and
+ * RMQ2 protocols. This setting is true for the transitional period when we need to
+ * support both protocols.
+ */
+ public static final String GTALK_SUPPORT_RMQ_AND_RMQ2_PROTOCOLS =
+ "gtalk_support_rmq_and_rmq2";
+
+ /**
+ * a boolean setting controlling whether the rmq2 protocol will include stream ids in
+ * the protobufs. This is used for debugging.
+ */
+ public static final String GTALK_RMQ2_INCLUDE_STREAM_ID =
+ "gtalk_rmq2_include_stream_id";
+
+ /**
+ * This is gdata url to lookup album and picture info from picasa web.
+ */
+ public static final String GTALK_PICASA_ALBUM_URL =
+ "gtalk_picasa_album_url";
+
+ /**
+ * This is the url to lookup picture info from flickr.
+ */
+ public static final String GTALK_FLICKR_PHOTO_INFO_URL =
+ "gtalk_flickr_photo_info_url";
+
+ /**
+ * This is the url to lookup an actual picture from flickr.
+ */
+ public static final String GTALK_FLICKR_PHOTO_URL =
+ "gtalk_flickr_photo_url";
+
+ /**
+ * This is the gdata url to lookup info on a youtube video.
+ */
+ public static final String GTALK_YOUTUBE_VIDEO_URL =
+ "gtalk_youtube_video_url";
+
+ /**
+ * This is the url for getting the app token for server-to-device push messaging.
+ */
+ public static final String PUSH_MESSAGING_REGISTRATION_URL =
+ "push_messaging_registration_url";
+
+ /**
+ * Use android://<it> routing infos for Google Sync Server subcriptions.
+ */
+ public static final String GSYNC_USE_RMQ2_ROUTING_INFO = "gsync_use_rmq2_routing_info";
+
+ /**
* Enable use of ssl session caching.
* 'db' - save each session in a (per process) database
* 'file' - save each session in a (per process) file
@@ -2907,6 +3016,12 @@
"vending_require_sim_for_purchase";
/**
+ * Indicates the Vending Machine backup state. It is set if the
+ * Vending application has been backed up at least once.
+ */
+ public static final String VENDING_BACKUP_STATE = "vending_backup_state";
+
+ /**
* The current version id of the Vending Machine terms of service.
*/
public static final String VENDING_TOS_VERSION = "vending_tos_version";
@@ -3213,39 +3328,6 @@
"short_keylight_delay_ms";
/**
- * URL that points to the voice search servers. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_URL = "voice_search_url";
-
- /**
- * Speech encoding used with voice search on 3G networks. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENCODING_THREE_G = "voice_search_encoding_three_g";
-
- /**
- * Speech encoding used with voice search on WIFI networks. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENCODING_WIFI = "voice_search_encoding_wifi";
-
- /**
- * Whether to use automatic gain control in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_AGC = "voice_search_enable_agc";
-
- /**
- * Whether to use noise suppression in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_NS = "voice_search_enable_ns";
-
- /**
- * Whether to use the IIR filter in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_IIR = "voice_search_enable_iir";
-
- /**
* List of test suites (local disk filename) for the automatic instrumentation test runner.
* The file format is similar to automated_suites.xml, see AutoTesterService.
* If this setting is missing or empty, the automatic test runner will not start.
@@ -3288,6 +3370,14 @@
public static final String USE_LOCATION_FOR_SERVICES = "use_location";
/**
+ * The length of the calendar sync window into the future.
+ * This specifies the number of days into the future for the sliding window sync.
+ * Setting this to zero will disable sliding sync.
+ */
+ public static final String GOOGLE_CALENDAR_SYNC_WINDOW_DAYS =
+ "google_calendar_sync_window_days";
+
+ /**
* @deprecated
* @hide
*/
@@ -3530,42 +3620,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/SocialContract.java b/core/java/android/provider/SocialContract.java
new file mode 100644
index 0000000..ee271ba
--- /dev/null
+++ b/core/java/android/provider/SocialContract.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.provider;
+
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+
+/**
+ * The contract between the social provider and applications. Contains
+ * definitions for the supported URIs and columns.
+ *
+ * @hide
+ */
+public class SocialContract {
+ /** The authority for the social provider */
+ public static final String AUTHORITY = "com.android.social";
+
+ /** A content:// style uri to the authority for the contacts provider */
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ private interface ActivitiesColumns {
+ /**
+ * The package name to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The mime-type of this social activity.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * Internal raw identifier for this social activity. This field is
+ * analogous to the <code>atom:id</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String RAW_ID = "raw_id";
+
+ /**
+ * Reference to another {@link Activities#RAW_ID} that this social activity
+ * is replying to. This field is analogous to the
+ * <code>thr:in-reply-to</code> element defined in RFC 4685.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String IN_REPLY_TO = "in_reply_to";
+
+ /**
+ * Reference to the {@link android.provider.ContactsContract.Contacts#_ID} that authored
+ * this social activity. This field is analogous to the <code>atom:author</code>
+ * element defined in RFC 4287.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String AUTHOR_CONTACT_ID = "author_contact_id";
+
+ /**
+ * Optional reference to the {@link android.provider.ContactsContract.Contacts#_ID} this
+ * social activity is targeted towards. If more than one direct target, this field may
+ * be left undefined. This field is analogous to the
+ * <code>activity:target</code> element defined in the Atom Activity
+ * Extensions Internet-Draft.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String TARGET_CONTACT_ID = "target_contact_id";
+
+ /**
+ * Timestamp when this social activity was published, in a
+ * {@link System#currentTimeMillis()} time base. This field is analogous
+ * to the <code>atom:published</code> element defined in RFC 4287.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String PUBLISHED = "published";
+
+ /**
+ * Timestamp when the original social activity in a thread was
+ * published. For activities that have an in-reply-to field specified, the
+ * content provider will automatically populate this field with the
+ * timestamp of the original activity.
+ * <p>
+ * This field is useful for sorting order of activities that keeps together all
+ * messages in each thread.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String THREAD_PUBLISHED = "thread_published";
+
+ /**
+ * Title of this social activity. This field is analogous to the
+ * <code>atom:title</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * Summary of this social activity. This field is analogous to the
+ * <code>atom:summary</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String SUMMARY = "summary";
+
+ /**
+ * A URI associated this social activity. This field is analogous to the
+ * <code>atom:link rel="alternate"</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String LINK = "link";
+
+ /**
+ * Optional thumbnail specific to this social activity. This is the raw
+ * bytes of an image that could be inflated using {@link BitmapFactory}.
+ * <p>
+ * Type: BLOB
+ */
+ public static final String THUMBNAIL = "thumbnail";
+ }
+
+ public static final class Activities implements BaseColumns, ActivitiesColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Activities() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "activities");
+
+ /**
+ * The content:// URI for this table filtered to the set of social activities
+ * authored by a specific {@link android.provider.ContactsContract.Contacts#_ID}.
+ */
+ public static final Uri CONTENT_AUTHORED_BY_URI =
+ Uri.withAppendedPath(CONTENT_URI, "authored_by");
+
+ /**
+ * The {@link Uri} for the latest social activity performed by any
+ * raw contact aggregated under the specified {@link Contacts#_ID}. Will
+ * also join with most-present {@link Presence} for this aggregate.
+ */
+ public static final Uri CONTENT_CONTACT_STATUS_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "contact_status");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of social
+ * activities.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/activity";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * social activity.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/activity";
+ }
+
+}
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index 4d430d5..8e9f402 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -20,6 +20,7 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import android.accounts.Account;
/**
* The SubscribedFeeds provider stores all information about subscribed feeds.
@@ -99,7 +100,7 @@
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
/**
@@ -114,38 +115,36 @@
* @return the Uri of the feed that was added
*/
public static Uri addFeed(ContentResolver resolver,
- String feed, String account,
+ String feed, Account account,
String authority, String service) {
ContentValues values = new ContentValues();
values.put(SubscribedFeeds.Feeds.FEED, feed);
- values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account);
+ 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);
}
public static int deleteFeed(ContentResolver resolver,
- String feed, String account, String authority) {
+ String feed, Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account, feed, authority});
+ where.toString(), new String[] {account.name, account.type, feed, authority});
}
public static int deleteFeeds(ContentResolver resolver,
- String account, String authority) {
+ Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ 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, authority});
- }
-
- public static String gtalkServiceRoutingInfoFromAccountAndResource(
- String account, String res) {
- return Uri.parse("gtalk://" + account + "/" + res).toString();
+ where.toString(), new String[] {account.name, account.type, authority});
}
/**
@@ -157,6 +156,12 @@
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ACCOUNT = SyncConstValue._SYNC_ACCOUNT;
+
+ /**
+ * The account type.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = SyncConstValue._SYNC_ACCOUNT_TYPE;
}
/**
@@ -199,6 +204,6 @@
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
}
diff --git a/core/java/android/provider/SyncConstValue.java b/core/java/android/provider/SyncConstValue.java
index 6eb4398..30966eb 100644
--- a/core/java/android/provider/SyncConstValue.java
+++ b/core/java/android/provider/SyncConstValue.java
@@ -29,6 +29,12 @@
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
+ * The type of the account that was used to sync the entry to the device.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
* <P>Type: TEXT</P>
*/
@@ -68,4 +74,9 @@
* Used to indicate that this account is not synced
*/
public static final String NON_SYNCABLE_ACCOUNT = "non_syncable";
+
+ /**
+ * Used to indicate that this account is not synced
+ */
+ public static final String NON_SYNCABLE_ACCOUNT_TYPE = "android.local";
}
diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
new file mode 100644
index 0000000..5c93af0
--- /dev/null
+++ b/core/java/android/provider/SyncStateContract.java
@@ -0,0 +1,125 @@
+/*
+ * 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.provider;
+
+import android.net.Uri;
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.ContentProviderOperation;
+import android.accounts.Account;
+import android.database.Cursor;
+import android.os.RemoteException;
+
+/**
+ * The ContentProvider contract for associating data with ana data array account.
+ * This may be used by providers that want to store this data in a standard way.
+ */
+public class SyncStateContract {
+ public interface Columns extends BaseColumns {
+ /**
+ * A reference to the name of the account to which this data belongs
+ * <P>Type: STRING</P>
+ */
+ public static final String ACCOUNT_NAME = "account_name";
+
+ /**
+ * A reference to the type of the account to which this data belongs
+ * <P>Type: STRING</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * The sync data associated with this account.
+ * <P>Type: NONE</P>
+ */
+ public static final String DATA = "data";
+ }
+
+ public static class Constants implements Columns {
+ public static final String CONTENT_DIRECTORY = "syncstate";
+ }
+
+ public static final class Helpers {
+ private static final String[] DATA_PROJECTION = new String[]{Columns.DATA};
+ private static final String SELECT_BY_ACCOUNT =
+ Columns.ACCOUNT_NAME + "=? AND " + Columns.ACCOUNT_TYPE + "=?";
+
+ /**
+ * Get the sync state that is associated with the account or null.
+ * @param provider the {@link ContentProviderClient} that is to be used to communicate
+ * with the {@link android.content.ContentProvider} that contains the sync state.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be returned
+ * @return the sync state or null if there is no sync state associated with the account
+ * @throws RemoteException if there is a failure communicating with the remote
+ * {@link android.content.ContentProvider}
+ */
+ 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.name, account.type}, null);
+ try {
+ if (c.moveToNext()) {
+ return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
+ }
+ } finally {
+ c.close();
+ }
+ return null;
+ }
+
+ /**
+ * Assigns the data array as the sync state for the given account.
+ * @param provider the {@link ContentProviderClient} that is to be used to communicate
+ * with the {@link android.content.ContentProvider} that contains the sync state.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be set
+ * @param data the byte[] that contains the sync state
+ * @throws RemoteException if there is a failure communicating with the remote
+ * {@link android.content.ContentProvider}
+ */
+ public static void set(ContentProviderClient provider, Uri uri,
+ Account account, byte[] data) throws RemoteException {
+ ContentValues values = new ContentValues();
+ values.put(Columns.DATA, data);
+ values.put(Columns.ACCOUNT_NAME, account.name);
+ values.put(Columns.ACCOUNT_TYPE, account.type);
+ provider.insert(uri, values);
+ }
+
+ /**
+ * Creates and returns a ContentProviderOperation that assigns the data array as the
+ * sync state for the given account.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be set
+ * @param data the byte[] that contains the sync state
+ * @return the new ContentProviderOperation that assigns the data array as the
+ * account's sync state
+ */
+ public static ContentProviderOperation newSetOperation(Uri uri,
+ Account account, byte[] data) {
+ ContentValues values = new ContentValues();
+ values.put(Columns.DATA, data);
+ return ContentProviderOperation
+ .newInsert(uri)
+ .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 c292c53..7a6f6bb 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -146,7 +146,13 @@
* <P>Type: TEXT</P>
*/
public static final String SERVICE_CENTER = "service_center";
- }
+
+ /**
+ * Has the message been locked?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String LOCKED = "locked";
+}
/**
* Contains all text based SMS messages.
@@ -1008,6 +1014,12 @@
* <P>Type: INTEGER</P>
*/
public static final String THREAD_ID = "thread_id";
+
+ /**
+ * Has the message been locked?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String LOCKED = "locked";
}
/**
@@ -1416,6 +1428,8 @@
*/
public static final String _DATA = "_data";
+ public static final String TEXT = "text";
+
}
public static final class Rate {
@@ -1493,6 +1507,14 @@
public static final Uri CONTENT_DRAFT_URI = Uri.parse(
"content://mms-sms/draft");
+ /***
+ * Pass in a query parameter called "pattern" which is the text
+ * to search for.
+ * The sort order is fixed to be thread_id ASC,date DESC.
+ */
+ public static final Uri SEARCH_URI = Uri.parse(
+ "content://mms-sms/search");
+
// Constants for message protocol types.
public static final int SMS_PROTO = 0;
public static final int MMS_PROTO = 1;
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 5c4e56d..d9fcb53 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -23,17 +23,17 @@
package android.server;
import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.media.AudioManager;
-import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
@@ -41,9 +41,10 @@
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 {
private static final String TAG = "BluetoothA2dpService";
@@ -54,36 +55,76 @@
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
- private static final String A2DP_SINK_ADDRESS = "a2dp_sink_address";
private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
private static final int MESSAGE_CONNECT_TO = 1;
- private static final int MESSAGE_DISCONNECT = 2;
+
+ private static final String PROPERTY_STATE = "State";
+
+ private static final String SINK_STATE_DISCONNECTED = "disconnected";
+ private static final String SINK_STATE_CONNECTING = "connecting";
+ private static final String SINK_STATE_CONNECTED = "connected";
+ private static final String SINK_STATE_PLAYING = "playing";
+
+ private static int mSinkCount;
private final Context mContext;
private final IntentFilter mIntentFilter;
- private HashMap<String, SinkState> mAudioDevices;
+ private HashMap<BluetoothDevice, Integer> mAudioDevices;
private final AudioManager mAudioManager;
- private final BluetoothDevice mBluetooth;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
- // list of disconnected sinks to process after a delay
- private final ArrayList<String> mPendingDisconnects = new ArrayList<String>();
- // number of active sinks
- private int mSinkCount = 0;
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ 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 BluetoothAdapter.BLUETOOTH_STATE_ON:
+ onBluetoothEnable();
+ break;
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
+ onBluetoothDisable();
+ break;
+ }
+ } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
+ int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
+ BluetoothError.ERROR);
+ switch(bondState) {
+ case BluetoothDevice.BOND_BONDED:
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO);
+ break;
+ case BluetoothDevice.BOND_BONDING:
+ case BluetoothDevice.BOND_NOT_BONDED:
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
+ break;
+ }
+ } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
+ 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, device);
+ mHandler.sendMessageDelayed(msg, 6000);
+ }
+ }
+ }
+ };
- private class SinkState {
- public String address;
- public int state;
- public SinkState(String a, int s) {address = a; state = s;}
- }
-
- public BluetoothA2dpService(Context context) {
+ public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mBluetooth = (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (mBluetooth == null) {
+ mBluetoothService = bluetoothService;
+ if (mBluetoothService == null) {
throw new RuntimeException("Platform does not support Bluetooth");
}
@@ -91,14 +132,17 @@
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);
- if (mBluetooth.isEnabled()) {
+ mAudioDevices = new HashMap<BluetoothDevice, Integer>();
+
+ if (mBluetoothService.isEnabled())
onBluetoothEnable();
- }
}
@Override
@@ -110,120 +154,130 @@
}
}
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
- int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
- BluetoothError.ERROR);
- switch (state) {
- case BluetoothDevice.BLUETOOTH_STATE_ON:
- onBluetoothEnable();
- break;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
- onBluetoothDisable();
- break;
- }
- } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
- int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
- BluetoothError.ERROR);
- switch(bondState) {
- case BluetoothDevice.BOND_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO);
- break;
- case BluetoothDevice.BOND_BONDING:
- case BluetoothDevice.BOND_NOT_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
- break;
- }
- } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
- if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF) {
- // 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);
- mHandler.sendMessageDelayed(msg, 6000);
- }
- }
- }
- };
-
private final Handler mHandler = new Handler() {
@Override
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 (mBluetooth.isEnabled() &&
- getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
+ if (mBluetoothService.isEnabled() &&
+ 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;
- case MESSAGE_DISCONNECT:
- handleDeferredDisconnect((String)msg.obj);
- break;
}
}
};
- private synchronized void onBluetoothEnable() {
- mAudioDevices = new HashMap<String, SinkState>();
- String[] paths = (String[])listHeadsetsNative();
- if (paths != null) {
- for (String path : paths) {
- mAudioDevices.put(path, new SinkState(getAddressNative(path),
- isSinkConnectedNative(path) ? BluetoothA2dp.STATE_CONNECTED :
- BluetoothA2dp.STATE_DISCONNECTED));
+ private int convertBluezSinkStringtoState(String value) {
+ if (value.equalsIgnoreCase("disconnected"))
+ return BluetoothA2dp.STATE_DISCONNECTED;
+ if (value.equalsIgnoreCase("connecting"))
+ return BluetoothA2dp.STATE_CONNECTING;
+ if (value.equalsIgnoreCase("connected"))
+ return BluetoothA2dp.STATE_CONNECTED;
+ if (value.equalsIgnoreCase("playing"))
+ return BluetoothA2dp.STATE_PLAYING;
+ return -1;
+ }
+
+ private boolean isSinkDevice(BluetoothDevice device) {
+ String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
+ UUID uuid;
+ if (uuids != null) {
+ for (String deviceUuid: uuids) {
+ uuid = UUID.fromString(deviceUuid);
+ if (BluetoothUuid.isAudioSink(uuid)) {
+ return true;
+ }
}
}
- mAudioManager.setParameter(BLUETOOTH_ENABLED, "true");
+ return false;
+ }
+
+ 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: " + device);
+ return false;
+ }
+ Integer state = null;
+ // Properties are name-value pairs
+ for (int i = 0; i < propValues.length; i+=2) {
+ if (propValues[i].equals(PROPERTY_STATE)) {
+ state = new Integer(convertBluezSinkStringtoState(propValues[i+1]));
+ break;
+ }
+ }
+ mAudioDevices.put(device, state);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state);
+ return true;
+ }
+
+ private synchronized void onBluetoothEnable() {
+ String devices = mBluetoothService.getProperty("Devices");
+ mSinkCount = 0;
+ if (devices != null) {
+ 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) {
+ UUID remoteUuid = UUID.fromString(uuid);
+ if (BluetoothUuid.isAudioSink(remoteUuid) ||
+ BluetoothUuid.isAudioSource(remoteUuid) ||
+ BluetoothUuid.isAdvAudioDist(remoteUuid)) {
+ addAudioSink(device);
+ break;
+ }
+ }
+ }
+ }
+ mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
}
private synchronized void onBluetoothDisable() {
- if (mAudioDevices != null) {
- // copy to allow modification during iteration
- String[] paths = new String[mAudioDevices.size()];
- paths = mAudioDevices.keySet().toArray(paths);
- for (String path : paths) {
- switch (mAudioDevices.get(path).state) {
+ if (!mAudioDevices.isEmpty()) {
+ 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(path);
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(
+ device.getAddress()));
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
break;
case BluetoothA2dp.STATE_DISCONNECTING:
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING,
+ BluetoothA2dp.STATE_DISCONNECTED);
break;
}
}
- mAudioDevices = null;
+ mAudioDevices.clear();
}
- mAudioManager.setBluetoothA2dpOn(false);
- mAudioManager.setParameter(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 (mAudioDevices == null) {
- return BluetoothError.ERROR;
- }
+ if (DBG) log("connectSink(" + device + ")");
+
// ignore if there are any active sinks
if (lookupSinksMatchingStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
@@ -233,20 +287,11 @@
return BluetoothError.ERROR;
}
- String path = lookupPath(address);
- if (path == null) {
- path = createHeadsetNative(address);
- if (DBG) log("new bluez sink: " + address + " (" + path + ")");
- }
- if (path == null) {
+ if (mAudioDevices.get(device) == null && !addAudioSink(device))
return BluetoothError.ERROR;
- }
- SinkState sink = mAudioDevices.get(path);
- int state = BluetoothA2dp.STATE_DISCONNECTED;
- if (sink != null) {
- state = sink.state;
- }
+ int state = mAudioDevices.get(device);
+
switch (state) {
case BluetoothA2dp.STATE_CONNECTED:
case BluetoothA2dp.STATE_PLAYING:
@@ -256,29 +301,28 @@
return BluetoothError.SUCCESS;
}
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ if (path == null)
+ return BluetoothError.ERROR;
+
// State is DISCONNECTED
if (!connectSinkNative(path)) {
return BluetoothError.ERROR;
}
- updateState(path, BluetoothA2dp.STATE_CONNECTING);
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;
- }
- if (mAudioDevices == null) {
- return BluetoothError.ERROR;
- }
- String path = lookupPath(address);
+ if (DBG) log("disconnectSink(" + device + ")");
+
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (path == null) {
return BluetoothError.ERROR;
}
- switch (mAudioDevices.get(path).state) {
+
+ switch (getSinkState(device)) {
case BluetoothA2dp.STATE_DISCONNECTED:
return BluetoothError.ERROR;
case BluetoothA2dp.STATE_DISCONNECTING:
@@ -289,151 +333,106 @@
if (!disconnectSinkNative(path)) {
return BluetoothError.ERROR;
} else {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTING);
return BluetoothError.SUCCESS;
}
}
- 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;
- }
- if (mAudioDevices == null) {
+ Integer state = mAudioDevices.get(device);
+ if (state == null)
return BluetoothA2dp.STATE_DISCONNECTED;
- }
- for (SinkState sink : mAudioDevices.values()) {
- if (address.equals(sink.address)) {
- return sink.state;
- }
- }
- 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;
}
- private synchronized void onHeadsetCreated(String path) {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
- }
-
- private synchronized void onHeadsetRemoved(String path) {
- if (mAudioDevices == null) return;
- mAudioDevices.remove(path);
- }
-
- private synchronized void onSinkConnected(String path) {
- // if we are reconnected, do not process previous disconnect event.
- mPendingDisconnects.remove(path);
-
- if (mAudioDevices == null) return;
- // bluez 3.36 quietly disconnects the previous sink when a new sink
- // is connected, so we need to mark all previously connected sinks as
- // disconnected
-
- // copy to allow modification during iteration
- String[] paths = new String[mAudioDevices.size()];
- paths = mAudioDevices.keySet().toArray(paths);
- for (String oldPath : paths) {
- if (path.equals(oldPath)) {
- continue;
- }
- int state = mAudioDevices.get(oldPath).state;
- if (state == BluetoothA2dp.STATE_CONNECTED || state == BluetoothA2dp.STATE_PLAYING) {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
- }
+ private synchronized void onSinkPropertyChanged(String path, String []propValues) {
+ if (!mBluetoothService.isEnabled()) {
+ return;
}
- updateState(path, BluetoothA2dp.STATE_CONNECTING);
- mAudioManager.setParameter(A2DP_SINK_ADDRESS, lookupAddress(path));
- mAudioManager.setBluetoothA2dpOn(true);
- updateState(path, BluetoothA2dp.STATE_CONNECTED);
- }
+ String name = propValues[0];
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ if (address == null) {
+ Log.e(TAG, "onSinkPropertyChanged: Address of the remote device in null");
+ return;
+ }
- private synchronized void onSinkDisconnected(String path) {
- // This is to work around a problem in bluez that results
- // sink disconnect events being sent, immediately followed by a reconnect.
- // To avoid unnecessary audio routing changes, we defer handling
- // sink disconnects until after a short delay.
- mPendingDisconnects.add(path);
- Message msg = Message.obtain(mHandler, MESSAGE_DISCONNECT, path);
- mHandler.sendMessageDelayed(msg, 2000);
- }
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
- private synchronized void handleDeferredDisconnect(String path) {
- if (mPendingDisconnects.contains(path)) {
- mPendingDisconnects.remove(path);
- if (mSinkCount == 1) {
- mAudioManager.setBluetoothA2dpOn(false);
+ if (name.equals(PROPERTY_STATE)) {
+ int state = convertBluezSinkStringtoState(propValues[1]);
+ 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(device);
+ } else {
+ int prevState = mAudioDevices.get(device);
+ handleSinkStateChange(device, prevState, state);
}
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ }
+ }
+
+ private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
+ if (state != prevState) {
+ if (state == BluetoothA2dp.STATE_DISCONNECTED ||
+ state == BluetoothA2dp.STATE_DISCONNECTING) {
+ if (prevState == BluetoothA2dp.STATE_CONNECTED ||
+ prevState == BluetoothA2dp.STATE_PLAYING) {
+ // disconnecting or disconnected
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
+ mSinkCount--;
+ } else if (state == BluetoothA2dp.STATE_CONNECTED) {
+ mSinkCount ++;
+ }
+ mAudioDevices.put(device, state);
+
+ Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ 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 : device: " + device + " State:" + prevState + "->" + state);
}
}
- private synchronized void onSinkPlaying(String path) {
- updateState(path, BluetoothA2dp.STATE_PLAYING);
- }
-
- private synchronized void onSinkStopped(String path) {
- updateState(path, BluetoothA2dp.STATE_CONNECTED);
- }
-
- private synchronized final String lookupAddress(String path) {
- if (mAudioDevices == null) return null;
- SinkState sink = mAudioDevices.get(path);
- if (sink == null) {
- Log.w(TAG, "lookupAddress() called for unknown device " + path);
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
- }
- String address = mAudioDevices.get(path).address;
- if (address == null) Log.e(TAG, "Can't find address for " + path);
- return address;
- }
-
- private synchronized final String lookupPath(String address) {
- if (mAudioDevices == null) return null;
-
- for (String path : mAudioDevices.keySet()) {
- if (address.equals(mAudioDevices.get(path).address)) {
- return path;
- }
- }
- return null;
- }
-
- private synchronized List<String> lookupSinksMatchingStates(int[] states) {
- List<String> sinks = new ArrayList<String>();
- if (mAudioDevices == null) {
+ private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
+ Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
+ if (mAudioDevices.isEmpty()) {
return sinks;
}
- for (SinkState sink : mAudioDevices.values()) {
+ for (BluetoothDevice device: mAudioDevices.keySet()) {
+ int sinkState = getSinkState(device);
for (int state : states) {
- if (sink.state == state) {
- sinks.add(sink.address);
+ if (state == sinkState) {
+ sinks.add(device);
break;
}
}
@@ -441,57 +440,13 @@
return sinks;
}
- private synchronized void updateState(String path, int state) {
- if (mAudioDevices == null) return;
-
- SinkState s = mAudioDevices.get(path);
- int prevState;
- String address;
- if (s == null) {
- address = getAddressNative(path);
- mAudioDevices.put(path, new SinkState(address, state));
- prevState = BluetoothA2dp.STATE_DISCONNECTED;
- } else {
- address = lookupAddress(path);
- prevState = s.state;
- s.state = state;
- }
-
- if (state != prevState) {
- if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state);
-
- // keep track of the number of active sinks
- if (prevState == BluetoothA2dp.STATE_DISCONNECTED) {
- mSinkCount++;
- } else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
- mSinkCount--;
- }
-
- Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothA2dp.SINK_STATE, state);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-
- if ((prevState == BluetoothA2dp.STATE_CONNECTED ||
- prevState == BluetoothA2dp.STATE_PLAYING) &&
- (state != BluetoothA2dp.STATE_CONNECTING &&
- state != BluetoothA2dp.STATE_CONNECTED &&
- state != BluetoothA2dp.STATE_PLAYING)) {
- // disconnected
- intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- }
- }
- }
-
@Override
protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mAudioDevices == null) return;
+ if (mAudioDevices.isEmpty()) return;
pw.println("Cached audio devices:");
- for (String path : mAudioDevices.keySet()) {
- SinkState sink = mAudioDevices.get(path);
- pw.println(path + " " + sink.address + " " + BluetoothA2dp.stateToString(sink.state));
+ for (BluetoothDevice device : mAudioDevices.keySet()) {
+ int state = mAudioDevices.get(device);
+ pw.println(device + " " + BluetoothA2dp.stateToString(state));
}
}
@@ -501,11 +456,7 @@
private native boolean initNative();
private native void cleanupNative();
- private synchronized native String[] listHeadsetsNative();
- private synchronized native String createHeadsetNative(String address);
- private synchronized native boolean removeHeadsetNative(String path);
- private synchronized native String getAddressNative(String path);
private synchronized native boolean connectSinkNative(String path);
private synchronized native boolean disconnectSinkNative(String path);
- private synchronized native boolean isSinkConnectedNative(String path);
+ private synchronized native Object []getSinkPropertiesNative(String path);
}
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
deleted file mode 100644
index 8c843ef..0000000
--- a/core/java/android/server/BluetoothDeviceService.java
+++ /dev/null
@@ -1,1263 +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.
- */
-
-/**
- * TODO: Move this to
- * java/services/com/android/server/BluetoothDeviceService.java
- * and make the contructor package private again.
- *
- * @hide
- */
-
-package android.server;
-
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothError;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDevice;
-import android.bluetooth.IBluetoothDeviceCallback;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemService;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import com.android.internal.app.IBatteryStats;
-
-public class BluetoothDeviceService extends IBluetoothDevice.Stub {
- private static final String TAG = "BluetoothDeviceService";
- private static final boolean DBG = true;
-
- private int mNativeData;
- private BluetoothEventLoop mEventLoop;
- private IntentFilter mIntentFilter;
- 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 final Context mContext;
-
- private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
- private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
-
- private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
- private static final int MESSAGE_FINISH_DISABLE = 2;
-
- static {
- classInitNative();
- }
- private native static void classInitNative();
-
- public BluetoothDeviceService(Context context) {
- mContext = context;
-
- // Need to do this in place of:
- // mBatteryStats = BatteryStatsService.getService();
- // 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) {
- Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
- disableNative();
- }
-
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
- mIsDiscovering = false;
- mEventLoop = new BluetoothEventLoop(mContext, this);
- registerForAirplaneMode();
- }
- private native void initializeNativeDataNative();
-
- @Override
- protected void finalize() throws Throwable {
- if (mIsAirplaneSensitive) {
- mContext.unregisterReceiver(mReceiver);
- }
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
- private native void cleanupNativeDataNative();
-
- public boolean isEnabled() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON;
- }
- private native int isEnabledNative();
-
- public int getBluetoothState() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothState;
- }
-
-
- /**
- * Bring down bluetooth and disable BT in settings. Returns true on success.
- */
- public boolean disable() {
- return disable(true);
- }
-
- /**
- * Bring down bluetooth. Returns true on success.
- *
- * @param saveSetting If true, disable BT in settings
- */
- public synchronized boolean disable(boolean saveSetting) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
-
- switch (mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
- return true;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
- break;
- default:
- return false;
- }
- if (mEnableThread != null && mEnableThread.isAlive()) {
- return false;
- }
- setBluetoothState(BluetoothDevice.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
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
- return true;
- }
-
-
- private synchronized void finishDisable(boolean saveSetting) {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
- return;
- }
- mEventLoop.stop();
- disableNative();
-
- // mark in progress bondings as cancelled
- for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
- mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- }
-
- // Remove remoteServiceChannelCallbacks
- HashMap<String, IBluetoothDeviceCallback> callbacksMap =
- mEventLoop.getRemoteServiceChannelCallbacks();
-
- for (Iterator<String> i = callbacksMap.keySet().iterator(); i.hasNext();) {
- String address = i.next();
- IBluetoothDeviceCallback callback = callbacksMap.get(address);
- try {
- callback.onGetRemoteServiceChannelResult(address, BluetoothError.ERROR_DISABLED);
- } catch (RemoteException e) {}
- i.remove();
- }
-
- // update mode
- Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-
- mIsDiscovering = false;
-
- if (saveSetting) {
- persistBluetoothOnSetting(false);
- }
-
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
-
- // Log bluetooth off to battery stats.
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.noteBluetoothOff();
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- if (mRestart) {
- mRestart = false;
- enable();
- }
- }
-
- /** Bring up BT and persist BT on in settings */
- public boolean enable() {
- return enable(true);
- }
-
- /**
- * Enable this Bluetooth device, asynchronously.
- * This turns on/off the underlying hardware.
- *
- * @param saveSetting If true, persist the new state of BT in settings
- * @return True on success (so far)
- */
- public synchronized boolean enable(boolean saveSetting) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
-
- // Airplane mode can prevent Bluetooth radio from being turned on.
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
- return false;
- }
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) {
- return false;
- }
- if (mEnableThread != null && mEnableThread.isAlive()) {
- return false;
- }
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
- mEnableThread = new EnableThread(saveSetting);
- mEnableThread.start();
- return true;
- }
-
- /** Forcibly restart Bluetooth if it is on */
- /* package */ synchronized void restart() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_ON) {
- return;
- }
- mRestart = true;
- if (!disable(false)) {
- mRestart = false;
- }
- }
-
- private synchronized void setBluetoothState(int state) {
- if (state == mBluetoothState) {
- return;
- }
-
- if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
-
- Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
- intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
- mBluetoothState = state;
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_REGISTER_SDP_RECORDS:
- //TODO: Don't assume HSP/HFP is running, don't use sdptool,
- if (isEnabled()) {
- SystemService.start("hsag");
- SystemService.start("hfag");
- }
- break;
- case MESSAGE_FINISH_DISABLE:
- finishDisable(msg.arg1 != 0);
- break;
- }
- }
- };
-
- private EnableThread mEnableThread;
-
- private class EnableThread extends Thread {
- private final boolean mSaveSetting;
- public EnableThread(boolean saveSetting) {
- mSaveSetting = saveSetting;
- }
- public void run() {
- boolean res = (enableNative() == 0);
- if (res) {
- int retryCount = 2;
- boolean running = false;
- while ((retryCount-- > 0) && !running) {
- mEventLoop.start();
- // it may take a momement for the other thread to do its
- // thing. Check periodically for a while.
- int pollCount = 5;
- while ((pollCount-- > 0) && !running) {
- if (mEventLoop.isEventLoopRunning()) {
- running = true;
- break;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
- }
- }
- if (!running) {
- log("bt EnableThread giving up");
- res = false;
- disableNative();
- }
- }
-
-
- if (res) {
- if (mSaveSetting) {
- persistBluetoothOnSetting(true);
- }
- mIsDiscovering = false;
- mBondState.loadBondState();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
- 3000);
-
- // Log bluetooth on to battery stats.
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.noteBluetoothOn();
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- mEnableThread = null;
-
- setBluetoothState(res ?
- BluetoothDevice.BLUETOOTH_STATE_ON :
- BluetoothDevice.BLUETOOTH_STATE_OFF);
-
- if (res) {
- // Update mode
- mEventLoop.onModeChanged(getModeNative());
- }
-
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
- disable(false);
- }
-
- }
- }
-
- private void persistBluetoothOnSetting(boolean bluetoothOn) {
- long origCallerIdentityToken = Binder.clearCallingIdentity();
- Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
- bluetoothOn ? 1 : 0);
- Binder.restoreCallingIdentity(origCallerIdentityToken);
- }
-
- private native int enableNative();
- private native int disableNative();
-
- /* package */ BondState getBondState() {
- return mBondState;
- }
-
- /** local cache of bonding state.
- /* we keep our own state to track the intermediate state BONDING, which
- /* bluez does not track.
- * All addreses must be passed in upper case.
- */
- public class BondState {
- private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
- private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
- private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
- // List of all the vendor_id prefix of Bluetooth addresses for
- // which auto pairing is not attempted.
- // The following companies are included in the list below:
- // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
- // Parrot, Zhongshan General K-mate Electronics, Great Well
- // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
- // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
- // Continental Automotive, Harman/Becker
- private final ArrayList<String> mAutoPairingBlacklisted =
- new ArrayList<String>(Arrays.asList(
- "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
- "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
- "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
- "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
- "00:0A:30", "00:1E:AE", "00:1C:D7"
- ));
-
- public synchronized void loadBondState() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) {
- return;
- }
- String[] bonds = listBondingsNative();
- if (bonds == null) {
- return;
- }
- mState.clear();
- if (DBG) log("found " + bonds.length + " bonded devices");
- for (String address : bonds) {
- mState.put(address.toUpperCase(), BluetoothDevice.BOND_BONDED);
- }
- }
-
- public synchronized void setBondState(String address, int state) {
- setBondState(address, state, 0);
- }
-
- /** reason is ignored unless state == BOND_NOT_BONDED */
- public synchronized void setBondState(String address, int state, int reason) {
- int oldState = getBondState(address);
- if (oldState == state) {
- return;
- }
- 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.BOND_STATE, state);
- intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
- if (state == BluetoothDevice.BOND_NOT_BONDED) {
- if (reason <= 0) {
- Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
- "invalid. Overriding reason code with BOND_RESULT_REMOVED");
- reason = BluetoothDevice.UNBOND_REASON_REMOVED;
- }
- intent.putExtra(BluetoothIntent.REASON, reason);
- mState.remove(address);
- } else {
- mState.put(address, state);
- }
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
-
- public boolean isAutoPairingBlacklisted(String address) {
- for (String blacklistAddress : mAutoPairingBlacklisted) {
- if (address.startsWith(blacklistAddress)) return true;
- }
- return false;
- }
-
- public synchronized int getBondState(String address) {
- Integer state = mState.get(address);
- if (state == null) {
- return BluetoothDevice.BOND_NOT_BONDED;
- }
- return state.intValue();
- }
-
- private synchronized String[] listInState(int state) {
- ArrayList<String> result = new ArrayList<String>(mState.size());
- for (Map.Entry<String, Integer> e : mState.entrySet()) {
- if (e.getValue().intValue() == state) {
- result.add(e.getKey());
- }
- }
- return result.toArray(new String[result.size()]);
- }
-
- public synchronized void addAutoPairingFailure(String address) {
- if (!mAutoPairingFailures.contains(address)) {
- mAutoPairingFailures.add(address);
- }
- }
-
- public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
- return getAttempt(address) != 0;
- }
-
- public synchronized void clearPinAttempts(String address) {
- mPinAttempt.remove(address);
- }
-
- public synchronized boolean hasAutoPairingFailed(String address) {
- return mAutoPairingFailures.contains(address);
- }
-
- public synchronized int getAttempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- if (attempt == null) {
- return 0;
- }
- return attempt.intValue();
- }
-
- public synchronized void attempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- int newAttempt;
- if (attempt == null) {
- newAttempt = 1;
- } else {
- newAttempt = attempt.intValue() + 1;
- }
- mPinAttempt.put(address, new Integer(newAttempt));
- }
-
- }
- private native String[] listBondingsNative();
-
- private static String toBondStateString(int bondState) {
- switch (bondState) {
- case BluetoothDevice.BOND_NOT_BONDED:
- return "not bonded";
- case BluetoothDevice.BOND_BONDING:
- return "bonding";
- case BluetoothDevice.BOND_BONDED:
- return "bonded";
- default:
- return "??????";
- }
- }
-
- public synchronized String getAddress() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getAddressNative();
- }
- private native String getAddressNative();
-
- public synchronized String getName() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getNameNative();
- }
- private native String getNameNative();
-
- public synchronized boolean setName(String name) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (name == null) {
- return false;
- }
- // hcid handles persistance of the bluetooth name
- return setNameNative(name);
- }
- private native boolean setNameNative(String name);
-
- /**
- * Returns the user-friendly name of a remote device. This value is
- * retrned from our local cache, which is updated during device discovery.
- * Do not expect to retrieve the updated remote name immediately after
- * changing the name on the remote device.
- *
- * @param address Bluetooth address of remote device.
- *
- * @return The user-friendly name of the specified remote device.
- */
- public synchronized String getRemoteName(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteNameNative(address);
- }
- private native String getRemoteNameNative(String address);
-
- /* pacakge */ native String getAdapterPathNative();
-
- public synchronized boolean startDiscovery(boolean resolveNames) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return startDiscoveryNative(resolveNames);
- }
- private native boolean startDiscoveryNative(boolean resolveNames);
-
- public synchronized boolean cancelDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return cancelDiscoveryNative();
- }
- private native boolean cancelDiscoveryNative();
-
- public synchronized boolean isDiscovering() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mIsDiscovering;
- }
-
- /* package */ void setIsDiscovering(boolean isDiscovering) {
- mIsDiscovering = isDiscovering;
- }
-
- public synchronized boolean startPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return startPeriodicDiscoveryNative();
- }
- private native boolean startPeriodicDiscoveryNative();
-
- public synchronized boolean stopPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return stopPeriodicDiscoveryNative();
- }
- private native boolean stopPeriodicDiscoveryNative();
-
- public synchronized boolean isPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return isPeriodicDiscoveryNative();
- }
- private native boolean isPeriodicDiscoveryNative();
-
- /**
- * Set the discoverability window for the device. A timeout of zero
- * makes the device permanently discoverable (if the device is
- * discoverable). Setting the timeout to a nonzero value does not make
- * a device discoverable; you need to call setMode() to make the device
- * explicitly discoverable.
- *
- * @param timeout_s The discoverable timeout in seconds.
- */
- public synchronized boolean setDiscoverableTimeout(int timeout) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return setDiscoverableTimeoutNative(timeout);
- }
- private native boolean setDiscoverableTimeoutNative(int timeout_s);
-
- /**
- * Get the discoverability window for the device. A timeout of zero
- * means that the device is permanently discoverable (if the device is
- * in the discoverable mode).
- *
- * @return The discoverability window of the device, in seconds. A negative
- * value indicates an error.
- */
- public synchronized int getDiscoverableTimeout() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getDiscoverableTimeoutNative();
- }
- private native int getDiscoverableTimeoutNative();
-
- public synchronized boolean isAclConnected(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return isConnectedNative(address);
- }
- private native boolean isConnectedNative(String address);
-
- public synchronized int getScanMode() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return bluezStringToScanMode(getModeNative());
- }
- private native String getModeNative();
-
- public synchronized boolean setScanMode(int mode) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- String bluezMode = scanModeToBluezString(mode);
- if (bluezMode != null) {
- return setModeNative(bluezMode);
- }
- return false;
- }
- private native boolean setModeNative(String mode);
-
- public synchronized boolean disconnectRemoteDeviceAcl(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return disconnectRemoteDeviceNative(address);
- }
- private native boolean disconnectRemoteDeviceNative(String address);
-
- public synchronized boolean createBond(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
-
- String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
- if (bonding.length > 0 && !bonding[0].equals(address)) {
- log("Ignoring createBond(): another device is bonding");
- // a different device is currently bonding, fail
- return false;
- }
-
- // Check for bond state only if we are not performing auto
- // pairing exponential back-off attempts.
- if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
- mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
- log("Ignoring createBond(): this device is already bonding or bonded");
- return false;
- }
-
- if (!createBondingNative(address, 60000 /* 1 minute */)) {
- return false;
- }
-
- mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
- return true;
- }
- private native boolean createBondingNative(String address, int timeout_ms);
-
- public synchronized boolean cancelBondProcess(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
- return false;
- }
-
- mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- cancelBondingProcessNative(address);
- return true;
- }
- private native boolean cancelBondingProcessNative(String address);
-
- public synchronized boolean removeBond(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return removeBondingNative(address);
- }
- private native boolean removeBondingNative(String address);
-
- public synchronized String[] listBonds() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBondState.listInState(BluetoothDevice.BOND_BONDED);
- }
-
- public synchronized int getBondState(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- return mBondState.getBondState(address.toUpperCase());
- }
-
- public synchronized String[] listAclConnections() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return listConnectionsNative();
- }
- private native String[] listConnectionsNative();
-
- /**
- * This method lists all remote devices that this adapter is aware of.
- * This is a list not only of all most-recently discovered devices, but of
- * all devices discovered by this adapter up to some point in the past.
- * Note that many of these devices may not be in the neighborhood anymore,
- * and attempting to connect to them will result in an error.
- *
- * @return An array of strings representing the Bluetooth addresses of all
- * remote devices that this adapter is aware of.
- */
- public synchronized String[] listRemoteDevices() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return listRemoteDevicesNative();
- }
- private native String[] listRemoteDevicesNative();
-
- /**
- * Returns the version of the Bluetooth chip. This version is compiled from
- * the LMP version. In case of EDR the features attribute must be checked.
- * Example: "Bluetooth 2.0 + EDR".
- *
- * @return a String representation of the this Adapter's underlying
- * Bluetooth-chip version.
- */
- public synchronized String getVersion() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getVersionNative();
- }
- private native String getVersionNative();
-
- /**
- * Returns the revision of the Bluetooth chip. This is a vendor-specific
- * value and in most cases it represents the firmware version. This might
- * derive from the HCI revision and LMP subversion values or via extra
- * vendord specific commands.
- * In case the revision of a chip is not available. This method should
- * return the LMP subversion value as a string.
- * Example: "HCI 19.2"
- *
- * @return The HCI revision of this adapter.
- */
- public synchronized String getRevision() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getRevisionNative();
- }
- private native String getRevisionNative();
-
- /**
- * Returns the manufacturer of the Bluetooth chip. If the company id is not
- * known the sting "Company ID %d" where %d should be replaced with the
- * numeric value from the manufacturer field.
- * Example: "Cambridge Silicon Radio"
- *
- * @return Manufacturer name.
- */
- public synchronized String getManufacturer() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getManufacturerNative();
- }
- private native String getManufacturerNative();
-
- /**
- * Returns the company name from the OUI database of the Bluetooth device
- * address. This function will need a valid and up-to-date oui.txt from
- * the IEEE. This value will be different from the manufacturer string in
- * the most cases.
- * If the oui.txt file is not present or the OUI part of the Bluetooth
- * address is not listed, it should return the string "OUI %s" where %s is
- * the actual OUI.
- *
- * Example: "Apple Computer"
- *
- * @return company name
- */
- public synchronized String getCompany() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getCompanyNative();
- }
- private native String getCompanyNative();
-
- /**
- * Like getVersion(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device Bluetooth version
- *
- * @see #getVersion
- */
- public synchronized String getRemoteVersion(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteVersionNative(address);
- }
- private native String getRemoteVersionNative(String address);
-
- /**
- * Like getRevision(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device HCI revision
- *
- * @see #getRevision
- */
- public synchronized String getRemoteRevision(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteRevisionNative(address);
- }
- private native String getRemoteRevisionNative(String address);
-
- /**
- * Like getManufacturer(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device Bluetooth chip manufacturer
- *
- * @see #getManufacturer
- */
- public synchronized String getRemoteManufacturer(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteManufacturerNative(address);
- }
- private native String getRemoteManufacturerNative(String address);
-
- /**
- * Like getCompany(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device company
- *
- * @see #getCompany
- */
- public synchronized String getRemoteCompany(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteCompanyNative(address);
- }
- private native String getRemoteCompanyNative(String address);
-
- /**
- * Returns the date and time when the specified remote device has been seen
- * by a discover procedure.
- * Example: "2006-02-08 12:00:00 GMT"
- *
- * @return a String with the timestamp.
- */
- public synchronized String lastSeen(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return lastSeenNative(address);
- }
- private native String lastSeenNative(String address);
-
- /**
- * Returns the date and time when the specified remote device has last been
- * connected to
- * Example: "2006-02-08 12:00:00 GMT"
- *
- * @return a String with the timestamp.
- */
- public synchronized String lastUsed(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return lastUsedNative(address);
- }
- private native String lastUsedNative(String address);
-
- /**
- * Gets the remote major, minor, and service classes encoded as a 32-bit
- * integer.
- *
- * Note: this value is retrieved from cache, because we get it during
- * remote-device discovery.
- *
- * @return 32-bit integer encoding the remote major, minor, and service
- * classes.
- *
- * @see #getRemoteMajorClass
- * @see #getRemoteMinorClass
- * @see #getRemoteServiceClasses
- */
- public synchronized int getRemoteClass(String address) {
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return BluetoothClass.ERROR;
- }
- return getRemoteClassNative(address);
- }
- private native int getRemoteClassNative(String address);
-
- /**
- * Gets the remote features encoded as bit mask.
- *
- * Note: This method may be obsoleted soon.
- *
- * @return byte array of features.
- */
- public synchronized byte[] getRemoteFeatures(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteFeaturesNative(address);
- }
- private native byte[] getRemoteFeaturesNative(String address);
-
- /**
- * This method and {@link #getRemoteServiceRecord} query the SDP service
- * on a remote device. They do not interpret the data, but simply return
- * it raw to the user. To read more about SDP service handles and records,
- * consult the Bluetooth core documentation (www.bluetooth.com).
- *
- * @param address Bluetooth address of remote device.
- * @param match a String match to narrow down the service-handle search.
- * The only supported value currently is "hsp" for the headset
- * profile. To retrieve all service handles, simply pass an empty
- * match string.
- *
- * @return all service handles corresponding to the string match.
- *
- * @see #getRemoteServiceRecord
- */
- public synchronized int[] getRemoteServiceHandles(String address, String match) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- if (match == null) {
- match = "";
- }
- return getRemoteServiceHandlesNative(address, match);
- }
- private native int[] getRemoteServiceHandlesNative(String address, String match);
-
- /**
- * This method retrieves the service records corresponding to a given
- * service handle (method {@link #getRemoteServiceHandles} retrieves the
- * service handles.)
- *
- * This method and {@link #getRemoteServiceHandles} do not interpret their
- * data, but simply return it raw to the user. To read more about SDP
- * service handles and records, consult the Bluetooth core documentation
- * (www.bluetooth.com).
- *
- * @param address Bluetooth address of remote device.
- * @param handle Service handle returned by {@link #getRemoteServiceHandles}
- *
- * @return a byte array of all service records corresponding to the
- * specified service handle.
- *
- * @see #getRemoteServiceHandles
- */
- public synchronized byte[] getRemoteServiceRecord(String address, int handle) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteServiceRecordNative(address, handle);
- }
- private native byte[] getRemoteServiceRecordNative(String address, int handle);
-
- private static final int MAX_OUTSTANDING_ASYNC = 32;
-
- // AIDL does not yet support short's
- public synchronized boolean getRemoteServiceChannel(String address, int uuid16,
- IBluetoothDeviceCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- HashMap<String, IBluetoothDeviceCallback> callbacks =
- mEventLoop.getRemoteServiceChannelCallbacks();
- if (callbacks.containsKey(address)) {
- Log.w(TAG, "SDP request already in progress for " + address);
- return false;
- }
- // Protect from malicious clients - only allow 32 bonding requests per minute.
- if (callbacks.size() > MAX_OUTSTANDING_ASYNC) {
- Log.w(TAG, "Too many outstanding SDP requests, dropping request for " + address);
- return false;
- }
- callbacks.put(address, callback);
-
- if (!getRemoteServiceChannelNative(address, (short)uuid16)) {
- callbacks.remove(address);
- return false;
- }
- return true;
- }
- private native boolean getRemoteServiceChannelNative(String address, short uuid16);
-
- public synchronized boolean setPin(String address, byte[] pin) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (pin == null || pin.length <= 0 || pin.length > 16 ||
- !BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
- if (data == null) {
- Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
- "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
- " or by bluez.\n");
- return false;
- }
- // bluez API wants pin as a string
- String pinString;
- try {
- pinString = new String(pin, "UTF8");
- } catch (UnsupportedEncodingException uee) {
- Log.e(TAG, "UTF8 not supported?!?");
- return false;
- }
- return setPinNative(address, pinString, data.intValue());
- }
- private native boolean setPinNative(String address, String pin, int nativeData);
-
- public synchronized boolean cancelPin(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
- if (data == null) {
- Log.w(TAG, "cancelPin(" + address + ") called but no native data available, " +
- "ignoring. Maybe the PasskeyAgent Request was already cancelled by the remote " +
- "or by bluez.\n");
- return false;
- }
- return cancelPinNative(address, data.intValue());
- }
- private native boolean cancelPinNative(String address, int natveiData);
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- ContentResolver resolver = context.getContentResolver();
- // Query the airplane mode from Settings.System just to make sure that
- // some random app is not sending this intent and disabling bluetooth
- boolean enabled = !isAirplaneModeOn();
- // If bluetooth is currently expected to be on, then enable or disable bluetooth
- if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
- if (enabled) {
- enable(false);
- } else {
- disable(false);
- }
- }
- }
- }
- };
-
- private void registerForAirplaneMode() {
- String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_RADIOS);
- mIsAirplaneSensitive = airplaneModeRadios == null
- ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
- if (mIsAirplaneSensitive) {
- mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, mIntentFilter);
- }
- }
-
- /* Returns true if airplane mode is currently on */
- private final boolean isAirplaneModeOn() {
- return Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
-
- switch(mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
- pw.println("\nBluetooth OFF\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON:
- pw.println("\nBluetooth TURNING ON\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
- pw.println("\nBluetooth TURNING OFF\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
- pw.println("\nBluetooth ON\n");
- }
-
- pw.println("\nLocal address = " + getAddress());
- pw.println("\nLocal name = " + getName());
- pw.println("\nisDiscovering() = " + isDiscovering());
-
- BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
-
- String[] addresses = listRemoteDevices();
-
- pw.println("\n--Known devices--");
- for (String address : addresses) {
- pw.printf("%s %10s (%d) %s\n", address,
- toBondStateString(mBondState.getBondState(address)),
- mBondState.getAttempt(address),
- getRemoteName(address));
- }
-
- addresses = listAclConnections();
- pw.println("\n--ACL connected devices--");
- for (String address : addresses) {
- pw.println(address);
- }
-
- // Rather not do this from here, but no-where else and I need this
- // dump
- pw.println("\n--Headset Service--");
- switch (headset.getState()) {
- case BluetoothHeadset.STATE_DISCONNECTED:
- pw.println("getState() = STATE_DISCONNECTED");
- break;
- case BluetoothHeadset.STATE_CONNECTING:
- pw.println("getState() = STATE_CONNECTING");
- break;
- case BluetoothHeadset.STATE_CONNECTED:
- pw.println("getState() = STATE_CONNECTED");
- break;
- case BluetoothHeadset.STATE_ERROR:
- pw.println("getState() = STATE_ERROR");
- break;
- }
- pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
- pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
-
- headset.close();
- }
-
- /* package */ static int bluezStringToScanMode(String mode) {
- if (mode == null) {
- return BluetoothError.ERROR;
- }
- mode = mode.toLowerCase();
- if (mode.equals("off")) {
- return BluetoothDevice.SCAN_MODE_NONE;
- } else if (mode.equals("connectable")) {
- return BluetoothDevice.SCAN_MODE_CONNECTABLE;
- } else if (mode.equals("discoverable")) {
- return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
- } else {
- return BluetoothError.ERROR;
- }
- }
-
- /* package */ static String scanModeToBluezString(int mode) {
- switch (mode) {
- case BluetoothDevice.SCAN_MODE_NONE:
- return "off";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE:
- return "connectable";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
- return "discoverable";
- }
- return null;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 8cc229b..6610d0e 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -18,18 +18,19 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDeviceCallback;
+import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
import java.util.HashMap;
+import java.util.UUID;
/**
* TODO: Move this to
@@ -46,9 +47,10 @@
private Thread mThread;
private boolean mStarted;
private boolean mInterrupted;
+
private final HashMap<String, Integer> mPasskeyAgentRequestData;
- private final HashMap<String, IBluetoothDeviceCallback> mGetRemoteServiceChannelCallbacks;
- 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;
@@ -85,14 +87,14 @@
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();
- mGetRemoteServiceChannelCallbacks = new HashMap();
+ mAdapter = adapter;
initializeNativeDataNative();
}
- private native void initializeNativeDataNative();
protected void finalize() throws Throwable {
try {
@@ -101,20 +103,11 @@
super.finalize();
}
}
- private native void cleanupNativeDataNative();
- /* pacakge */ HashMap<String, IBluetoothDeviceCallback> getRemoteServiceChannelCallbacks() {
- return mGetRemoteServiceChannelCallbacks;
- }
-
- /* pacakge */ HashMap<String, Integer> getPasskeyAgentRequestData() {
+ /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
return mPasskeyAgentRequestData;
}
- private native void startEventLoopNative();
- private native void stopEventLoopNative();
- private native boolean isEventLoopRunningNative();
-
/* package */ void start() {
if (!isEventLoopRunningNative()) {
@@ -134,79 +127,47 @@
return isEventLoopRunningNative();
}
- /*package*/ void onModeChanged(String bluezMode) {
- int mode = BluetoothDeviceService.bluezStringToScanMode(bluezMode);
- if (mode >= 0) {
- Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ private void addDevice(String address, String[] properties) {
+ mBluetoothService.addRemoteDeviceProperties(address, properties);
+ String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
+ String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
+ String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
+ short rssiValue;
+ // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
+ // If we accept the pairing, we will automatically show it at the top of the list.
+ if (rssi != null) {
+ rssiValue = (short)Integer.valueOf(rssi).intValue();
+ } else {
+ rssiValue = Short.MIN_VALUE;
+ }
+ if (classValue != null) {
+ Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
+ intent.putExtra(BluetoothIntent.RSSI, rssiValue);
+ intent.putExtra(BluetoothIntent.NAME, name);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ } else {
+ log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
}
}
- private void onDiscoveryStarted() {
- mBluetoothService.setIsDiscovering(true);
- Intent intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onDiscoveryCompleted() {
- mBluetoothService.setIsDiscovering(false);
- Intent intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ private void onDeviceFound(String address, String[] properties) {
+ if (properties == null) {
+ Log.e(TAG, "ERROR: Remote device properties are null");
+ return;
+ }
+ addDevice(address, properties);
}
- private void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.CLASS, deviceClass);
- intent.putExtra(BluetoothIntent.RSSI, rssi);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisappeared(String address) {
+ private void onDeviceDisappeared(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteClassUpdated(String address, int deviceClass) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.CLASS, deviceClass);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceConnected(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisconnectRequested(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisconnected(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameUpdated(String address, String name) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.NAME, name);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameFailed(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameChanged(String address, String name) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.NAME, name);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- private void onCreateBondingResult(String address, int result) {
+ private void onCreatePairedDeviceResult(String address, int result) {
address = address.toUpperCase();
if (result == BluetoothError.SUCCESS) {
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
@@ -259,31 +220,178 @@
mBluetoothService.getBondState().attempt(address);
}
- private void onBondingCreated(String address) {
- mBluetoothService.getBondState().setBondState(address.toUpperCase(),
- BluetoothDevice.BOND_BONDED);
+ private void onDeviceCreated(String deviceObjectPath) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (!mBluetoothService.isRemoteDeviceInCache(address)) {
+ // Incoming connection, we haven't seen this device, add to cache.
+ String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
+ if (properties != null) {
+ addDevice(address, properties);
+ }
+ }
+ return;
}
- private void onBondingRemoved(String address) {
- mBluetoothService.getBondState().setBondState(address.toUpperCase(),
- BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
+ private void onDeviceRemoved(String deviceObjectPath) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (address != null)
+ mBluetoothService.getBondState().setBondState(address.toUpperCase(),
+ BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
}
- private void onNameChanged(String name) {
- Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.NAME, name);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ /*package*/ void onPropertyChanged(String[] propValues) {
+ String name = propValues[0];
+ if (name.equals("Name")) {
+ Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.NAME, propValues[1]);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Pairable") || name.equals("Discoverable")) {
+ String pairable = name.equals("Pairable") ? propValues[1] :
+ mBluetoothService.getProperty("Pairable");
+ String discoverable = name.equals("Discoverable") ? propValues[1] :
+ mBluetoothService.getProperty("Discoverable");
+
+ // This shouldn't happen, unless Adapter Properties are null.
+ if (pairable == null || discoverable == null)
+ return;
+
+ int mode = BluetoothService.bluezStringToScanMode(
+ pairable.equals("true"),
+ discoverable.equals("true"));
+ if (mode >= 0) {
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Discovering")) {
+ Intent intent;
+ if (propValues[1].equals("true")) {
+ mBluetoothService.setIsDiscovering(true);
+ intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
+ } else {
+ // Stop the discovery.
+ mBluetoothService.cancelDiscovery();
+ mBluetoothService.setIsDiscovering(false);
+ intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
+ }
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Devices")) {
+ String value = null;
+ int len = Integer.valueOf(propValues[1]);
+ if (len > 0) {
+ value = "";
+ for (int i = 2; i < propValues.length; i++) {
+ value = value + propValues[i] + ',';
+ }
+ }
+ mBluetoothService.setProperty(name, value);
+ } else if (name.equals("Powered")) {
+ // bluetoothd has restarted, re-read all our properties.
+ // Note: bluez only sends this property change when it restarts.
+ if (propValues[1].equals("true"))
+ onRestartRequired();
+ }
}
- private void onPasskeyAgentRequest(String address, int nativeData) {
+ private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
+ String name = propValues[0];
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (address == null) {
+ 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.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.DEVICE, device);
+ intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
+ } else if (name.equals("Connected")) {
+ Intent intent = null;
+ if (propValues[1].equals("true")) {
+ intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+ } else {
+ intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
+ }
+ intent.putExtra(BluetoothIntent.DEVICE, device);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
+ } else if (name.equals("UUIDs")) {
+ String uuid = null;
+ int len = Integer.valueOf(propValues[1]);
+ if (len > 0) {
+ uuid = "";
+ for (int i = 2; i < propValues.length; i++) {
+ uuid = uuid + propValues[i] + ",";
+ }
+ }
+ mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
+ } else if (name.equals("Paired")) {
+ if (propValues[1].equals("true")) {
+ mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+ } else {
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED);
+ }
+ }
+ }
+
+ private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
+ String address = mBluetoothService.getAddressFromObjectPath(objectPath);
+ if (address == null) {
+ Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
+ "returning null");
+ return null;
+ }
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.cancelPin(address);
- return;
+ mBluetoothService.cancelPairingUserInput(address);
+ return null;
}
+ return address;
+ }
+
+ private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.PASSKEY, passkey);
+ intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
+ }
+
+ private void onRequestPasskey(String objectPath, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
+ }
+
+ private void onRequestPinCode(String objectPath, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
if (mBluetoothService.getBondState().getBondState(address) ==
BluetoothDevice.BOND_BONDING) {
@@ -307,55 +415,48 @@
}
}
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;
}
- private void onPasskeyAgentCancel(String address) {
- address = address.toUpperCase();
- mBluetoothService.cancelPin(address);
- Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- }
+ private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
+ String address = mBluetoothService.getAddressFromObjectPath(objectPath);
+ if (address == null) {
+ Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
+ return false;
+ }
- private boolean onAuthAgentAuthorize(String address, String service, String uuid) {
boolean authorized = false;
- if (mBluetoothService.isEnabled() && service.endsWith("service_audio")) {
+ UUID uuid = UUID.fromString(deviceUuid);
+ if (mBluetoothService.isEnabled() &&
+ (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(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 connection from " + address);
+ Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
} else {
- Log.i(TAG, "Rejecting incoming A2DP connection from " + address);
+ Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
}
} else {
- Log.i(TAG, "Rejecting incoming " + service + " connection from " + address);
+ Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
}
return authorized;
}
- private void onAuthAgentCancel(String address, String service, String uuid) {
- // We immediately response to DBUS Authorize() so this should not
- // usually happen
- log("onAuthAgentCancel(" + address + ", " + service + ", " + uuid + ")");
- }
-
- private void onGetRemoteServiceChannelResult(String address, int channel) {
- IBluetoothDeviceCallback callback = mGetRemoteServiceChannelCallbacks.get(address);
- if (callback != null) {
- mGetRemoteServiceChannelCallbacks.remove(address);
- try {
- callback.onGetRemoteServiceChannelResult(address, channel);
- } catch (RemoteException e) {}
- }
+ private void onAgentCancel() {
+ Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
}
private void onRestartRequired() {
if (mBluetoothService.isEnabled()) {
- Log.e(TAG, "*** A serious error occured (did hcid crash?) - restarting Bluetooth ***");
+ Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
+ "restarting Bluetooth ***");
mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
}
}
@@ -363,4 +464,10 @@
private static void log(String msg) {
Log.d(TAG, msg);
}
+
+ private native void initializeNativeDataNative();
+ private native void startEventLoopNative();
+ private native void stopEventLoopNative();
+ private native boolean isEventLoopRunningNative();
+ private native void cleanupNativeDataNative();
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
new file mode 100644
index 0000000..acee3af
--- /dev/null
+++ b/core/java/android/server/BluetoothService.java
@@ -0,0 +1,1210 @@
+/*
+ * 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.
+ */
+
+/**
+ * TODO: Move this to
+ * java/services/com/android/server/BluetoothService.java
+ * and make the contructor package private again.
+ *
+ * @hide
+ */
+
+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.IBluetooth;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemService;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.app.IBatteryStats;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class BluetoothService extends IBluetooth.Stub {
+ private static final String TAG = "BluetoothService";
+ private static final boolean DBG = true;
+
+ private int mNativeData;
+ private BluetoothEventLoop mEventLoop;
+ private IntentFilter mIntentFilter;
+ private boolean mIsAirplaneSensitive;
+ private int mBluetoothState;
+ private boolean mRestart = false; // need to call enable() after disable()
+ private boolean mIsDiscovering;
+
+ 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;
+ private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+ private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
+ private static final int MESSAGE_FINISH_DISABLE = 2;
+
+ private final Map<String, String> mAdapterProperties;
+ private final HashMap <String, Map<String, String>> mDeviceProperties;
+
+ static {
+ classInitNative();
+ }
+
+ public BluetoothService(Context context) {
+ mContext = context;
+
+ // Need to do this in place of:
+ // mBatteryStats = BatteryStatsService.getService();
+ // 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"));
+
+ initializeNativeDataNative();
+
+ if (isEnabledNative() == 1) {
+ Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
+ disableNative();
+ }
+
+ mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF;
+ mIsDiscovering = false;
+ mAdapterProperties = new HashMap<String, String>();
+ mDeviceProperties = new HashMap<String, Map<String,String>>();
+ registerForAirplaneMode();
+ }
+
+ public synchronized void initAfterRegistration() {
+ mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mIsAirplaneSensitive) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ try {
+ cleanupNativeDataNative();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public boolean isEnabled() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON;
+ }
+
+ public int getBluetoothState() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothState;
+ }
+
+
+ /**
+ * Bring down bluetooth and disable BT in settings. Returns true on success.
+ */
+ public boolean disable() {
+ return disable(true);
+ }
+
+ /**
+ * Bring down bluetooth. Returns true on success.
+ *
+ * @param saveSetting If true, disable BT in settings
+ */
+ public synchronized boolean disable(boolean saveSetting) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
+ switch (mBluetoothState) {
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+ return true;
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
+ break;
+ default:
+ return false;
+ }
+ if (mEnableThread != null && mEnableThread.isAlive()) {
+ return false;
+ }
+ 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
+ // BluetoothService when it is done shutting down
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
+ return true;
+ }
+
+
+ private synchronized void finishDisable(boolean saveSetting) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
+ return;
+ }
+ mEventLoop.stop();
+ tearDownNativeDataNative();
+ disableNative();
+
+ // mark in progress bondings as cancelled
+ for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ }
+
+ // update mode
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
+ mIsDiscovering = false;
+ mAdapterProperties.clear();
+
+ if (saveSetting) {
+ persistBluetoothOnSetting(false);
+ }
+
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF);
+
+ // Log bluetooth off to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOff();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ if (mRestart) {
+ mRestart = false;
+ enable();
+ }
+ }
+
+ /** Bring up BT and persist BT on in settings */
+ public boolean enable() {
+ return enable(true);
+ }
+
+ /**
+ * Enable this Bluetooth device, asynchronously.
+ * This turns on/off the underlying hardware.
+ *
+ * @param saveSetting If true, persist the new state of BT in settings
+ * @return True on success (so far)
+ */
+ public synchronized boolean enable(boolean saveSetting) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+
+ // Airplane mode can prevent Bluetooth radio from being turned on.
+ if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ return false;
+ }
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) {
+ return false;
+ }
+ if (mEnableThread != null && mEnableThread.isAlive()) {
+ return false;
+ }
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON);
+ mEnableThread = new EnableThread(saveSetting);
+ mEnableThread.start();
+ return true;
+ }
+
+ /** Forcibly restart Bluetooth if it is on */
+ /* package */ synchronized void restart() {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) {
+ return;
+ }
+ mRestart = true;
+ if (!disable(false)) {
+ mRestart = false;
+ }
+ }
+
+ private synchronized void setBluetoothState(int state) {
+ if (state == mBluetoothState) {
+ return;
+ }
+
+ if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
+
+ Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mBluetoothState = state;
+
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_REGISTER_SDP_RECORDS:
+ //TODO: Don't assume HSP/HFP is running, don't use sdptool,
+ if (isEnabled()) {
+ SystemService.start("hsag");
+ SystemService.start("hfag");
+ SystemService.start("opush");
+ SystemService.start("pbap");
+ }
+ break;
+ case MESSAGE_FINISH_DISABLE:
+ finishDisable(msg.arg1 != 0);
+ break;
+ }
+ }
+ };
+
+ private EnableThread mEnableThread;
+
+ private class EnableThread extends Thread {
+ private final boolean mSaveSetting;
+ public EnableThread(boolean saveSetting) {
+ mSaveSetting = saveSetting;
+ }
+ public void run() {
+ boolean res = (enableNative() == 0);
+ if (res) {
+ int retryCount = 2;
+ boolean running = false;
+ while ((retryCount-- > 0) && !running) {
+ mEventLoop.start();
+ // it may take a momement for the other thread to do its
+ // thing. Check periodically for a while.
+ int pollCount = 5;
+ while ((pollCount-- > 0) && !running) {
+ if (mEventLoop.isEventLoopRunning()) {
+ running = true;
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ }
+ }
+ if (!running) {
+ log("bt EnableThread giving up");
+ res = false;
+ disableNative();
+ }
+ }
+
+
+ if (res) {
+ if (!setupNativeDataNative()) {
+ return;
+ }
+ if (mSaveSetting) {
+ persistBluetoothOnSetting(true);
+ }
+ mIsDiscovering = false;
+ mBondState.loadBondState();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
+ 3000);
+
+ // Log bluetooth on to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOn();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ mEnableThread = null;
+
+ setBluetoothState(res ?
+ BluetoothAdapter.BLUETOOTH_STATE_ON :
+ BluetoothAdapter.BLUETOOTH_STATE_OFF);
+
+ if (res) {
+ // Update mode
+ String[] propVal = {"Pairable", getProperty("Pairable")};
+ mEventLoop.onPropertyChanged(propVal);
+ }
+
+ if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ disable(false);
+ }
+
+ }
+ }
+
+ private void persistBluetoothOnSetting(boolean bluetoothOn) {
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
+ bluetoothOn ? 1 : 0);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
+
+ /* package */ BondState getBondState() {
+ return mBondState;
+ }
+
+ /** local cache of bonding state.
+ /* we keep our own state to track the intermediate state BONDING, which
+ /* bluez does not track.
+ * All addreses must be passed in upper case.
+ */
+ public class BondState {
+ private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
+ private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
+ private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
+ // List of all the vendor_id prefix of Bluetooth addresses for
+ // which auto pairing is not attempted.
+ // The following companies are included in the list below:
+ // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
+ // Parrot, Zhongshan General K-mate Electronics, Great Well
+ // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
+ // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
+ // Continental Automotive, Harman/Becker
+ private final ArrayList<String> mAutoPairingBlacklisted =
+ new ArrayList<String>(Arrays.asList(
+ "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
+ "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
+ "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
+ "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
+ "00:0A:30", "00:1E:AE", "00:1C:D7"
+ ));
+
+ public synchronized void loadBondState() {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) {
+ return;
+ }
+ String []bonds = null;
+ String val = getProperty("Devices");
+ if (val != null) {
+ bonds = val.split(",");
+ }
+ if (bonds == null) {
+ return;
+ }
+ mState.clear();
+ if (DBG) log("found " + bonds.length + " bonded devices");
+ for (String device : bonds) {
+ mState.put(getAddressFromObjectPath(device).toUpperCase(),
+ BluetoothDevice.BOND_BONDED);
+ }
+ }
+
+ public synchronized void setBondState(String address, int state) {
+ setBondState(address, state, 0);
+ }
+
+ /** reason is ignored unless state == BOND_NOT_BONDED */
+ public synchronized void setBondState(String address, int state, int reason) {
+ int oldState = getBondState(address);
+ if (oldState == state) {
+ return;
+ }
+ if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
+ reason + ")");
+ Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
+ 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) {
+ if (reason <= 0) {
+ Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+ "invalid. Overriding reason code with BOND_RESULT_REMOVED");
+ reason = BluetoothDevice.UNBOND_REASON_REMOVED;
+ }
+ intent.putExtra(BluetoothIntent.REASON, reason);
+ mState.remove(address);
+ } else {
+ mState.put(address, state);
+ }
+
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
+ public boolean isAutoPairingBlacklisted(String address) {
+ for (String blacklistAddress : mAutoPairingBlacklisted) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ return false;
+ }
+
+ public synchronized int getBondState(String address) {
+ Integer state = mState.get(address);
+ if (state == null) {
+ return BluetoothDevice.BOND_NOT_BONDED;
+ }
+ return state.intValue();
+ }
+
+ private synchronized String[] listInState(int state) {
+ ArrayList<String> result = new ArrayList<String>(mState.size());
+ for (Map.Entry<String, Integer> e : mState.entrySet()) {
+ if (e.getValue().intValue() == state) {
+ result.add(e.getKey());
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ public synchronized void addAutoPairingFailure(String address) {
+ if (!mAutoPairingFailures.contains(address)) {
+ mAutoPairingFailures.add(address);
+ }
+ }
+
+ public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+ return getAttempt(address) != 0;
+ }
+
+ public synchronized void clearPinAttempts(String address) {
+ mPinAttempt.remove(address);
+ }
+
+ public synchronized boolean hasAutoPairingFailed(String address) {
+ return mAutoPairingFailures.contains(address);
+ }
+
+ public synchronized int getAttempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ if (attempt == null) {
+ return 0;
+ }
+ return attempt.intValue();
+ }
+
+ public synchronized void attempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ int newAttempt;
+ if (attempt == null) {
+ newAttempt = 1;
+ } else {
+ newAttempt = attempt.intValue() + 1;
+ }
+ mPinAttempt.put(address, new Integer(newAttempt));
+ }
+
+ }
+
+ private static String toBondStateString(int bondState) {
+ switch (bondState) {
+ case BluetoothDevice.BOND_NOT_BONDED:
+ return "not bonded";
+ case BluetoothDevice.BOND_BONDING:
+ return "bonding";
+ case BluetoothDevice.BOND_BONDED:
+ return "bonded";
+ default:
+ return "??????";
+ }
+ }
+
+ /*package*/synchronized void getAllProperties() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ mAdapterProperties.clear();
+
+ String properties[] = (String [])getAdapterPropertiesNative();
+ // The String Array consists of key-value pairs.
+ if (properties == null) {
+ Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
+ return;
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
+ continue;
+ }
+ if (name.equals("Devices")) {
+ len = Integer.valueOf(properties[++i]);
+ if (len != 0)
+ newValue = "";
+ else
+ newValue = null;
+ for (int j = 0; j < len; j++) {
+ newValue += properties[++i] + ",";
+ }
+ } else {
+ newValue = properties[++i];
+ }
+ mAdapterProperties.put(name, newValue);
+ }
+
+ // Add adapter object path property.
+ String adapterPath = getAdapterPathNative();
+ if (adapterPath != null)
+ mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
+ }
+
+ /* package */ synchronized void setProperty(String name, String value) {
+ mAdapterProperties.put(name, value);
+ }
+
+ public synchronized boolean setName(String name) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (name == null) {
+ return false;
+ }
+ return setPropertyString("Name", name);
+ }
+
+ //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
+ // Either have a single property function with Object as the parameter
+ // or have a function for each property and then obfuscate in the JNI layer.
+ // The following looks dirty.
+ private boolean setPropertyString(String key, String value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyStringNative(key, value);
+ }
+
+ private boolean setPropertyInteger(String key, int value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyIntegerNative(key, value);
+ }
+
+ private boolean setPropertyBoolean(String key, boolean value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
+ }
+
+ /**
+ * Set the discoverability window for the device. A timeout of zero
+ * makes the device permanently discoverable (if the device is
+ * discoverable). Setting the timeout to a nonzero value does not make
+ * a device discoverable; you need to call setMode() to make the device
+ * explicitly discoverable.
+ *
+ * @param timeout_s The discoverable timeout in seconds.
+ */
+ public synchronized boolean setDiscoverableTimeout(int timeout) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ return setPropertyInteger("DiscoverableTimeout", timeout);
+ }
+
+ public synchronized boolean setScanMode(int mode) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ boolean pairable = false, discoverable = false;
+ String modeString = scanModeToBluezString(mode);
+ if (modeString.equals("off")) {
+ pairable = false;
+ discoverable = false;
+ } else if (modeString.equals("pariable")) {
+ pairable = true;
+ discoverable = false;
+ } else if (modeString.equals("discoverable")) {
+ pairable = true;
+ discoverable = true;
+ }
+ setPropertyBoolean("Pairable", pairable);
+ setPropertyBoolean("Discoverable", discoverable);
+
+ return true;
+ }
+
+ /*package*/ synchronized String getProperty (String name) {
+ if (!mAdapterProperties.isEmpty())
+ return mAdapterProperties.get(name);
+ getAllProperties();
+ return mAdapterProperties.get(name);
+ }
+
+ public synchronized String getAddress() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return getProperty("Address");
+ }
+
+ public synchronized String getName() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return getProperty("Name");
+ }
+
+ /**
+ * Returns the user-friendly name of a remote device. This value is
+ * returned from our local cache, which is updated when onPropertyChange
+ * event is received.
+ * Do not expect to retrieve the updated remote name immediately after
+ * changing the name on the remote device.
+ *
+ * @param address Bluetooth address of remote device.
+ *
+ * @return The user-friendly name of the specified remote device.
+ */
+ public synchronized String getRemoteName(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return null;
+ }
+ Map <String, String> properties = mDeviceProperties.get(address);
+ if (properties != null) return properties.get("Name");
+ return null;
+ }
+
+ /**
+ * Get the discoverability window for the device. A timeout of zero
+ * means that the device is permanently discoverable (if the device is
+ * in the discoverable mode).
+ *
+ * @return The discoverability window of the device, in seconds. A negative
+ * value indicates an error.
+ */
+ public synchronized int getDiscoverableTimeout() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ String timeout = getProperty("DiscoverableTimeout");
+ if (timeout != null)
+ return Integer.valueOf(timeout);
+ else
+ return -1;
+ }
+
+ public synchronized int getScanMode() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!isEnabled())
+ return BluetoothError.ERROR;
+
+ boolean pairable = getProperty("Pairable").equals("true");
+ boolean discoverable = getProperty("Discoverable").equals("true");
+ return bluezStringToScanMode (pairable, discoverable);
+ }
+
+ public synchronized boolean startDiscovery() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!isEnabled()) {
+ return false;
+ }
+ return startDiscoveryNative();
+ }
+
+ public synchronized boolean cancelDiscovery() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ return stopDiscoveryNative();
+ }
+
+ public synchronized boolean isDiscovering() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mIsDiscovering;
+ }
+
+ /* package */ void setIsDiscovering(boolean isDiscovering) {
+ mIsDiscovering = isDiscovering;
+ }
+
+ public synchronized boolean createBond(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+
+ String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
+ if (bonding.length > 0 && !bonding[0].equals(address)) {
+ log("Ignoring createBond(): another device is bonding");
+ // a different device is currently bonding, fail
+ return false;
+ }
+
+ // Check for bond state only if we are not performing auto
+ // pairing exponential back-off attempts.
+ if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
+ mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+ log("Ignoring createBond(): this device is already bonding or bonded");
+ return false;
+ }
+
+ if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
+ return false;
+ }
+
+ mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
+ return true;
+ }
+
+ public synchronized boolean cancelBondProcess(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
+ return false;
+ }
+
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ cancelDeviceCreationNative(address);
+ return true;
+ }
+
+ public synchronized boolean removeBond(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ return removeDeviceNative(getObjectPathFromAddress(address));
+ }
+
+ public synchronized String[] listBonds() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBondState.listInState(BluetoothDevice.BOND_BONDED);
+ }
+
+ public synchronized int getBondState(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return BluetoothError.ERROR;
+ }
+ return mBondState.getBondState(address.toUpperCase());
+ }
+
+ /*package*/ boolean isRemoteDeviceInCache(String address) {
+ return (mDeviceProperties.get(address) != null);
+ }
+
+ /*package*/ String[] getRemoteDeviceProperties(String address) {
+ String objectPath = getObjectPathFromAddress(address);
+ return (String [])getDevicePropertiesNative(objectPath);
+ }
+
+ /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
+ Map<String, String> properties = mDeviceProperties.get(address);
+ if (properties != null) {
+ return properties.get(property);
+ } else {
+ // Query for remote device properties, again.
+ // We will need to reload the cache when we switch Bluetooth on / off
+ // or if we crash.
+ String[] propValues = getRemoteDeviceProperties(address);
+ if (propValues != null) {
+ addRemoteDeviceProperties(address, propValues);
+ return getRemoteDeviceProperty(address, property);
+ }
+ }
+ Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
+ return null;
+ }
+
+ /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
+ /*
+ * 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 = mDeviceProperties.get(address);
+ if (propertyValues != null) {
+ propertyValues.clear();
+ } else {
+ propertyValues = new HashMap<String, String>();
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
+ continue;
+ }
+ if (name.equals("UUIDs") || name.equals("Nodes")) {
+ len = Integer.valueOf(properties[++i]);
+ if (len != 0)
+ newValue = "";
+ else
+ newValue = null;
+ for (int j = 0; j < len; j++) {
+ newValue += properties[++i] + ",";
+ }
+ } else {
+ newValue = properties[++i];
+ }
+ propertyValues.put(name, newValue);
+ }
+ mDeviceProperties.put(address, propertyValues);
+ }
+
+ /* package */ void removeRemoteDeviceProperties(String address) {
+ mDeviceProperties.remove(address);
+ }
+
+ /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
+ String value) {
+ Map <String, String> propVal = mDeviceProperties.get(address);
+ if (propVal != null) {
+ propVal.put(name, value);
+ mDeviceProperties.put(address, propVal);
+ } else {
+ Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
+ }
+ }
+
+ /**
+ * Gets the remote major, minor classes encoded as a 32-bit
+ * integer.
+ *
+ * Note: this value is retrieved from cache, because we get it during
+ * remote-device discovery.
+ *
+ * @return 32-bit integer encoding the remote major, minor, and service
+ * classes.
+ */
+ public synchronized int getRemoteClass(String address) {
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return BluetoothClass.ERROR;
+ }
+ String val = getRemoteDeviceProperty(address, "Class");
+ if (val == null)
+ return BluetoothClass.ERROR;
+ else {
+ return Integer.valueOf(val);
+ }
+ }
+
+
+ /**
+ * Gets the remote features encoded as bit mask.
+ *
+ * Note: This method may be obsoleted soon.
+ *
+ * @return String array of 128bit UUIDs
+ */
+ public synchronized String[] getRemoteUuids(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return null;
+ }
+ String value = getRemoteDeviceProperty(address, "UUIDs");
+ String[] uuids = null;
+ // The UUIDs are stored as a "," separated string.
+ if (value != null)
+ uuids = value.split(",");
+ return uuids;
+ }
+
+ /**
+ * Gets the rfcomm channel associated with the UUID.
+ *
+ * @param address Address of the remote device
+ * @param uuid UUID of the service attribute
+ *
+ * @return rfcomm channel associated with the service attribute
+ */
+ public int getRemoteServiceChannel(String address, String uuid) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return BluetoothError.ERROR_IPC;
+ }
+ return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
+ }
+
+ public synchronized boolean setPin(String address, byte[] pin) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (pin == null || pin.length <= 0 || pin.length > 16 ||
+ !BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ // bluez API wants pin as a string
+ String pinString;
+ try {
+ pinString = new String(pin, "UTF8");
+ } catch (UnsupportedEncodingException uee) {
+ Log.e(TAG, "UTF8 not supported?!?");
+ return false;
+ }
+ return setPinNative(address, pinString, data.intValue());
+ }
+
+ public synchronized boolean setPasskey(String address, int passkey) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (passkey < 0 || passkey > 999999 || !BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ return setPasskeyNative(address, passkey, data.intValue());
+ }
+
+ public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ return setPairingConfirmationNative(address, confirm, data.intValue());
+ }
+
+ public synchronized boolean cancelPairingUserInput(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
+ "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
+ "by the remote or by bluez.\n");
+ return false;
+ }
+ return cancelPairingUserInputNative(address, data.intValue());
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ ContentResolver resolver = context.getContentResolver();
+ // Query the airplane mode from Settings.System just to make sure that
+ // some random app is not sending this intent and disabling bluetooth
+ boolean enabled = !isAirplaneModeOn();
+ // If bluetooth is currently expected to be on, then enable or disable bluetooth
+ if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
+ if (enabled) {
+ enable(false);
+ } else {
+ disable(false);
+ }
+ }
+ }
+ }
+ };
+
+ private void registerForAirplaneMode() {
+ String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_RADIOS);
+ mIsAirplaneSensitive = airplaneModeRadios == null
+ ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+ if (mIsAirplaneSensitive) {
+ mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+ }
+ }
+
+ /* Returns true if airplane mode is currently on */
+ private final boolean isAirplaneModeOn() {
+ return Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
+
+ switch(mBluetoothState) {
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+ pw.println("\nBluetooth OFF\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON:
+ pw.println("\nBluetooth TURNING ON\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
+ pw.println("\nBluetooth TURNING OFF\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
+ pw.println("\nBluetooth ON\n");
+ }
+
+ pw.println("\nLocal address = " + getAddress());
+ pw.println("\nLocal name = " + getName());
+ pw.println("\nisDiscovering() = " + isDiscovering());
+
+ BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
+
+ pw.println("\n--Known devices--");
+ for (String address : mDeviceProperties.keySet()) {
+ pw.printf("%s %10s (%d) %s\n", address,
+ toBondStateString(mBondState.getBondState(address)),
+ mBondState.getAttempt(address),
+ getRemoteName(address));
+ }
+
+ String value = getProperty("Devices");
+ String []devicesObjectPath = null;
+ if (value != null) {
+ devicesObjectPath = value.split(",");
+ }
+ pw.println("\n--ACL connected devices--");
+ for (String device : devicesObjectPath) {
+ pw.println(getAddressFromObjectPath(device));
+ }
+
+ // Rather not do this from here, but no-where else and I need this
+ // dump
+ pw.println("\n--Headset Service--");
+ switch (headset.getState()) {
+ case BluetoothHeadset.STATE_DISCONNECTED:
+ pw.println("getState() = STATE_DISCONNECTED");
+ break;
+ case BluetoothHeadset.STATE_CONNECTING:
+ pw.println("getState() = STATE_CONNECTING");
+ break;
+ case BluetoothHeadset.STATE_CONNECTED:
+ pw.println("getState() = STATE_CONNECTED");
+ break;
+ case BluetoothHeadset.STATE_ERROR:
+ pw.println("getState() = STATE_ERROR");
+ break;
+ }
+ pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
+ pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
+
+ headset.close();
+ }
+
+ /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
+ if (pairable && discoverable)
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+ else if (pairable && !discoverable)
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
+ else
+ return BluetoothAdapter.SCAN_MODE_NONE;
+ }
+
+ /* package */ static String scanModeToBluezString(int mode) {
+ switch (mode) {
+ case BluetoothAdapter.SCAN_MODE_NONE:
+ return "off";
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
+ return "connectable";
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ return "discoverable";
+ }
+ return null;
+ }
+
+ /*package*/ String getAddressFromObjectPath(String objectPath) {
+ String adapterObjectPath = getProperty("ObjectPath");
+ if (adapterObjectPath == null || objectPath == null) {
+ Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ " or deviceObjectPath:" + objectPath + " is null");
+ return null;
+ }
+ if (!objectPath.startsWith(adapterObjectPath)) {
+ Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ " is not a prefix of deviceObjectPath:" + objectPath +
+ "bluetoothd crashed ?");
+ return null;
+ }
+ String address = objectPath.substring(adapterObjectPath.length());
+ if (address != null) return address.replace('_', ':');
+
+ Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
+ return null;
+ }
+
+ /*package*/ String getObjectPathFromAddress(String address) {
+ String path = getProperty("ObjectPath");
+ if (path == null) {
+ Log.e(TAG, "Error: Object Path is null");
+ return null;
+ }
+ path = path + address.replace(":", "_");
+ return path;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
+ private native static void classInitNative();
+ private native void initializeNativeDataNative();
+ private native boolean setupNativeDataNative();
+ private native boolean tearDownNativeDataNative();
+ private native void cleanupNativeDataNative();
+ private native String getAdapterPathNative();
+
+ private native int isEnabledNative();
+ private native int enableNative();
+ private native int disableNative();
+
+ private native Object[] getAdapterPropertiesNative();
+ private native Object[] getDevicePropertiesNative(String objectPath);
+ private native boolean setAdapterPropertyStringNative(String key, String value);
+ private native boolean setAdapterPropertyIntegerNative(String key, int value);
+ private native boolean setAdapterPropertyBooleanNative(String key, int value);
+
+ private native boolean startDiscoveryNative();
+ private native boolean stopDiscoveryNative();
+
+ private native boolean createPairedDeviceNative(String address, int timeout_ms);
+ private native boolean cancelDeviceCreationNative(String address);
+ private native boolean removeDeviceNative(String objectPath);
+ private native int getDeviceServiceChannelNative(String objectPath, String uuid,
+ int attributeId);
+
+ private native boolean cancelPairingUserInputNative(String address, int nativeData);
+ private native boolean setPinNative(String address, String pin, int nativeData);
+ private native boolean setPasskeyNative(String address, int passkey, int nativeData);
+ private native boolean setPairingConfirmationNative(String address, boolean confirm,
+ int nativeData);
+
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
new file mode 100644
index 0000000..b09ccab
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.service.wallpaper;
+
+import android.os.ParcelFileDescriptor;
+import android.service.wallpaper.IWallpaperEngine;
+
+/**
+ * @hide
+ */
+interface IWallpaperConnection {
+ void attachEngine(IWallpaperEngine engine);
+ ParcelFileDescriptor setWallpaper(String name);
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
new file mode 100644
index 0000000..9586e34
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.service.wallpaper;
+
+/**
+ * @hide
+ */
+oneway interface IWallpaperEngine {
+ void destroy();
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
new file mode 100644
index 0000000..eb58c3b
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.service.wallpaper;
+
+import android.service.wallpaper.IWallpaperConnection;
+
+/**
+ * @hide
+ */
+oneway interface IWallpaperService {
+ void attach(IWallpaperConnection connection,
+ IBinder windowToken, int reqWidth, int reqHeight);
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
new file mode 100644
index 0000000..80a154b
--- /dev/null
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -0,0 +1,579 @@
+/*
+ * 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.service.wallpaper;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.BaseSurfaceHolder;
+
+import android.app.Service;
+import android.app.WallpaperManager;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+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;
+import android.view.ViewRoot;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+/**
+ * A wallpaper service is responsible for showing a live wallpaper behind
+ * applications that would like to sit on top of it.
+ * @hide Live Wallpaper
+ */
+public abstract class WallpaperService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.wallpaper.WallpaperService";
+
+ static final String TAG = "WallpaperService";
+ static final boolean DEBUG = false;
+
+ private static final int DO_ATTACH = 10;
+ private static final int DO_DETACH = 20;
+
+ 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
+ * have multiple instances running (for example as a real wallpaper
+ * and as a preview), each of which is represented by its own Engine
+ * instance. You must implement {@link WallpaperService#onCreateEngine()}
+ * to return your concrete Engine implementation.
+ */
+ public class Engine {
+ IWallpaperEngineWrapper mIWallpaperEngine;
+
+ // Copies from mIWallpaperEngine.
+ HandlerCaller mCaller;
+ IWallpaperConnection mConnection;
+ IBinder mWindowToken;
+
+ boolean mInitializing = true;
+
+ // Current window state.
+ boolean mCreated;
+ boolean mIsCreating;
+ boolean mDrawingAllowed;
+ int mWidth;
+ int mHeight;
+ int mFormat;
+ 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();
+ final Rect mContentInsets = new Rect();
+
+ final WindowManager.LayoutParams mLayout
+ = new WindowManager.LayoutParams();
+ IWindowSession mSession;
+
+ final Object mLock = new Object();
+ boolean mOffsetMessageEnqueued;
+ float mPendingXOffset;
+ float mPendingYOffset;
+ MotionEvent mPendingMove;
+
+ final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
+
+ @Override
+ public boolean onAllowLockCanvas() {
+ return mDrawingAllowed;
+ }
+
+ @Override
+ public void onRelayoutContainer() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
+ public void onUpdateSurface() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
+
+ public boolean isCreating() {
+ return mIsCreating;
+ }
+
+ public void setKeepScreenOn(boolean screenOn) {
+ // Ignore.
+ }
+
+ };
+
+ 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);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
+ public void dispatchWallpaperOffsets(float x, float y) {
+ synchronized (mLock) {
+ mPendingXOffset = x;
+ mPendingYOffset = y;
+ if (!mOffsetMessageEnqueued) {
+ mOffsetMessageEnqueued = true;
+ Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
+ mCaller.sendMessage(msg);
+ }
+ }
+ }
+
+ };
+
+ /**
+ * Provides access to the surface in which this wallpaper is drawn.
+ */
+ public SurfaceHolder getSurfaceHolder() {
+ return mSurfaceHolder;
+ }
+
+ /**
+ * Convenience for {@link WallpaperManager#getDesiredMinimumWidth()
+ * WallpaperManager.getDesiredMinimumWidth()}, returning the width
+ * that the system would like this wallpaper to run in.
+ */
+ public int getDesiredMinimumWidth() {
+ return mIWallpaperEngine.mReqWidth;
+ }
+
+ /**
+ * Convenience for {@link WallpaperManager#getDesiredMinimumHeight()
+ * WallpaperManager.getDesiredMinimumHeight()}, returning the height
+ * that the system would like this wallpaper to run in.
+ */
+ public int getDesiredMinimumHeight() {
+ return mIWallpaperEngine.mReqHeight;
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Called once to initialize the engine. After returning, the
+ * engine's surface will be created by the framework.
+ */
+ public void onCreate(SurfaceHolder surfaceHolder) {
+ }
+
+ /**
+ * Called right before the engine is going away. After this the
+ * surface will be destroyed and this Engine object is no longer
+ * valid.
+ */
+ public void onDestroy() {
+ }
+
+ /**
+ * Called to inform you of the wallpaper becoming visible or
+ * hidden. <em>It is very important that a wallpaper only use
+ * CPU while it is visible.</em>.
+ */
+ public void onVisibilityChanged(boolean visible) {
+ }
+
+ /**
+ * 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)
+ * WallpaperManager.setWallpaperOffsets()}.
+ */
+ public void onOffsetsChanged(float xOffset, float yOffset,
+ int xPixelOffset, int yPixelOffset) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
+ * SurfaceHolder.Callback.surfaceChanged()}.
+ */
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
+ * SurfaceHolder.Callback.surfaceCreated()}.
+ */
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
+ * SurfaceHolder.Callback.surfaceDestroyed()}.
+ */
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ void updateSurface(boolean force) {
+ int myWidth = mSurfaceHolder.getRequestedWidth();
+ if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
+ int myHeight = mSurfaceHolder.getRequestedHeight();
+ if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT;
+
+ final boolean creating = !mCreated;
+ final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
+ boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+ final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
+ final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
+ if (force || creating || formatChanged || sizeChanged || typeChanged
+ || flagsChanged) {
+
+ if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ + " format=" + formatChanged + " size=" + sizeChanged);
+
+ try {
+ mWidth = myWidth;
+ mHeight = myHeight;
+ mFormat = mSurfaceHolder.getRequestedFormat();
+ mType = mSurfaceHolder.getRequestedType();
+
+ mLayout.x = 0;
+ mLayout.y = 0;
+ mLayout.width = myWidth;
+ mLayout.height = myHeight;
+
+ mLayout.format = mFormat;
+
+ 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.gravity = Gravity.LEFT|Gravity.TOP;
+ mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
+ }
+
+ mSurfaceHolder.mSurfaceLock.lock();
+ mDrawingAllowed = true;
+
+ final int relayoutResult = mSession.relayout(
+ mWindow, mLayout, mWidth, mHeight,
+ View.VISIBLE, false, mWinFrame, mContentInsets,
+ mVisibleInsets, mSurfaceHolder.mSurface);
+
+ if (DEBUG) Log.i(TAG, "New surface: " + mSurfaceHolder.mSurface
+ + ", frame=" + mWinFrame);
+
+ 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();
+
+ try {
+ mDestroyReportNeeded = true;
+
+ SurfaceHolder.Callback callbacks[] = null;
+ synchronized (mSurfaceHolder.mCallbacks) {
+ final int N = mSurfaceHolder.mCallbacks.size();
+ if (N > 0) {
+ callbacks = new SurfaceHolder.Callback[N];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ }
+
+ if (!mCreated) {
+ mIsCreating = true;
+ onSurfaceCreated(mSurfaceHolder);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceCreated(mSurfaceHolder);
+ }
+ }
+ }
+ if (force || creating || formatChanged || sizeChanged) {
+ onSurfaceChanged(mSurfaceHolder, mFormat,
+ mCurWidth, mCurHeight);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceChanged(mSurfaceHolder, mFormat,
+ mCurWidth, mCurHeight);
+ }
+ }
+ }
+ } finally {
+ mIsCreating = false;
+ mCreated = true;
+ if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ mSession.finishDrawing(mWindow);
+ }
+ }
+ } catch (RemoteException ex) {
+ }
+ if (DEBUG) Log.v(
+ TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
+ " w=" + mLayout.width + " h=" + mLayout.height);
+ }
+ }
+
+ void attach(IWallpaperEngineWrapper wrapper) {
+ mIWallpaperEngine = wrapper;
+ mCaller = wrapper.mCaller;
+ mConnection = wrapper.mConnection;
+ mWindowToken = wrapper.mWindowToken;
+ // XXX temp -- should run in size from layout (screen) mode.
+ mSurfaceHolder.setFixedSize(mIWallpaperEngine.mReqWidth,
+ mIWallpaperEngine.mReqHeight);
+ //mSurfaceHolder.setSizeFromLayout();
+ mInitializing = true;
+ mSession = ViewRoot.getWindowSession(getMainLooper());
+ mWindow.setSession(mSession);
+
+ onCreate(mSurfaceHolder);
+
+ mInitializing = false;
+ updateSurface(false);
+ }
+
+ void detach() {
+ onDestroy();
+ if (mDestroyReportNeeded) {
+ mDestroyReportNeeded = false;
+ SurfaceHolder.Callback callbacks[];
+ synchronized (mSurfaceHolder.mCallbacks) {
+ callbacks = new SurfaceHolder.Callback[
+ mSurfaceHolder.mCallbacks.size()];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceDestroyed(mSurfaceHolder);
+ }
+ }
+ if (mCreated) {
+ try {
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ }
+ mSurfaceHolder.mSurface.clear();
+ mCreated = false;
+ }
+ }
+ }
+
+ class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
+ implements HandlerCaller.Callback {
+ private final HandlerCaller mCaller;
+
+ final IWallpaperConnection mConnection;
+ final IBinder mWindowToken;
+ int mReqWidth;
+ int mReqHeight;
+
+ Engine mEngine;
+
+ IWallpaperEngineWrapper(WallpaperService context,
+ IWallpaperConnection conn, IBinder windowToken,
+ int reqWidth, int reqHeight) {
+ mCaller = new HandlerCaller(context, this);
+ mConnection = conn;
+ mWindowToken = windowToken;
+ mReqWidth = reqWidth;
+ mReqHeight = reqHeight;
+
+ try {
+ conn.attachEngine(this);
+ } catch (RemoteException e) {
+ destroy();
+ }
+
+ Message msg = mCaller.obtainMessage(DO_ATTACH);
+ mCaller.sendMessage(msg);
+ }
+
+ public void destroy() {
+ Message msg = mCaller.obtainMessage(DO_DETACH);
+ mCaller.sendMessage(msg);
+ }
+
+ public void executeMessage(Message message) {
+ switch (message.what) {
+ case DO_ATTACH: {
+ Engine engine = onCreateEngine();
+ mEngine = engine;
+ engine.attach(this);
+ return;
+ }
+ case DO_DETACH: {
+ mEngine.detach();
+ return;
+ }
+ case MSG_UPDATE_SURFACE:
+ mEngine.updateSurface(false);
+ break;
+ case MSG_VISIBILITY_CHANGED:
+ if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
+ + ": " + message.arg1);
+ mEngine.onVisibilityChanged(message.arg1 != 0);
+ break;
+ case MSG_WALLPAPER_OFFSETS: {
+ float xOffset;
+ float yOffset;
+ synchronized (mEngine.mLock) {
+ xOffset = mEngine.mPendingXOffset;
+ yOffset = mEngine.mPendingYOffset;
+ mEngine.mOffsetMessageEnqueued = false;
+ }
+ if (DEBUG) Log.v(TAG, "Offsets change in " + mEngine
+ + ": " + xOffset + "," + yOffset);
+ final int availw = mReqWidth-mEngine.mCurWidth;
+ final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
+ final int availh = mReqHeight-mEngine.mCurHeight;
+ 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);
+ 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);
+ }
+ }
+ }
+
+ /**
+ * Implements the internal {@link IWallpaperService} interface to convert
+ * incoming calls to it back to calls on an {@link WallpaperService}.
+ */
+ class IWallpaperServiceWrapper extends IWallpaperService.Stub {
+ private final WallpaperService mTarget;
+
+ public IWallpaperServiceWrapper(WallpaperService context) {
+ mTarget = context;
+ }
+
+ public void attach(IWallpaperConnection conn,
+ IBinder windowToken, int reqWidth, int reqHeight) {
+ new IWallpaperEngineWrapper(
+ mTarget, conn, windowToken, reqWidth, reqHeight);
+ }
+ }
+
+ /**
+ * Implement to return the implementation of the internal accessibility
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IWallpaperServiceWrapper(this);
+ }
+
+ public abstract Engine onCreateEngine();
+}
diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index ecd719d..4b4c394 100644
--- a/core/java/android/syncml/pim/vcard/ContactStruct.java
+++ b/core/java/android/syncml/pim/vcard/ContactStruct.java
@@ -17,6 +17,7 @@
package android.syncml.pim.vcard;
import android.content.AbstractSyncableContentProvider;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -780,17 +781,16 @@
personId = ContentUris.parseId(personUri);
}
} else {
- personUri = provider.nonTransactionalInsert(People.CONTENT_URI, contentValues);
+ 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.nonTransactionalInsert(
- GroupMembership.CONTENT_URI, values);
+ Uri resultUri = provider.insert(GroupMembership.CONTENT_URI, values);
if (resultUri == null) {
Log.e(LOG_TAG, "Faild to insert the person to MyContact.");
- provider.nonTransactionalDelete(personUri, null, null);
+ provider.delete(personUri, null, null);
personUri = null;
}
}
@@ -830,7 +830,7 @@
if (resolver != null) {
phoneUri = resolver.insert(Phones.CONTENT_URI, values);
} else {
- phoneUri = provider.nonTransactionalInsert(Phones.CONTENT_URI, values);
+ phoneUri = provider.insert(Phones.CONTENT_URI, values);
}
if (phoneData.isPrimary) {
primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());
@@ -856,8 +856,7 @@
if (resolver != null) {
organizationUri = resolver.insert(Organizations.CONTENT_URI, values);
} else {
- organizationUri = provider.nonTransactionalInsert(
- Organizations.CONTENT_URI, values);
+ organizationUri = provider.insert(Organizations.CONTENT_URI, values);
}
if (organizationData.isPrimary) {
primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());
@@ -883,8 +882,7 @@
if (resolver != null) {
emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);
} else {
- emailUri = provider.nonTransactionalInsert(
- ContactMethods.CONTENT_URI, values);
+ emailUri = provider.insert(ContactMethods.CONTENT_URI, values);
}
if (contactMethod.isPrimary) {
primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());
@@ -893,8 +891,7 @@
if (resolver != null) {
resolver.insert(ContactMethods.CONTENT_URI, values);
} else {
- provider.nonTransactionalInsert(
- ContactMethods.CONTENT_URI, values);
+ provider.insert(ContactMethods.CONTENT_URI, values);
}
}
}
@@ -918,7 +915,7 @@
if (resolver != null) {
contentValuesArray.add(values);
} else {
- provider.nonTransactionalInsert(Extensions.CONTENT_URI, values);
+ provider.insert(Extensions.CONTENT_URI, values);
}
}
}
@@ -942,7 +939,7 @@
if (resolver != null) {
resolver.update(personUri, values, null, null);
} else {
- provider.nonTransactionalUpdate(personUri, values, null, null);
+ provider.update(personUri, values, null, null);
}
}
}
@@ -960,12 +957,12 @@
public void pushIntoAbstractSyncableContentProvider(
AbstractSyncableContentProvider provider, long myContactsGroupId) {
boolean successful = false;
- provider.beginTransaction();
+ provider.beginBatch();
try {
pushIntoContentProviderOrResolver(provider, myContactsGroupId);
successful = true;
} finally {
- provider.endTransaction(successful);
+ provider.endBatch(successful);
}
}
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index de0587a..1015506 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -30,6 +30,7 @@
public class AndroidTestCase extends TestCase {
protected Context mContext;
+ private Context mTestContext;
@Override
protected void setUp() throws Exception {
@@ -43,7 +44,7 @@
public void testAndroidTestCaseSetupProperly() {
assertNotNull("Context is null. setContext should be called before tests are run",
- mContext);
+ mContext);
}
public void setContext(Context context) {
@@ -55,6 +56,25 @@
}
/**
+ * Test context can be used to access resources from the test's own package
+ * as opposed to the resources from the test target package. Access to the
+ * latter is provided by the context set with the {@link #setContext}
+ * method.
+ *
+ * @hide
+ */
+ public void setTestContext(Context context) {
+ mTestContext = context;
+ }
+
+ /**
+ * @hide
+ */
+ public Context getTestContext() {
+ return mTestContext;
+ }
+
+ /**
* Asserts that launching a given activity is protected by a particular permission by
* attempting to start the activity and validating that a {@link SecurityException}
* is thrown that mentions the permission in its error message.
@@ -125,9 +145,9 @@
* to scrub out any class variables. This protects against memory leaks in the case where a
* test case creates a non-static inner class (thus referencing the test case) and gives it to
* someone else to hold onto.
- *
+ *
* @param testCaseClass The class of the derived TestCase implementation.
- *
+ *
* @throws IllegalAccessException
*/
protected void scrubClass(final Class<?> testCaseClass)
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/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c133cf2..f0a5ffd 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -968,7 +968,13 @@
fm.bottom = bottom;
for (int i = 0; i < chooseht.length; i++) {
- chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+ if (chooseht[i] instanceof LineHeightSpan.WithDensity) {
+ ((LineHeightSpan.WithDensity) chooseht[i]).
+ chooseHeight(text, start, end, choosehtv[i], v, fm, paint);
+
+ } else {
+ chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+ }
}
above = fm.ascent;
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index f13820d..f9e7cac 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -27,6 +27,7 @@
public int baselineShift;
public int linkColor;
public int[] drawableState;
+ public float density = 1.0f;
public TextPaint() {
super();
@@ -51,5 +52,6 @@
baselineShift = tp.baselineShift;
linkColor = tp.linkColor;
drawableState = tp.drawableState;
+ density = tp.density;
}
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 1a4eb699..9dd8ceb 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -25,7 +25,9 @@
import java.util.Calendar;
import java.util.Date;
+import java.util.Formatter;
import java.util.GregorianCalendar;
+import java.util.Locale;
import java.util.TimeZone;
/**
@@ -1040,6 +1042,31 @@
/**
* Formats a date or a time range according to the local conventions.
+ * <p>
+ * Note that this is a convenience method. Using it involves creating an
+ * internal {@link java.util.Formatter} instance on-the-fly, which is
+ * somewhat costly in terms of memory and time. This is probably acceptable
+ * if you use the method only rarely, but if you rely on it for formatting a
+ * large number of dates, consider creating and reusing your own
+ * {@link java.util.Formatter} instance and use the version of
+ * {@link #formatDateRange(Context, long, long, int) formatDateRange}
+ * that takes a {@link java.util.Formatter}.
+ *
+ * @param context the context is required only if the time is shown
+ * @param startMillis the start time in UTC milliseconds
+ * @param endMillis the end time in UTC milliseconds
+ * @param flags a bit mask of options See
+ * {@link #formatDateRange(Context, long, long, int) formatDateRange}
+ * @return a string containing the formatted date/time range.
+ */
+ public static String formatDateRange(Context context, long startMillis,
+ long endMillis, int flags) {
+ Formatter f = new Formatter(new StringBuilder(50), Locale.getDefault());
+ return formatDateRange(context, f, startMillis, endMillis, flags).toString();
+ }
+
+ /**
+ * Formats a date or a time range according to the local conventions.
*
* <p>
* Example output strings (date formats in these examples are shown using
@@ -1181,14 +1208,17 @@
* instead of "December 31, 2008".
*
* @param context the context is required only if the time is shown
+ * @param formatter the Formatter used for formatting the date range.
+ * Note: be sure to call setLength(0) on StringBuilder passed to
+ * the Formatter constructor unless you want the results to accumulate.
* @param startMillis the start time in UTC milliseconds
* @param endMillis the end time in UTC milliseconds
* @param flags a bit mask of options
*
- * @return a string containing the formatted date/time range.
+ * @return the formatter with the formatted date/time range appended to the string buffer.
*/
- public static String formatDateRange(Context context, long startMillis,
- long endMillis, int flags) {
+ public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis,
+ long endMillis, int flags) {
Resources res = Resources.getSystem();
boolean showTime = (flags & FORMAT_SHOW_TIME) != 0;
boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0;
@@ -1423,8 +1453,7 @@
if (noMonthDay && startMonthNum == endMonthNum) {
// Example: "January, 2008"
- String startDateString = startDate.format(defaultDateFormat);
- return startDateString;
+ return formatter.format("%s", startDate.format(defaultDateFormat));
}
if (startYear != endYear || noMonthDay) {
@@ -1436,10 +1465,9 @@
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startDateString, startTimeString,
endWeekDayString, endDateString, endTimeString);
- return dateRange;
}
// Get the month, day, and year strings for the start and end dates
@@ -1476,12 +1504,11 @@
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
endYearString, endTimeString);
- return dateRange;
}
if (startDay != endDay) {
@@ -1496,12 +1523,11 @@
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
endYearString, endTimeString);
- return dateRange;
}
// Same start and end day
@@ -1522,6 +1548,7 @@
} else {
// Example: "10:00 - 11:00 am"
String timeFormat = res.getString(com.android.internal.R.string.time1_time2);
+ // Don't use the user supplied Formatter because the result will pollute the buffer.
timeString = String.format(timeFormat, startTimeString, endTimeString);
}
}
@@ -1545,7 +1572,7 @@
fullFormat = res.getString(com.android.internal.R.string.time_date);
} else {
// Example: "Oct 9"
- return dateString;
+ return formatter.format("%s", dateString);
}
}
} else if (showWeekDay) {
@@ -1554,16 +1581,15 @@
fullFormat = res.getString(com.android.internal.R.string.time_wday);
} else {
// Example: "Tue"
- return startWeekDayString;
+ return formatter.format("%s", startWeekDayString);
}
} else if (showTime) {
- return timeString;
+ return formatter.format("%s", timeString);
}
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat, timeString, startWeekDayString, dateString);
- return dateRange;
+ return formatter.format(fullFormat, timeString, startWeekDayString, dateString);
}
/**
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 92f6289..ab33cb3 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -22,6 +22,7 @@
import android.text.*;
import android.widget.TextView;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.MotionEvent;
// XXX this doesn't extend MetaKeyKeyListener because the signatures
@@ -256,8 +257,32 @@
(MetaKeyKeyListener.getMetaState(buffer,
MetaKeyKeyListener.META_SELECTING) != 0);
+ DoubleTapState[] tap = buffer.getSpans(0, buffer.length(),
+ DoubleTapState.class);
+ boolean doubletap = false;
+
+ if (tap.length > 0) {
+ if (event.getEventTime() - tap[0].mWhen <=
+ ViewConfiguration.getDoubleTapTimeout()) {
+ if (sameWord(buffer, off, Selection.getSelectionEnd(buffer))) {
+ doubletap = true;
+ }
+ }
+
+ tap[0].mWhen = event.getEventTime();
+ } else {
+ DoubleTapState newtap = new DoubleTapState();
+ newtap.mWhen = event.getEventTime();
+ buffer.setSpan(newtap, 0, buffer.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
if (cap) {
Selection.extendSelection(buffer, off);
+ } else if (doubletap) {
+ Selection.setSelection(buffer,
+ findWordStart(buffer, off),
+ findWordEnd(buffer, off));
} else {
Selection.setSelection(buffer, off);
}
@@ -272,6 +297,62 @@
return handled;
}
+ private static class DoubleTapState implements NoCopySpan {
+ long mWhen;
+ }
+
+ private static boolean sameWord(CharSequence text, int one, int two) {
+ int start = findWordStart(text, one);
+ int end = findWordEnd(text, one);
+
+ if (end == start) {
+ return false;
+ }
+
+ return start == findWordStart(text, two) &&
+ end == findWordEnd(text, two);
+ }
+
+ // TODO: Unify with TextView.getWordForDictionary()
+ private static int findWordStart(CharSequence text, int start) {
+ for (; start > 0; start--) {
+ char c = text.charAt(start - 1);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ return start;
+ }
+
+ // TODO: Unify with TextView.getWordForDictionary()
+ private static int findWordEnd(CharSequence text, int end) {
+ int len = text.length();
+
+ for (; end < len; end++) {
+ char c = text.charAt(end);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ return end;
+ }
+
public boolean canSelectArbitrarily() {
return true;
}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index e420c27..172e9ac 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -434,7 +434,7 @@
PICKER_SETS.put('y', "\u00FD\u00FF");
PICKER_SETS.put('z', "\u017A\u017C\u017E");
PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
- "\u2026\u00A5\u2022\u00AE\u00A9\u00B1");
+ "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
};
private boolean showCharacterPicker(View view, Editable content, char c,
diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java
index 484f8ce..1214040 100644
--- a/core/java/android/text/style/AbsoluteSizeSpan.java
+++ b/core/java/android/text/style/AbsoluteSizeSpan.java
@@ -24,13 +24,28 @@
public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
private final int mSize;
+ private boolean mDip;
+ /**
+ * Set the text size to <code>size</code> physical pixels.
+ */
public AbsoluteSizeSpan(int size) {
mSize = size;
}
+ /**
+ * Set the text size to <code>size</code> physical pixels,
+ * or to <code>size</code> device-independent pixels if
+ * <code>dip</code> is true.
+ */
+ public AbsoluteSizeSpan(int size, boolean dip) {
+ mSize = size;
+ mDip = dip;
+ }
+
public AbsoluteSizeSpan(Parcel src) {
mSize = src.readInt();
+ mDip = src.readInt() != 0;
}
public int getSpanTypeId() {
@@ -43,19 +58,32 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSize);
+ dest.writeInt(mDip ? 1 : 0);
}
public int getSize() {
return mSize;
}
+ public boolean getDip() {
+ return mDip;
+ }
+
@Override
public void updateDrawState(TextPaint ds) {
- ds.setTextSize(mSize);
+ if (mDip) {
+ ds.setTextSize(mSize * ds.density);
+ } else {
+ ds.setTextSize(mSize);
+ }
}
@Override
public void updateMeasureState(TextPaint ds) {
- ds.setTextSize(mSize);
+ if (mDip) {
+ ds.setTextSize(mSize * ds.density);
+ } else {
+ ds.setTextSize(mSize);
+ }
}
}
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index c0ef97c..44a1706 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -19,6 +19,7 @@
import android.graphics.Paint;
import android.graphics.Canvas;
import android.text.Layout;
+import android.text.TextPaint;
public interface LineHeightSpan
extends ParagraphStyle, WrapTogetherSpan
@@ -26,4 +27,10 @@
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm);
+
+ public interface WithDensity extends LineHeightSpan {
+ public void chooseHeight(CharSequence text, int start, int end,
+ int spanstartv, int v,
+ Paint.FontMetricsInt fm, TextPaint paint);
+ }
}
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 24b4f73..81dd96e 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -73,7 +73,7 @@
* </ul>
* </li>
* <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- * corruption and enable stansard unix tools like grep, tail and wc to operate
+ * corruption and enable standard unix tools like grep, tail and wc to operate
* on event logs. </li>
* </ul>
*
@@ -124,10 +124,6 @@
"A List must have fewer than "
+ Byte.MAX_VALUE + " items in it.");
}
- if (items.length < 1) {
- throw new IllegalArgumentException(
- "A List must have at least one item in it.");
- }
for (int i = 0; i < items.length; i++) {
final Object item = items[i];
if (item == null) {
@@ -192,17 +188,21 @@
return decodeObject();
}
+ public byte[] getRawData() {
+ return mBuffer.array();
+ }
+
/** @return the loggable item at the current position in mBuffer. */
private Object decodeObject() {
if (mBuffer.remaining() < 1) return null;
switch (mBuffer.get()) {
case INT:
if (mBuffer.remaining() < 4) return null;
- return mBuffer.getInt();
+ return (Integer) mBuffer.getInt();
case LONG:
if (mBuffer.remaining() < 8) return null;
- return mBuffer.getLong();
+ return (Long) mBuffer.getLong();
case STRING:
try {
@@ -219,7 +219,7 @@
case LIST:
if (mBuffer.remaining() < 1) return null;
int length = mBuffer.get();
- if (length <= 0) return null;
+ if (length < 0) return null;
Object[] array = new Object[length];
for (int i = 0; i < length; ++i) {
array[i] = decodeObject();
@@ -285,4 +285,13 @@
*/
public static native void readEvents(int[] tags, Collection<Event> output)
throws IOException;
+
+ /**
+ * Read events from a file.
+ * @param path to read from
+ * @param output container to add events into
+ * @throws IOException if something goes wrong reading events
+ */
+ public static native void readEvents(String path, Collection<Event> output)
+ throws IOException;
}
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
new file mode 100644
index 0000000..b35dd1e
--- /dev/null
+++ b/core/java/android/util/MathUtils.java
@@ -0,0 +1,176 @@
+/*
+ * 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.util;
+
+import java.util.Random;
+
+/**
+ * A class that contains utility methods related to numbers.
+ *
+ * @hide Pending API council approval
+ */
+public final class MathUtils {
+ private static final Random sRandom = new Random();
+ private static final float DEG_TO_RAD = 3.1415926f / 180.0f;
+ private static final float RAD_TO_DEG = 180.0f / 3.1415926f;
+
+ private MathUtils() {
+ }
+
+ public static float abs(float v) {
+ return v > 0 ? v : -v;
+ }
+
+ public static int constrain(int amount, int low, int high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ public static float constrain(float amount, float low, float high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ public static float log(float a) {
+ return (float) Math.log(a);
+ }
+
+ public static float exp(float a) {
+ return (float) Math.exp(a);
+ }
+
+ public static float pow(float a, float b) {
+ return (float) Math.pow(a, b);
+ }
+
+ public static float max(float a, float b) {
+ return a > b ? a : b;
+ }
+
+ public static float max(int a, int b) {
+ return a > b ? a : b;
+ }
+
+ public static float max(float a, float b, float c) {
+ return a > b ? (a > c ? a : c) : (b > c ? b : c);
+ }
+
+ public static float max(int a, int b, int c) {
+ return a > b ? (a > c ? a : c) : (b > c ? b : c);
+ }
+
+ public static float min(float a, float b) {
+ return a < b ? a : b;
+ }
+
+ public static float min(int a, int b) {
+ return a < b ? a : b;
+ }
+
+ public static float min(float a, float b, float c) {
+ return a < b ? (a < c ? a : c) : (b < c ? b : c);
+ }
+
+ public static float min(int a, int b, int c) {
+ return a < b ? (a < c ? a : c) : (b < c ? b : c);
+ }
+
+ public static float dist(float x1, float y1, float x2, float y2) {
+ final float x = (x2 - x1);
+ final float y = (y2 - y1);
+ return (float) Math.sqrt(x * x + y * y);
+ }
+
+ public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) {
+ final float x = (x2 - x1);
+ final float y = (y2 - y1);
+ final float z = (z2 - z1);
+ return (float) Math.sqrt(x * x + y * y + z * z);
+ }
+
+ public static float mag(float a, float b) {
+ return (float) Math.sqrt(a * a + b * b);
+ }
+
+ public static float mag(float a, float b, float c) {
+ return (float) Math.sqrt(a * a + b * b + c * c);
+ }
+
+ public static float sq(float v) {
+ return v * v;
+ }
+
+ public static float radians(float degrees) {
+ return degrees * DEG_TO_RAD;
+ }
+
+ public static float degrees(float radians) {
+ return radians * RAD_TO_DEG;
+ }
+
+ public static float acos(float value) {
+ return (float) Math.acos(value);
+ }
+
+ public static float asin(float value) {
+ return (float) Math.asin(value);
+ }
+
+ public static float atan(float value) {
+ return (float) Math.atan(value);
+ }
+
+ public static float atan2(float a, float b) {
+ return (float) Math.atan2(a, b);
+ }
+
+ public static float tan(float angle) {
+ return (float) Math.tan(angle);
+ }
+
+ public static float lerp(float start, float stop, float amount) {
+ return start + (stop - start) * amount;
+ }
+
+ public static float norm(float start, float stop, float value) {
+ return (value - start) / (stop - start);
+ }
+
+ public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) {
+ return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+ }
+
+ public static int random(int howbig) {
+ return (int) (sRandom.nextFloat() * howbig);
+ }
+
+ public static int random(int howsmall, int howbig) {
+ if (howsmall >= howbig) return howsmall;
+ return (int) (sRandom.nextFloat() * (howbig - howsmall) + howsmall);
+ }
+
+ public static float random(float howbig) {
+ return sRandom.nextFloat() * howbig;
+ }
+
+ public static float random(float howsmall, float howbig) {
+ if (howsmall >= howbig) return howsmall;
+ return sRandom.nextFloat() * (howbig - howsmall) + howsmall;
+ }
+
+ public static void randomSeed(long seed) {
+ sRandom.setSeed(seed);
+ }
+}
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
new file mode 100644
index 0000000..bf25306
--- /dev/null
+++ b/core/java/android/util/Pair.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util;
+
+/**
+ * Container to ease passing around a tuple of two objects. This object provides a sensible
+ * implementation of equals(), returning true if equals() is true on each of the contained
+ * objects.
+ */
+public class Pair<F, S> {
+ public final F first;
+ public final S second;
+
+ /**
+ * Constructor for a Pair. If either are null then equals() and hashCode() will throw
+ * a NullPointerException.
+ * @param first the first object in the Pair
+ * @param second the second object in the pair
+ */
+ public Pair(F first, S second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ /**
+ * Checks the two objects for equality by delegating to their respective equals() methods.
+ * @param o the Pair to which this one is to be checked for equality
+ * @return true if the underlying objects of the Pair are both considered equals()
+ */
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Pair)) return false;
+ final Pair<F, S> other;
+ try {
+ other = (Pair<F, S>) o;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ return first.equals(other.first) && second.equals(other.second);
+ }
+
+ /**
+ * Compute a hash code using the hash codes of the underlying objects
+ * @return a hashcode of the Pair
+ */
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + first.hashCode();
+ result = 31 * result + second.hashCode();
+ return result;
+ }
+
+ /**
+ * Convenience method for creating an appropriately typed pair.
+ * @param a the first object in the Pair
+ * @param b the second object in the pair
+ * @return a Pair that is templatized with the types of a and b
+ */
+ public static <A, B> Pair <A, B> create(A a, B b) {
+ return new Pair<A, B>(a, b);
+ }
+}
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 841066c..f936f65 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -24,9 +24,18 @@
private HapticFeedbackConstants() {}
+ /**
+ * The user has performed a long press on an object that is resulting
+ * in an action being performed.
+ */
public static final int LONG_PRESS = 0;
/**
+ * The user has pressed on a virtual on-screen key.
+ */
+ public static final int VIRTUAL_KEY = 1;
+
+ /**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the setting in the
* view for whether to perform haptic feedback, do it always.
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 99d5c0c..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();
@@ -56,4 +56,9 @@
* to date on the current state showing navigational focus (touch mode) too.
*/
void windowFocusChanged(boolean hasFocus, boolean inTouchMode);
+
+ /**
+ * Called for wallpaper windows when their offsets change.
+ */
+ void dispatchWallpaperOffsets(float x, float y);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5607d4b..3e6cdc2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -90,7 +90,6 @@
void exitKeyguardSecurely(IOnKeyguardExitResult callback);
boolean inKeyguardRestrictedInputMode();
-
// These can only be called with the SET_ANIMATON_SCALE permission.
float getAnimationScale(int which);
float[] getAnimationScales();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1156856..4d662d2 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -108,4 +108,10 @@
boolean getInTouchMode();
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
+
+ /**
+ * For windows with the wallpaper behind them, and the wallpaper is
+ * larger than the screen, set the offset within the screen.
+ */
+ void setWallpaperPosition(IBinder windowToken, float x, float y);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6349288..f9b16fc 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -258,6 +258,25 @@
public static final int FLAG_EDITOR_ACTION = 0x10;
/**
+ * When associated with up key events, this indicates that the key press
+ * has been canceled. Typically this is used with virtual touch screen
+ * keys, where the user can slide from the virtual key area on to the
+ * display: in that case, the application will receive a canceled up
+ * event and should not perform the action normally associated with the
+ * key. Note that for this to work, the application can not perform an
+ * action for a key until it receives an up or the long press timeout has
+ * expired.
+ */
+ public static final int FLAG_CANCELED = 0x20;
+
+ /**
+ * This key event was generated by a virtual (on-screen) hard key area.
+ * Typically this is an area of the touchscreen, outside of the regular
+ * display, dedicated to "hardware" buttons.
+ */
+ public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
+
+ /**
* Returns the maximum keycode.
*/
public static int getMaxKeyCode() {
@@ -694,6 +713,14 @@
}
/**
+ * For {@link #ACTION_UP} events, indicates that the event has been
+ * canceled as per {@link #FLAG_CANCELED}.
+ */
+ public final boolean isCanceled() {
+ return (mFlags&FLAG_CANCELED) != 0;
+ }
+
+ /**
* Retrieve the key code of the key event. This is the physical key that
* was pressed, <em>not</em> the Unicode character.
*
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a224ed3..b2f0c60 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -19,7 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.util.Config;
+import android.util.Log;
/**
* Object used to report movement (mouse, pen, finger, trackball) events. This
@@ -27,17 +27,26 @@
* it is being used for.
*/
public final class MotionEvent implements Parcelable {
+ static final boolean DEBUG_POINTERS = false;
+
+ /**
+ * Bit mask of the parts of the action code that are the action itself.
+ */
+ public static final int ACTION_MASK = 0xff;
+
/**
* Constant for {@link #getAction}: A pressed gesture has started, the
* motion contains the initial starting location.
*/
public static final int ACTION_DOWN = 0;
+
/**
* Constant for {@link #getAction}: A pressed gesture has finished, the
* motion contains the final release location as well as any intermediate
* points since the last down or move event.
*/
public static final int ACTION_UP = 1;
+
/**
* Constant for {@link #getAction}: A change has happened during a
* press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
@@ -45,12 +54,14 @@
* points since the last down or move event.
*/
public static final int ACTION_MOVE = 2;
+
/**
* Constant for {@link #getAction}: The current gesture has been aborted.
* You will not receive any more points in it. You should treat this as
* an up event, but not perform any action that you normally would.
*/
public static final int ACTION_CANCEL = 3;
+
/**
* Constant for {@link #getAction}: A movement has happened outside of the
* normal bounds of the UI element. This does not provide a full gesture,
@@ -58,6 +69,70 @@
*/
public static final int ACTION_OUTSIDE = 4;
+ /**
+ * A non-primary pointer has gone down. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_DOWN = 5;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_2_DOWN = ACTION_POINTER_DOWN | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200;
+
+ /**
+ * A non-primary pointer has gone up. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_UP = 6;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_1_UP = ACTION_POINTER_UP | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_2_UP = ACTION_POINTER_UP | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_3_UP = ACTION_POINTER_UP | 0x0200;
+
+ /**
+ * Bits in the action code that represent a pointer ID, used with
+ * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Pointer IDs
+ * start at 0, with 0 being the primary (first) pointer in the motion. Note
+ * that this not <em>not</em> an index into the array of pointer values,
+ * which is compacted to only contain pointers that are down; the pointer
+ * ID for a particular index can be found with {@link #findPointerIndex}.
+ */
+ public static final int ACTION_POINTER_ID_MASK = 0xff00;
+
+ /**
+ * Bit shift for the action bits holding the pointer identifier as
+ * defined by {@link #ACTION_POINTER_ID_MASK}.
+ */
+ public static final int ACTION_POINTER_ID_SHIFT = 8;
+
private static final boolean TRACK_RECYCLED_LOCATION = false;
/**
@@ -80,34 +155,83 @@
*/
public static final int EDGE_RIGHT = 0x00000008;
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_X = 0;
+
+ /**
+ * Offset for the sample's Y coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_Y = 1;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_PRESSURE = 2;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_SIZE = 3;
+
+ /**
+ * Number of data items for each sample.
+ * @hide
+ */
+ static public final int NUM_SAMPLE_DATA = 4;
+
+ /**
+ * Number of possible pointers.
+ * @hide
+ */
+ static public final int BASE_AVAIL_POINTERS = 5;
+
+ static private final int BASE_AVAIL_SAMPLES = 8;
+
static private final int MAX_RECYCLED = 10;
static private Object gRecyclerLock = new Object();
static private int gRecyclerUsed = 0;
static private MotionEvent gRecyclerTop = null;
private long mDownTime;
- private long mEventTime;
+ private long mEventTimeNano;
private int mAction;
- private float mX;
- private float mY;
private float mRawX;
private float mRawY;
- private float mPressure;
- private float mSize;
- private int mMetaState;
- private int mNumHistory;
- private float[] mHistory;
- private long[] mHistoryTimes;
private float mXPrecision;
private float mYPrecision;
private int mDeviceId;
private int mEdgeFlags;
+ private int mMetaState;
+
+ // Here is the actual event data. Note that the order of the array
+ // is a little odd: the first entry is the most recent, and the ones
+ // following it are the historical data from oldest to newest. This
+ // allows us to easily retrieve the most recent data, without having
+ // to copy the arrays every time a new sample is added.
+
+ private int mNumPointers;
+ private int mNumSamples;
+ // Array of mNumPointers size of identifiers for each pointer of data.
+ private int[] mPointerIdentifiers;
+ // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data.
+ private float[] mDataSamples;
+ // Array of mNumSamples size of time stamps.
+ private long[] mTimeSamples;
private MotionEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
private MotionEvent() {
+ mPointerIdentifiers = new int[BASE_AVAIL_POINTERS];
+ mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA];
+ mTimeSamples = new long[BASE_AVAIL_SAMPLES];
}
static private MotionEvent obtain() {
@@ -127,6 +251,86 @@
/**
* Create a new MotionEvent, filling in all of the basic values that
* define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTimeNano The the time (in ns) when this specific event was generated. This
+ * must be obtained from {@link System#nanoTime()}.
+ * @param action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param pointers The number of points that will be in this event.
+ * @param inPointerIds An array of <em>pointers</em> values providing
+ * an identifier for each pointer.
+ * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial
+ * data samples for the event.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
+ * MotionEvent.
+ *
+ * @hide
+ */
+ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
+ int action, int pointers, int[] inPointerIds, float[] inData, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTimeNano = eventTimeNano;
+ ev.mAction = action;
+ ev.mMetaState = metaState;
+ ev.mRawX = inData[SAMPLE_X];
+ ev.mRawY = inData[SAMPLE_Y];
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+ ev.mNumPointers = pointers;
+ ev.mNumSamples = 1;
+
+ int[] pointerIdentifiers = ev.mPointerIdentifiers;
+ if (pointerIdentifiers.length < pointers) {
+ ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
+ }
+ System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
+
+ final int ND = pointers * NUM_SAMPLE_DATA;
+ float[] dataSamples = ev.mDataSamples;
+ if (dataSamples.length < ND) {
+ ev.mDataSamples = dataSamples = new float[ND];
+ }
+ System.arraycopy(inData, 0, dataSamples, 0, ND);
+
+ ev.mTimeSamples[0] = eventTime;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("New:");
+ for (int i=0; i<pointers; i++) {
+ sb.append(" #");
+ sb.append(ev.mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
+
+ return ev;
+ }
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
*
* @param downTime The time (in ms) when the user originally pressed down to start
* a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
@@ -162,16 +366,83 @@
ev.mDeviceId = deviceId;
ev.mEdgeFlags = edgeFlags;
ev.mDownTime = downTime;
- ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
- ev.mX = ev.mRawX = x;
- ev.mY = ev.mRawY = y;
- ev.mPressure = pressure;
- ev.mSize = size;
ev.mMetaState = metaState;
ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
+ return ev;
+ }
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param pointers The number of pointers that are active in this event.
+ * @param x The X coordinate of this event.
+ * @param y The Y coordinate of this event.
+ * @param pressure The current pressure of this event. The pressure generally
+ * ranges from 0 (no pressure at all) to 1 (normal pressure), however
+ * values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ * @param size A scaled value of the approximate size of the area being pressed when
+ * touched with the finger. The actual value in pixels corresponding to the finger
+ * touch is normalized with a device specific range of values
+ * and scaled to a value between 0 and 1.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
+ * MotionEvent.
+ */
+ static public MotionEvent obtain(long downTime, long eventTime, int action,
+ int pointers, float x, float y, float pressure, float size, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTimeNano = eventTime * 1000000;
+ ev.mAction = action;
+ ev.mNumPointers = pointers;
+ ev.mMetaState = metaState;
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -198,16 +469,24 @@
ev.mDeviceId = 0;
ev.mEdgeFlags = 0;
ev.mDownTime = downTime;
- ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
- ev.mX = ev.mRawX = x;
- ev.mY = ev.mRawY = y;
- ev.mPressure = 1.0f;
- ev.mSize = 1.0f;
+ ev.mNumPointers = 1;
ev.mMetaState = metaState;
ev.mXPrecision = 1.0f;
ev.mYPrecision = 1.0f;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = 1.0f;
+ data[SAMPLE_SIZE] = 1.0f;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -217,43 +496,17 @@
* @hide
*/
public void scale(float scale) {
- mX *= scale;
- mY *= scale;
mRawX *= scale;
mRawY *= scale;
- mSize *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] *= scale; // X
- history[i + 1] *= scale; // Y
- // no need to scale pressure ([i+2])
- history[i + 3] *= scale; // Size, TODO: square this?
- }
- }
- }
-
- /**
- * Translate the coordination of the event by given x and y.
- *
- * @hide
- */
- public void translate(float dx, float dy) {
- mX += dx;
- mY += dy;
- mRawX += dx;
- mRawY += dx;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] += dx; // X
- history[i + 1] += dy; // Y
- // no need to translate pressure (i+2) and size (i+3)
- }
+ float[] history = mDataSamples;
+ final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA;
+ for (int i = 0; i < length; i += NUM_SAMPLE_DATA) {
+ history[i + SAMPLE_X] *= scale;
+ history[i + SAMPLE_Y] *= scale;
+ // no need to scale pressure
+ history[i + SAMPLE_SIZE] *= scale; // TODO: square this?
}
}
@@ -265,24 +518,74 @@
ev.mDeviceId = o.mDeviceId;
ev.mEdgeFlags = o.mEdgeFlags;
ev.mDownTime = o.mDownTime;
- ev.mEventTime = o.mEventTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
ev.mAction = o.mAction;
- ev.mX = o.mX;
+ ev.mNumPointers = o.mNumPointers;
ev.mRawX = o.mRawX;
- ev.mY = o.mY;
ev.mRawY = o.mRawY;
- ev.mPressure = o.mPressure;
- ev.mSize = o.mSize;
ev.mMetaState = o.mMetaState;
ev.mXPrecision = o.mXPrecision;
ev.mYPrecision = o.mYPrecision;
- final int N = o.mNumHistory;
- ev.mNumHistory = N;
- if (N > 0) {
- // could be more efficient about this...
- ev.mHistory = (float[])o.mHistory.clone();
- ev.mHistoryTimes = (long[])o.mHistoryTimes.clone();
+
+ final int NS = ev.mNumSamples = o.mNumSamples;
+ if (ev.mTimeSamples.length >= NS) {
+ System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS);
+ } else {
+ ev.mTimeSamples = (long[])o.mTimeSamples.clone();
}
+
+ 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 * NS * 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;
+ }
+
+ /**
+ * 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;
}
@@ -305,7 +608,7 @@
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
gRecyclerUsed++;
- mNumHistory = 0;
+ mNumSamples = 0;
mNext = gRecyclerTop;
gRecyclerTop = this;
}
@@ -333,44 +636,145 @@
* Returns the time (in ms) when this specific event was generated.
*/
public final long getEventTime() {
- return mEventTime;
+ return mTimeSamples[0];
}
/**
- * Returns the X coordinate of this event. Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
+ * Returns the time (in ns) when this specific event was generated.
+ * The value is in nanosecond precision but it may not have nanosecond accuracy.
+ *
+ * @hide
+ */
+ public final long getEventTimeNano() {
+ return mEventTimeNano;
+ }
+
+ /**
+ * {@link #getX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getX() {
- return mX;
+ return mDataSamples[SAMPLE_X];
}
/**
- * Returns the Y coordinate of this event. Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
+ * {@link #getY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getY() {
- return mY;
+ return mDataSamples[SAMPLE_Y];
}
/**
- * Returns the current pressure of this event. The pressure generally
+ * {@link #getPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getPressure() {
+ return mDataSamples[SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getSize() {
+ return mDataSamples[SAMPLE_SIZE];
+ }
+
+ /**
+ * The number of pointers of data contained in this event. Always
+ * >= 1.
+ */
+ public final int getPointerCount() {
+ return mNumPointers;
+ }
+
+ /**
+ * Return the pointer identifier associated with a particular pointer
+ * data index is this event. The identifier tells you the actual pointer
+ * number associated with the data, accounting for individual pointers
+ * going up and down since the start of the current gesture.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final int getPointerId(int pointerIndex) {
+ return mPointerIdentifiers[pointerIndex];
+ }
+
+ /**
+ * Given a pointer identifier, find the index of its data in the event.
+ *
+ * @param pointerId The identifier of the pointer to be found.
+ * @return Returns either the index of the pointer (for use with
+ * {@link #getX(int) et al.), or -1 if there is no data available for
+ * that pointer identifier.
+ */
+ public final int findPointerIndex(int pointerId) {
+ int i = mNumPointers;
+ while (i > 0) {
+ i--;
+ if (mPointerIdentifiers[i] == pointerId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the X coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getX(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X];
+ }
+
+ /**
+ * Returns the Y coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getY(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y];
+ }
+
+ /**
+ * Returns the current pressure of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * The pressure generally
* ranges from 0 (no pressure at all) to 1 (normal pressure), however
* values higher than 1 may be generated depending on the calibration of
* the input device.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getPressure() {
- return mPressure;
+ public final float getPressure(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns a scaled value of the approximate size, of the area being pressed when
- * touched with the finger. The actual value in pixels corresponding to the finger
- * touch is normalized with the device specific range of values
+ * Returns a scaled value of the approximate size for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * This represents some approximation of the area of the screen being
+ * pressed; the actual value in pixels corresponding to the
+ * touch is normalized with the device specific range of values
* and scaled to a value between 0 and 1. The value of size can be used to
* determine fat touch events.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getSize() {
- return mSize;
+ public final float getSize(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -436,7 +840,7 @@
* @return Returns the number of historical points in the event.
*/
public final int getHistorySize() {
- return mNumHistory;
+ return mNumSamples - 1;
}
/**
@@ -450,63 +854,111 @@
* @see #getEventTime
*/
public final long getHistoricalEventTime(int pos) {
- return mHistoryTimes[pos];
+ return mTimeSamples[pos + 1];
}
/**
- * Returns a historical X coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * {@link #getHistoricalX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalX(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X];
+ }
+
+ /**
+ * {@link #getHistoricalY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalY(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y];
+ }
+
+ /**
+ * {@link #getHistoricalPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalPressure(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getHistoricalSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalSize(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE];
+ }
+
+ /**
+ * Returns a historical X coordinate, as per {@link #getX(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getX
*/
- public final float getHistoricalX(int pos) {
- return mHistory[pos*4];
+ public final float getHistoricalX(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X];
}
/**
- * Returns a historical Y coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical Y coordinate, as per {@link #getY(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getY
*/
- public final float getHistoricalY(int pos) {
- return mHistory[pos*4 + 1];
+ public final float getHistoricalY(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y];
}
/**
- * Returns a historical pressure coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical pressure coordinate, as per {@link #getPressure(int)},
+ * that occurred between this event and the previous event for the given
+ * pointer. Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getPressure
*/
- public final float getHistoricalPressure(int pos) {
- return mHistory[pos*4 + 2];
+ public final float getHistoricalPressure(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns a historical size coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical size coordinate, as per {@link #getSize(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getSize
*/
- public final float getHistoricalSize(int pos) {
- return mHistory[pos*4 + 3];
+ public final float getHistoricalSize(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -556,16 +1008,11 @@
* @param deltaY Amount to add to the current Y coordinate of the event.
*/
public final void offsetLocation(float deltaX, float deltaY) {
- mX += deltaX;
- mY += deltaY;
- final int N = mNumHistory*4;
- if (N <= 0) {
- return;
- }
- final float[] pos = mHistory;
- for (int i=0; i<N; i+=4) {
- pos[i] += deltaX;
- pos[i+1] += deltaY;
+ final int N = mNumPointers*mNumSamples*4;
+ final float[] pos = mDataSamples;
+ for (int i=0; i<N; i+=NUM_SAMPLE_DATA) {
+ pos[i+SAMPLE_X] += deltaX;
+ pos[i+SAMPLE_Y] += deltaY;
}
}
@@ -577,8 +1024,8 @@
* @param y New absolute Y location.
*/
public final void setLocation(float x, float y) {
- float deltaX = x-mX;
- float deltaY = y-mY;
+ float deltaX = x-mDataSamples[SAMPLE_X];
+ float deltaY = y-mDataSamples[SAMPLE_Y];
if (deltaX != 0 || deltaY != 0) {
offsetLocation(deltaX, deltaY);
}
@@ -590,58 +1037,119 @@
* the future, the current values in the event will be added to a list of
* historic values.
*
+ * @param eventTime The time stamp for this data.
* @param x The new X position.
* @param y The new Y position.
* @param pressure The new pressure.
* @param size The new size.
+ * @param metaState Meta key state.
*/
public final void addBatch(long eventTime, float x, float y,
float pressure, float size, int metaState) {
- float[] history = mHistory;
- long[] historyTimes = mHistoryTimes;
- int N;
- int avail;
- if (history == null) {
- mHistory = history = new float[8*4];
- mHistoryTimes = historyTimes = new long[8];
- mNumHistory = N = 0;
- avail = 8;
- } else {
- N = mNumHistory;
- avail = history.length/4;
- if (N == avail) {
- avail += 8;
- float[] newHistory = new float[avail*4];
- System.arraycopy(history, 0, newHistory, 0, N*4);
- mHistory = history = newHistory;
- long[] newHistoryTimes = new long[avail];
- System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N);
- mHistoryTimes = historyTimes = newHistoryTimes;
- }
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length <= ND) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
}
+ if (times.length <= NS) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
+ }
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ final int pos = NS*NUM_SAMPLE_DATA;
+ data[pos+SAMPLE_X] = data[SAMPLE_X];
+ data[pos+SAMPLE_Y] = data[SAMPLE_Y];
+ data[pos+SAMPLE_PRESSURE] = data[SAMPLE_PRESSURE];
+ data[pos+SAMPLE_SIZE] = data[SAMPLE_SIZE];
+ data[SAMPLE_X] = x;
+ data[SAMPLE_Y] = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ mNumSamples = NS+1;
- historyTimes[N] = mEventTime;
-
- final int pos = N*4;
- history[pos] = mX;
- history[pos+1] = mY;
- history[pos+2] = mPressure;
- history[pos+3] = mSize;
- mNumHistory = N+1;
-
- mEventTime = eventTime;
- mX = mRawX = x;
- mY = mRawY = y;
- mPressure = pressure;
- mSize = size;
+ mRawX = x;
+ mRawY = y;
mMetaState |= metaState;
}
+ /**
+ * Add a new movement to the batch of movements in this event. The
+ * input data must contain (NUM_SAMPLE_DATA * {@link #getPointerCount()})
+ * samples of data.
+ *
+ * @param eventTime The time stamp for this data.
+ * @param inData The actual data.
+ * @param metaState Meta key state.
+ *
+ * @hide
+ */
+ public final void addBatch(long eventTime, float[] inData, int metaState) {
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length <= ND) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
+ }
+ if (times.length <= NS) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
+ }
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ System.arraycopy(data, 0, data, ND, mNumPointers*NUM_SAMPLE_DATA);
+ System.arraycopy(inData, 0, data, 0, mNumPointers*NUM_SAMPLE_DATA);
+
+ mNumSamples = NS+1;
+
+ mRawX = inData[SAMPLE_X];
+ mRawY = inData[SAMPLE_Y];
+ mMetaState |= metaState;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Add:");
+ for (int i=0; i<mNumPointers; i++) {
+ sb.append(" #");
+ sb.append(mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
+ }
+
@Override
public String toString() {
return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this))
- + " action=" + mAction + " x=" + mX
- + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}";
+ + " action=" + mAction + " x=" + getX()
+ + " y=" + getY() + " pressure=" + getPressure() + " size=" + getSize() + "}";
}
public static final Parcelable.Creator<MotionEvent> CREATOR
@@ -663,26 +1171,29 @@
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mDownTime);
- out.writeLong(mEventTime);
+ out.writeLong(mEventTimeNano);
out.writeInt(mAction);
- out.writeFloat(mX);
- out.writeFloat(mY);
- out.writeFloat(mPressure);
- out.writeFloat(mSize);
out.writeInt(mMetaState);
out.writeFloat(mRawX);
out.writeFloat(mRawY);
- final int N = mNumHistory;
- out.writeInt(N);
- if (N > 0) {
- final int N4 = N*4;
+ final int NP = mNumPointers;
+ out.writeInt(NP);
+ final int NS = mNumSamples;
+ out.writeInt(NS);
+ final int NI = NP*NS;
+ if (NI > 0) {
int i;
- float[] history = mHistory;
- for (i=0; i<N4; i++) {
+ int[] state = mPointerIdentifiers;
+ for (i=0; i<NP; i++) {
+ out.writeInt(state[i]);
+ }
+ final int ND = NI*NUM_SAMPLE_DATA;
+ float[] history = mDataSamples;
+ for (i=0; i<ND; i++) {
out.writeFloat(history[i]);
}
- long[] times = mHistoryTimes;
- for (i=0; i<N; i++) {
+ long[] times = mTimeSamples;
+ for (i=0; i<NS; i++) {
out.writeLong(times[i]);
}
}
@@ -694,30 +1205,37 @@
private void readFromParcel(Parcel in) {
mDownTime = in.readLong();
- mEventTime = in.readLong();
+ mEventTimeNano = in.readLong();
mAction = in.readInt();
- mX = in.readFloat();
- mY = in.readFloat();
- mPressure = in.readFloat();
- mSize = in.readFloat();
mMetaState = in.readInt();
mRawX = in.readFloat();
mRawY = in.readFloat();
- final int N = in.readInt();
- if ((mNumHistory=N) > 0) {
- final int N4 = N*4;
- float[] history = mHistory;
- if (history == null || history.length < N4) {
- mHistory = history = new float[N4 + (4*4)];
+ final int NP = in.readInt();
+ mNumPointers = NP;
+ final int NS = in.readInt();
+ mNumSamples = NS;
+ final int NI = NP*NS;
+ if (NI > 0) {
+ int[] ids = mPointerIdentifiers;
+ if (ids.length < NP) {
+ mPointerIdentifiers = ids = new int[NP];
}
- for (int i=0; i<N4; i++) {
+ for (int i=0; i<NP; i++) {
+ ids[i] = in.readInt();
+ }
+ float[] history = mDataSamples;
+ final int ND = NI*NUM_SAMPLE_DATA;
+ if (history.length < ND) {
+ mDataSamples = history = new float[ND];
+ }
+ for (int i=0; i<ND; i++) {
history[i] = in.readFloat();
}
- long[] times = mHistoryTimes;
- if (times == null || times.length < N) {
- mHistoryTimes = times = new long[N + 4];
+ long[] times = mTimeSamples;
+ if (times == null || times.length < NS) {
+ mTimeSamples = times = new long[NS];
}
- for (int i=0; i<N; i++) {
+ for (int i=0; i<NS; i++) {
times[i] = in.readLong();
}
}
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
index 30da83e..db024b4 100644
--- a/core/java/android/view/RawInputEvent.java
+++ b/core/java/android/view/RawInputEvent.java
@@ -13,6 +13,8 @@
public static final int CLASS_ALPHAKEY = 0x00000002;
public static final int CLASS_TOUCHSCREEN = 0x00000004;
public static final int CLASS_TRACKBALL = 0x00000008;
+ public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
+ public static final int CLASS_DPAD = 0x00000020;
// More special classes for QueuedEvent below.
public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
@@ -158,8 +160,21 @@
public static final int ABS_TOOL_WIDTH = 0x1c;
public static final int ABS_VOLUME = 0x20;
public static final int ABS_MISC = 0x28;
+ public static final int ABS_MT_TOUCH_MAJOR = 0x30;
+ public static final int ABS_MT_TOUCH_MINOR = 0x31;
+ public static final int ABS_MT_WIDTH_MAJOR = 0x32;
+ public static final int ABS_MT_WIDTH_MINOR = 0x33;
+ public static final int ABS_MT_ORIENTATION = 0x34;
+ public static final int ABS_MT_POSITION_X = 0x35;
+ public static final int ABS_MT_POSITION_Y = 0x36;
+ public static final int ABS_MT_TOOL_TYPE = 0x37;
+ public static final int ABS_MT_BLOB_ID = 0x38;
public static final int ABS_MAX = 0x3f;
+ public static final int SYN_REPORT = 0;
+ public static final int SYN_CONFIG = 1;
+ public static final int SYN_MT_REPORT = 2;
+
public int deviceId;
public int type;
public int scancode;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 5100fff..9ec1013 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -34,12 +34,18 @@
/** Surface is created hidden */
public static final int HIDDEN = 0x00000004;
- /** The surface is to be used by hardware accelerators or DMA engines */
+ /** The surface is to be used by hardware accelerators or DMA engines
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int HARDWARE = 0x00000010;
/** Implies "HARDWARE", the surface is to be used by the GPU
* additionally the backbuffer is never preserved for these
- * surfaces. */
+ * surfaces.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int GPU = 0x00000028;
/** The surface contains secure content, special measures will
@@ -135,6 +141,8 @@
@SuppressWarnings("unused")
private int mSurface;
@SuppressWarnings("unused")
+ private int mSurfaceControl;
+ @SuppressWarnings("unused")
private int mSaveCount;
@SuppressWarnings("unused")
private Canvas mCanvas;
@@ -349,7 +357,7 @@
@Override
public String toString() {
- return "Surface(native-token=" + mSurface + ")";
+ return "Surface(native-token=" + mSurfaceControl + ")";
}
private Surface(Parcel source) throws OutOfResourcesException {
@@ -362,7 +370,7 @@
public native void readFromParcel(Parcel source);
public native void writeToParcel(Parcel dest, int flags);
-
+
public static final Parcelable.Creator<Surface> CREATOR
= new Parcelable.Creator<Surface>()
{
@@ -383,7 +391,7 @@
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
- clear();
+ release();
}
private native void init(SurfaceSession s,
@@ -391,4 +399,6 @@
throws OutOfResourcesException;
private native void init(Parcel source);
+
+ private native void release();
}
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 3d0dda3..64a10d1 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -38,8 +38,6 @@
* Surface type.
*
* @see #SURFACE_TYPE_NORMAL
- * @see #SURFACE_TYPE_HARDWARE
- * @see #SURFACE_TYPE_GPU
* @see #SURFACE_TYPE_PUSH_BUFFERS
*/
@@ -47,9 +45,15 @@
* contiguous, cached/buffered RAM. */
public static final int SURFACE_TYPE_NORMAL = MEMORY_TYPE_NORMAL;
/** Surface type: creates a suited to be used with DMA engines and
- * hardware accelerators. */
+ * hardware accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int SURFACE_TYPE_HARDWARE = MEMORY_TYPE_HARDWARE;
- /** Surface type: creates a surface suited to be used with the GPU */
+ /** Surface type: creates a surface suited to be used with the GPU
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int SURFACE_TYPE_GPU = MEMORY_TYPE_GPU;
/** Surface type: creates a "push" surface, that is a surface that
* doesn't owns its buffers. With such a surface lockCanvas will fail. */
@@ -139,11 +143,7 @@
public boolean isCreating();
/**
- * Sets the surface's type. Surfaces intended to be used with OpenGL ES
- * should be of SURFACE_TYPE_GPU, surfaces accessed by DMA engines and
- * hardware accelerators should be of type SURFACE_TYPE_HARDWARE.
- * Failing to set the surface's type appropriately could result in
- * degraded performance or failure.
+ * Sets the surface's type.
*
* @param type The surface's memory type.
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9cf7092..ea879ed9 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,8 @@
package android.view;
+import com.android.internal.view.BaseIWindow;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.CompatibilityInfo.Translator;
@@ -32,8 +34,9 @@
import android.util.AttributeSet;
import android.util.Config;
import android.util.Log;
-import java.util.ArrayList;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.ref.WeakReference;
@@ -279,7 +282,9 @@
return;
}
ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
- mTranslator = viewRoot.mTranslator;
+ if (viewRoot != null) {
+ mTranslator = viewRoot.mTranslator;
+ }
Resources res = getContext().getResources();
if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
@@ -434,7 +439,7 @@
updateWindow(false);
}
- private static class MyWindow extends IWindow.Stub {
+ private static class MyWindow extends BaseIWindow {
private final WeakReference<SurfaceView> mSurfaceView;
public MyWindow(SurfaceView surfaceView) {
@@ -476,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 {
@@ -486,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 {
@@ -568,9 +575,14 @@
public void setType(int type) {
switch (type) {
- case SURFACE_TYPE_NORMAL:
case SURFACE_TYPE_HARDWARE:
case SURFACE_TYPE_GPU:
+ // these are deprecated, treat as "NORMAL"
+ type = SURFACE_TYPE_NORMAL;
+ break;
+ }
+ switch (type) {
+ case SURFACE_TYPE_NORMAL:
case SURFACE_TYPE_PUSH_BUFFERS:
mRequestedType = type;
if (mWindow != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7ed2712..1dd0096 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2983,6 +2983,8 @@
* @param enabled True if this view is enabled, false otherwise.
*/
public void setEnabled(boolean enabled) {
+ if (enabled == isEnabled()) return;
+
setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
/*
@@ -6911,7 +6913,7 @@
/**
* Set the background to a given resource. The resource should refer to
- * a Drawable object.
+ * a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
* @attr ref android.R.styleable#View_background
*/
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index f7cb06b..3b78060 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -79,6 +79,9 @@
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean WATCH_POINTER = false;
+ private static final boolean MEASURE_LATENCY = false;
+ private static LatencyTimer lt;
+
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -148,7 +151,8 @@
boolean mWindowAttributesChanged = false;
// These can be accessed by any thread, must be protected with a lock.
- Surface mSurface;
+ // Surface can never be reassigned or cleared (use Surface.clear()).
+ private final Surface mSurface = new Surface();
boolean mAdded;
boolean mAddedTouchMode;
@@ -188,18 +192,11 @@
private final int mDensity;
- public ViewRoot(Context context) {
- super();
-
- ++sInstanceCount;
-
- // Initialize the statics when this class is first instantiated. This is
- // done here instead of in the static block because Zygote does not
- // allow the spawning of threads.
+ public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
- InputMethodManager imm = InputMethodManager.getInstance(context);
+ InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
@@ -207,8 +204,24 @@
} catch (RemoteException e) {
}
}
+ return sWindowSession;
+ }
+ }
+
+ public ViewRoot(Context context) {
+ super();
+
+ if (MEASURE_LATENCY && lt == null) {
+ lt = new LatencyTimer(100, 1000);
}
+ ++sInstanceCount;
+
+ // Initialize the statics when this class is first instantiated. This is
+ // done here instead of in the static block because Zygote does not
+ // allow the spawning of threads.
+ getWindowSession(context.getMainLooper());
+
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
@@ -224,7 +237,6 @@
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
- mSurface = new Surface();
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
@@ -1550,10 +1562,12 @@
mView = null;
mAttachInfo.mRootView = null;
+ mAttachInfo.mSurface = null;
if (mUseGL) {
destroyGL();
}
+ mSurface.clear();
try {
sWindowSession.remove(mWindow);
@@ -1623,16 +1637,24 @@
break;
case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent)msg.obj;
-
- boolean didFinish;
+ boolean callWhenDone = msg.arg1 != 0;
+
if (event == null) {
try {
+ long timeBeforeGettingEvents;
+ if (MEASURE_LATENCY) {
+ timeBeforeGettingEvents = System.nanoTime();
+ }
+
event = sWindowSession.getPendingPointerMove(mWindow);
+
+ if (MEASURE_LATENCY && event != null) {
+ lt.sample("9 Client got events ", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("8 Client getting events ", timeBeforeGettingEvents - event.getEventTimeNano());
+ }
} catch (RemoteException e) {
}
- didFinish = true;
- } else {
- didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
+ callWhenDone = false;
}
if (event != null && mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
@@ -1649,8 +1671,16 @@
if(Config.LOGV) {
captureMotionLog("captureDispatchPointer", event);
}
- event.offsetLocation(0, mCurScrollY);
+ if (mCurScrollY != 0) {
+ event.offsetLocation(0, mCurScrollY);
+ }
+ if (MEASURE_LATENCY) {
+ lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+ }
handled = mView.dispatchTouchEvent(event);
+ if (MEASURE_LATENCY) {
+ lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+ }
if (!handled && isDown) {
int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
@@ -1696,7 +1726,7 @@
}
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -1711,7 +1741,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);
@@ -1953,16 +1983,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);
@@ -1980,7 +2007,7 @@
}
} finally {
if (handled) {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2096,7 +2123,7 @@
mLastTrackballTime = curTime;
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2497,7 +2524,7 @@
}
}
- mSurface = null;
+ mSurface.clear();
}
if (mAdded) {
mAdded = false;
@@ -2559,15 +2586,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);
}
@@ -2740,19 +2771,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) {
- viewRoot.dispatchPointer(event, eventTime);
+ 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, 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);
}
@@ -2822,6 +2859,9 @@
}
}
}
+
+ public void dispatchWallpaperOffsets(float x, float y) {
+ }
}
/**
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index e159de4..703a38f 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -23,6 +23,8 @@
import com.android.internal.R;
+import java.lang.ref.WeakReference;
+
/**
* A ViewStub is an invisible, zero-sized View that can be used to lazily inflate
* layout resources at runtime.
@@ -68,6 +70,8 @@
private int mLayoutResource = 0;
private int mInflatedId;
+ private WeakReference<View> mInflatedViewRef;
+
private OnInflateListener mInflateListener;
public ViewStub(Context context) {
@@ -196,9 +200,15 @@
*/
@Override
public void setVisibility(int visibility) {
- super.setVisibility(visibility);
-
- if (visibility == VISIBLE || visibility == INVISIBLE) {
+ if (mInflatedViewRef != null) {
+ View view = mInflatedViewRef.get();
+ if (view != null) {
+ view.setVisibility(visibility);
+ } else {
+ throw new IllegalStateException("setVisibility called on un-referenced view");
+ }
+ } else if (visibility == VISIBLE || visibility == INVISIBLE) {
+ super.setVisibility(visibility);
inflate();
}
}
@@ -234,6 +244,8 @@
parent.addView(view, index);
}
+ mInflatedViewRef = new WeakReference(view);
+
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index a573983..e21824e 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -23,7 +23,9 @@
import android.media.AudioManager;
import android.media.AudioService;
import android.media.AudioSystem;
+import android.media.RingtoneManager;
import android.media.ToneGenerator;
+import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
@@ -44,7 +46,7 @@
public class VolumePanel extends Handler
{
private static final String TAG = "VolumePanel";
- private static boolean LOGD = false || Config.LOGD;
+ private static boolean LOGD = false;
/**
* The delay before playing a sound. This small period exists so the user
@@ -86,6 +88,7 @@
protected Context mContext;
private AudioManager mAudioManager;
protected AudioService mAudioService;
+ private boolean mRingIsSilent;
private final Toast mToast;
private final View mView;
@@ -138,7 +141,7 @@
onShowVolumeChanged(streamType, flags);
}
- if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
+ if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
removeMessages(MSG_PLAY_SOUND);
sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
}
@@ -157,6 +160,7 @@
int index = mAudioService.getStreamVolume(streamType);
int message = UNKNOWN_VOLUME_TEXT;
int additionalMessage = 0;
+ mRingIsSilent = false;
if (LOGD) {
Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
@@ -169,8 +173,15 @@
switch (streamType) {
case AudioManager.STREAM_RING: {
+ setRingerIcon();
message = RINGTONE_VOLUME_TEXT;
- setRingerIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_RINGTONE);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -208,6 +219,13 @@
case AudioManager.STREAM_NOTIFICATION: {
message = NOTIFICATION_VOLUME_TEXT;
setSmallIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_NOTIFICATION);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -254,7 +272,6 @@
mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
}
-
}
protected void onPlaySound(int streamType, int flags) {
@@ -337,17 +354,15 @@
/**
* Makes the ringer icon visible with an icon that is chosen
* based on the current ringer mode.
- *
- * @param index
*/
- private void setRingerIcon(int index) {
+ private void setRingerIcon() {
mSmallStreamIcon.setVisibility(View.GONE);
mLargeStreamIcon.setVisibility(View.VISIBLE);
int ringerMode = mAudioService.getRingerMode();
int icon;
- if (LOGD) Log.d(TAG, "setRingerIcon(index: " + index+ "), ringerMode: " + ringerMode);
+ if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
icon = com.android.internal.R.drawable.ic_volume_off;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 576c8c1..02e0515 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -56,11 +56,11 @@
public static final int FEATURE_CONTEXT_MENU = 6;
/** Flag for custom title. You cannot combine this feature with other title features. */
public static final int FEATURE_CUSTOM_TITLE = 7;
- /* Flag for asking for an OpenGL enabled window.
+ /** Flag for asking for an OpenGL enabled window.
All 2D graphics will be handled by OpenGL ES.
- Private for now, until it is better tested (not shipping in 1.0)
+ @hide
*/
- private static final int FEATURE_OPENGL = 8;
+ public static final int FEATURE_OPENGL = 8;
/** Flag for setting the progress bar's visibility to VISIBLE */
public static final int PROGRESS_VISIBILITY_ON = -1;
/** Flag for setting the progress bar's visibility to GONE */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c0be9e8..8c12656 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -314,6 +314,12 @@
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
/**
+ * Window type: wallpaper window, placed behind any window that wants
+ * to sit on top of the wallpaper.
+ */
+ public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
@@ -323,8 +329,6 @@
* Default is normal.
*
* @see #MEMORY_TYPE_NORMAL
- * @see #MEMORY_TYPE_HARDWARE
- * @see #MEMORY_TYPE_GPU
* @see #MEMORY_TYPE_PUSH_BUFFERS
*/
public int memoryType;
@@ -332,10 +336,16 @@
/** Memory type: The window's surface is allocated in main memory. */
public static final int MEMORY_TYPE_NORMAL = 0;
/** Memory type: The window's surface is configured to be accessible
- * by DMA engines and hardware accelerators. */
+ * by DMA engines and hardware accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int MEMORY_TYPE_HARDWARE = 1;
/** Memory type: The window's surface is configured to be accessible
- * by graphics accelerators. */
+ * by graphics accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int MEMORY_TYPE_GPU = 2;
/** Memory type: The window's surface doesn't own its buffers and
* therefore cannot be locked. Instead the buffers are pushed to
@@ -479,16 +489,23 @@
* key guard or any other lock screens. Can be used with
* {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
* directly before showing the key guard window
- *
- * {@hide} */
+ */
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
+ /** Window flag: ask that the system wallpaper be shown behind
+ * your window. The window surface must be translucent to be able
+ * to actually see the wallpaper behind it; this flag just ensures
+ * that the wallpaper surface will be there if this window actually
+ * has translucent regions.
+ */
+ public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
+
/** Window flag: special flag to limit the size of the window to be
* original size ([320x480] x density). Used to create window for applications
* running under compatibility mode.
*
* {@hide} */
- public static final int FLAG_COMPATIBLE_WINDOW = 0x00100000;
+ public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000;
/** Window flag: a special option intended for system dialogs. When
* this flag is set, the window will demand focus unconditionally when
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1371932..f4e9900 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -533,14 +533,15 @@
* @param win The window that currently has focus. This is where the key
* event will normally go.
* @param code Key code.
- * @param metaKeys TODO
+ * @param metaKeys bit mask of meta keys that are held.
* @param down Is this a key press (true) or release (false)?
* @param repeatCount Number of times a key down has repeated.
+ * @param flags event's flags.
* @return Returns true if the policy consumed the event and it should
* not be further dispatched.
*/
public boolean interceptKeyTi(WindowState win, int code,
- int metaKeys, boolean down, int repeatCount);
+ int metaKeys, boolean down, int repeatCount, int flags);
/**
* Called when layout of the windows is about to start.
@@ -792,6 +793,13 @@
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
/**
+ * A special function that is called from the very low-level input queue
+ * to provide feedback to the user. Currently only called for virtual
+ * keys.
+ */
+ public void keyFeedbackFromInput(KeyEvent event);
+
+ /**
* Called when we have stopped keeping the screen on because a window
* requesting this is no longer visible.
*/
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d797890..e30687f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -446,13 +446,22 @@
* @hide
*/
static public InputMethodManager getInstance(Context context) {
+ return getInstance(context.getMainLooper());
+ }
+
+ /**
+ * Internally, the input method manager can't be context-dependent, so
+ * we have this here for the places that need it.
+ * @hide
+ */
+ static public InputMethodManager getInstance(Looper mainLooper) {
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
- mInstance = new InputMethodManager(service, context.getMainLooper());
+ mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dbd2682..afa2c35 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -109,6 +109,8 @@
CacheManager.init(context);
// create CookieSyncManager with current Context
CookieSyncManager.createInstance(context);
+ // create PluginManager with current Context
+ PluginManager.getInstance(context);
}
AssetManager am = context.getAssets();
nativeCreateFrame(w, am, proxy.getBackForwardList());
@@ -119,7 +121,7 @@
mDatabase = WebViewDatabase.getInstance(context);
mWebViewCore = w;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
}
}
@@ -341,7 +343,7 @@
switch (msg.what) {
case FRAME_COMPLETED: {
if (mSettings.getSavePassword() && hasPasswordField()) {
- if (WebView.DEBUG) {
+ if (DebugFlags.BROWSER_FRAME) {
Assert.assertNotNull(mCallbackProxy.getBackForwardList()
.getCurrentItem());
}
@@ -463,8 +465,6 @@
* @param postData If the method is "POST" postData is sent as the request
* body. Is null when empty.
* @param cacheMode The cache mode to use when loading this resource.
- * @param isHighPriority True if this resource needs to be put at the front
- * of the network queue.
* @param synchronous True if the load is synchronous.
* @return A newly created LoadListener object.
*/
@@ -474,7 +474,6 @@
HashMap headers,
byte[] postData,
int cacheMode,
- boolean isHighPriority,
boolean synchronous) {
PerfChecker checker = new PerfChecker();
@@ -490,7 +489,7 @@
}
if (mSettings.getSavePassword() && hasPasswordField()) {
try {
- if (WebView.DEBUG) {
+ if (DebugFlags.BROWSER_FRAME) {
Assert.assertNotNull(mCallbackProxy.getBackForwardList()
.getCurrentItem());
}
@@ -538,10 +537,10 @@
// is this resource the main-frame top-level page?
boolean isMainFramePage = mIsMainFrame;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
- + method + ", postData=" + postData + ", isHighPriority="
- + isHighPriority + ", isMainFramePage=" + isMainFramePage);
+ + method + ", postData=" + postData + ", isMainFramePage="
+ + isMainFramePage);
}
// Create a LoadListener
@@ -551,23 +550,17 @@
mCallbackProxy.onLoadResource(url);
if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
+ // send an error message, so that loadListener can be deleted
+ // after this is returned. This is important as LoadListener's
+ // nativeError will remove the request from its DocLoader's request
+ // list. But the set up is not done until this method is returned.
loadListener.error(
android.net.http.EventHandler.ERROR, mContext.getString(
com.android.internal.R.string.httpErrorTooManyRequests));
- loadListener.notifyError();
- loadListener.tearDown();
- return null;
+ return loadListener;
}
- // during synchronous load, the WebViewCore thread is blocked, so we
- // need to endCacheTransaction first so that http thread won't be
- // blocked in setupFile() when createCacheFile.
- if (synchronous) {
- CacheManager.endCacheTransaction();
- }
-
- FrameLoader loader = new FrameLoader(loadListener, mSettings,
- method, isHighPriority);
+ FrameLoader loader = new FrameLoader(loadListener, mSettings, method);
loader.setHeaders(headers);
loader.setPostData(postData);
// Set the load mode to the mode used for the current page.
@@ -581,10 +574,6 @@
}
checker.responseAlert("startLoadingResource succeed");
- if (synchronous) {
- CacheManager.startCacheTransaction();
- }
-
return !synchronous ? loadListener : null;
}
@@ -615,6 +604,11 @@
mCallbackProxy.onReceivedIcon(icon);
}
+ // Called by JNI when an apple-touch-icon attribute was found.
+ private void didReceiveTouchIconUrl(String url) {
+ mCallbackProxy.onReceivedTouchIconUrl(url);
+ }
+
/**
* Request a new window from the client.
* @return The BrowserFrame object stored in the new WebView.
@@ -691,7 +685,7 @@
default:
Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
- return new String();
+ return "";
}
TypedValue value = new TypedValue();
mContext.getResources().getValue(resid, value, true);
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java
index 3e1b602..de8f888 100644
--- a/core/java/android/webkit/CacheLoader.java
+++ b/core/java/android/webkit/CacheLoader.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.net.http.Headers;
+import android.text.TextUtils;
/**
* This class is a concrete implementation of StreamLoader that uses a
@@ -49,17 +50,22 @@
@Override
protected void buildHeaders(Headers headers) {
StringBuilder sb = new StringBuilder(mCacheResult.mimeType);
- if (mCacheResult.encoding != null &&
- mCacheResult.encoding.length() > 0) {
+ if (!TextUtils.isEmpty(mCacheResult.encoding)) {
sb.append(';');
sb.append(mCacheResult.encoding);
}
headers.setContentType(sb.toString());
- if (mCacheResult.location != null &&
- mCacheResult.location.length() > 0) {
+ if (!TextUtils.isEmpty(mCacheResult.location)) {
headers.setLocation(mCacheResult.location);
}
- }
+ if (!TextUtils.isEmpty(mCacheResult.expiresString)) {
+ headers.setExpires(mCacheResult.expiresString);
+ }
+
+ if (!TextUtils.isEmpty(mCacheResult.contentdisposition)) {
+ headers.setContentDisposition(mCacheResult.contentdisposition);
+ }
+ }
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7897435..02e8d6f 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -51,7 +51,6 @@
private static final String NO_STORE = "no-store";
private static final String NO_CACHE = "no-cache";
- private static final String PRIVATE = "private";
private static final String MAX_AGE = "max-age";
private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
@@ -80,12 +79,14 @@
int httpStatusCode;
long contentLength;
long expires;
+ String expiresString;
String localPath;
String lastModified;
String etag;
String mimeType;
String location;
String encoding;
+ String contentdisposition;
// these fields are NOT saved to the database
InputStream inStream;
@@ -108,6 +109,13 @@
return expires;
}
+ /**
+ * @hide Pending API council approval
+ */
+ public String getExpiresString() {
+ return expiresString;
+ }
+
public String getLastModified() {
return lastModified;
}
@@ -128,6 +136,13 @@
return encoding;
}
+ /**
+ * @hide Pending API council approval
+ */
+ public String getContentDisposition() {
+ return contentdisposition;
+ }
+
// For out-of-package access to the underlying streams.
public InputStream getInputStream() {
return inStream;
@@ -321,7 +336,7 @@
}
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "getCacheFile for url " + url);
}
@@ -340,7 +355,7 @@
* @hide - hide createCacheFile since it has a parameter of type headers, which is
* in a hidden package.
*/
- // can be called from any thread
+ // only called from WebCore thread
public static CacheResult createCacheFile(String url, int statusCode,
Headers headers, String mimeType, boolean forceCache) {
if (!forceCache && mDisabled) {
@@ -349,17 +364,25 @@
// according to the rfc 2616, the 303 response MUST NOT be cached.
if (statusCode == 303) {
+ // remove the saved cache if there is any
+ mDataBase.removeCache(url);
return null;
}
// like the other browsers, do not cache redirects containing a cookie
// header.
if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) {
+ // remove the saved cache if there is any
+ mDataBase.removeCache(url);
return null;
}
CacheResult ret = parseHeaders(statusCode, headers, mimeType);
- if (ret != null) {
+ if (ret == null) {
+ // this should only happen if the headers has "no-store" in the
+ // cache-control. remove the saved cache if there is any
+ mDataBase.removeCache(url);
+ } else {
setupFiles(url, ret);
try {
ret.outStream = new FileOutputStream(ret.outFile);
@@ -403,19 +426,23 @@
}
cacheRet.contentLength = cacheRet.outFile.length();
- if (checkCacheRedirect(cacheRet.httpStatusCode)) {
+ boolean redirect = checkCacheRedirect(cacheRet.httpStatusCode);
+ if (redirect) {
// location is in database, no need to keep the file
cacheRet.contentLength = 0;
- cacheRet.localPath = new String();
- cacheRet.outFile.delete();
- } else if (cacheRet.contentLength == 0) {
- cacheRet.outFile.delete();
+ cacheRet.localPath = "";
+ }
+ if ((redirect || cacheRet.contentLength == 0)
+ && !cacheRet.outFile.delete()) {
+ Log.e(LOGTAG, cacheRet.outFile.getPath() + " delete failed.");
+ }
+ if (cacheRet.contentLength == 0) {
return;
}
mDataBase.addCache(url, cacheRet);
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "saveCacheFile for url " + url);
}
}
@@ -444,7 +471,10 @@
// if mBaseDir doesn't exist, files can be null.
if (files != null) {
for (int i = 0; i < files.length; i++) {
- new File(mBaseDir, files[i]).delete();
+ File f = new File(mBaseDir, files[i]);
+ if (!f.delete()) {
+ Log.e(LOGTAG, f.getPath() + " delete failed.");
+ }
}
}
} catch (SecurityException e) {
@@ -472,7 +502,10 @@
ArrayList<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
int size = pathList.size();
for (int i = 0; i < size; i++) {
- new File(mBaseDir, pathList.get(i)).delete();
+ File f = new File(mBaseDir, pathList.get(i));
+ if (!f.delete()) {
+ Log.e(LOGTAG, f.getPath() + " delete failed.");
+ }
}
}
}
@@ -511,12 +544,7 @@
// cache file. If it is not, resolve the collision.
while (file.exists()) {
if (checkOldPath) {
- // as this is called from http thread through
- // createCacheFile, we need endCacheTransaction before
- // database access.
- WebViewCore.endCacheTransaction();
CacheResult oldResult = mDataBase.getCache(url);
- WebViewCore.startCacheTransaction();
if (oldResult != null && oldResult.contentLength > 0) {
if (path.equals(oldResult.localPath)) {
path = oldResult.localPath;
@@ -596,21 +624,27 @@
if (location != null) ret.location = location;
ret.expires = -1;
- String expires = headers.getExpires();
- if (expires != null) {
+ ret.expiresString = headers.getExpires();
+ if (ret.expiresString != null) {
try {
- ret.expires = HttpDateTime.parse(expires);
+ ret.expires = HttpDateTime.parse(ret.expiresString);
} catch (IllegalArgumentException ex) {
// Take care of the special "-1" and "0" cases
- if ("-1".equals(expires) || "0".equals(expires)) {
+ if ("-1".equals(ret.expiresString)
+ || "0".equals(ret.expiresString)) {
// make it expired, but can be used for history navigation
ret.expires = 0;
} else {
- Log.e(LOGTAG, "illegal expires: " + expires);
+ Log.e(LOGTAG, "illegal expires: " + ret.expiresString);
}
}
}
+ String contentDisposition = headers.getContentDisposition();
+ if (contentDisposition != null) {
+ ret.contentdisposition = contentDisposition;
+ }
+
String lastModified = headers.getLastModified();
if (lastModified != null) ret.lastModified = lastModified;
@@ -628,7 +662,7 @@
// must be re-validated on every load. It does not mean that
// the content can not be cached. set to expire 0 means it
// can only be used in CACHE_MODE_CACHE_ONLY case
- if (NO_CACHE.equals(controls[i]) || PRIVATE.equals(controls[i])) {
+ if (NO_CACHE.equals(controls[i])) {
ret.expires = 0;
} else if (controls[i].startsWith(MAX_AGE)) {
int separator = controls[i].indexOf('=');
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 17d3f94..e77d29b 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -70,42 +70,51 @@
private final WebBackForwardList mBackForwardList;
// Used to call startActivity during url override.
private final Context mContext;
+ // Stores the URL being loaded and the viewing mode to switch into when
+ // the URL finishes loading.
+ private ChangeViewModeOnFinishedLoad mChange;
// Message Ids
- private static final int PAGE_STARTED = 100;
- private static final int RECEIVED_ICON = 101;
- private static final int RECEIVED_TITLE = 102;
- private static final int OVERRIDE_URL = 103;
- private static final int AUTH_REQUEST = 104;
- private static final int SSL_ERROR = 105;
- private static final int PROGRESS = 106;
- private static final int UPDATE_VISITED = 107;
- private static final int LOAD_RESOURCE = 108;
- private static final int CREATE_WINDOW = 109;
- private static final int CLOSE_WINDOW = 110;
- private static final int SAVE_PASSWORD = 111;
- private static final int JS_ALERT = 112;
- private static final int JS_CONFIRM = 113;
- private static final int JS_PROMPT = 114;
- private static final int JS_UNLOAD = 115;
- private static final int ASYNC_KEYEVENTS = 116;
- private static final int TOO_MANY_REDIRECTS = 117;
- private static final int DOWNLOAD_FILE = 118;
- private static final int REPORT_ERROR = 119;
- private static final int RESEND_POST_DATA = 120;
- private static final int PAGE_FINISHED = 121;
- private static final int REQUEST_FOCUS = 122;
- private static final int SCALE_CHANGED = 123;
- private static final int RECEIVED_CERTIFICATE = 124;
- private static final int SWITCH_OUT_HISTORY = 125;
- private static final int JS_TIMEOUT = 126;
+ private static final int PAGE_STARTED = 100;
+ private static final int RECEIVED_ICON = 101;
+ private static final int RECEIVED_TITLE = 102;
+ private static final int OVERRIDE_URL = 103;
+ private static final int AUTH_REQUEST = 104;
+ private static final int SSL_ERROR = 105;
+ private static final int PROGRESS = 106;
+ private static final int UPDATE_VISITED = 107;
+ private static final int LOAD_RESOURCE = 108;
+ private static final int CREATE_WINDOW = 109;
+ private static final int CLOSE_WINDOW = 110;
+ private static final int SAVE_PASSWORD = 111;
+ private static final int JS_ALERT = 112;
+ private static final int JS_CONFIRM = 113;
+ private static final int JS_PROMPT = 114;
+ private static final int JS_UNLOAD = 115;
+ private static final int ASYNC_KEYEVENTS = 116;
+ private static final int TOO_MANY_REDIRECTS = 117;
+ private static final int DOWNLOAD_FILE = 118;
+ private static final int REPORT_ERROR = 119;
+ private static final int RESEND_POST_DATA = 120;
+ private static final int PAGE_FINISHED = 121;
+ private static final int REQUEST_FOCUS = 122;
+ private static final int SCALE_CHANGED = 123;
+ private static final int RECEIVED_CERTIFICATE = 124;
+ private static final int SWITCH_OUT_HISTORY = 125;
+ private static final int EXCEEDED_DATABASE_QUOTA = 126;
+ private static final int REACHED_APPCACHE_MAXSIZE = 127;
+ private static final int JS_TIMEOUT = 128;
+ private static final int ADD_MESSAGE_TO_CONSOLE = 129;
+ private static final int GEOLOCATION_PERMISSIONS_SHOW_PROMPT = 130;
+ private static final int GEOLOCATION_PERMISSIONS_HIDE_PROMPT = 131;
+ private static final int RECEIVED_TOUCH_ICON_URL = 132;
// Message triggered by the client to resume execution
- private static final int NOTIFY = 200;
+ private static final int NOTIFY = 200;
// Result transportation object for returning results across thread
// boundaries.
- private class ResultTransport<E> {
+ private static class ResultTransport<E> {
// Private result object
private E mResult;
@@ -145,6 +154,16 @@
}
/**
+ * Get the WebChromeClient.
+ * @return the current WebChromeClient instance.
+ *
+ *@hide pending API council approval.
+ */
+ public WebChromeClient getWebChromeClient() {
+ return mWebChromeClient;
+ }
+
+ /**
* Set the client DownloadListener.
* @param client An implementation of DownloadListener.
*/
@@ -161,6 +180,37 @@
}
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param toZoomedOut If true, the WebView has zoomed out so that the page
+ * fits the screen. If false, it is zoomed to the setting
+ * specified by the user.
+ */
+ /* package */ void uiOnChangeViewingMode(boolean toZoomOverview) {
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onChangeViewingMode(toZoomOverview);
+ }
+ }
+
+ private static class ChangeViewModeOnFinishedLoad {
+ boolean mToZoomOverView;
+ String mOriginalUrl;
+ ChangeViewModeOnFinishedLoad(boolean toZoomOverview,
+ String originalUrl) {
+ mToZoomOverView = toZoomOverview;
+ mOriginalUrl = originalUrl;
+ }
+ }
+
+ /**
+ * Keep track of the url and the viewing mode to change into. If/when that
+ * url finishes loading, this will change the viewing mode.
+ */
+ /* package */ void uiChangeViewingModeOnFinishedLoad(
+ boolean toZoomOverview, String originalUrl) {
+ if (mWebChromeClient == null) return;
+ mChange = new ChangeViewModeOnFinishedLoad(toZoomOverview, originalUrl);
+ }
+ /**
* Called by the UI side. Calling overrideUrlLoading from the WebCore
* side will post a message to call this method.
*/
@@ -221,6 +271,15 @@
if (mWebViewClient != null) {
mWebViewClient.onPageFinished(mWebView, (String) msg.obj);
}
+ if (mChange != null) {
+ if (mWebView.getOriginalUrl().equals(mChange.mOriginalUrl)) {
+ uiOnChangeViewingMode(mChange.mToZoomOverView);
+ } else {
+ // The user has gone to a different page, so there is
+ // no need to hang on to the old object.
+ mChange = null;
+ }
+ }
break;
case RECEIVED_ICON:
@@ -229,6 +288,13 @@
}
break;
+ case RECEIVED_TOUCH_ICON_URL:
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onReceivedTouchIconUrl(mWebView,
+ (String) msg.obj);
+ }
+ break;
+
case RECEIVED_TITLE:
if (mWebChromeClient != null) {
mWebChromeClient.onReceivedTitle(mWebView,
@@ -389,6 +455,61 @@
}
break;
+ case EXCEEDED_DATABASE_QUOTA:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String databaseIdentifier =
+ (String) map.get("databaseIdentifier");
+ String url = (String) map.get("url");
+ long currentQuota =
+ ((Long) map.get("currentQuota")).longValue();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onExceededDatabaseQuota(url,
+ databaseIdentifier, currentQuota, totalUsedQuota,
+ quotaUpdater);
+ }
+ break;
+
+ case REACHED_APPCACHE_MAXSIZE:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ long spaceNeeded =
+ ((Long) map.get("spaceNeeded")).longValue();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onReachedMaxAppCacheSize(spaceNeeded,
+ totalUsedQuota, quotaUpdater);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_SHOW_PROMPT:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String origin = (String) map.get("origin");
+ GeolocationPermissions.Callback callback =
+ (GeolocationPermissions.Callback)
+ map.get("callback");
+ mWebChromeClient.onGeolocationPermissionsShowPrompt(origin,
+ callback);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_HIDE_PROMPT:
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onGeolocationPermissionsHidePrompt();
+ }
+ break;
+
case JS_ALERT:
if (mWebChromeClient != null) {
final JsResult res = (JsResult) msg.obj;
@@ -563,6 +684,13 @@
case SWITCH_OUT_HISTORY:
mWebView.switchOutDrawHistory();
break;
+
+ case ADD_MESSAGE_TO_CONSOLE:
+ String message = msg.getData().getString("message");
+ String sourceID = msg.getData().getString("sourceID");
+ int lineNumber = msg.getData().getInt("lineNumber");
+ mWebChromeClient.addMessageToConsole(message, lineNumber, sourceID);
+ break;
}
}
@@ -605,7 +733,40 @@
//--------------------------------------------------------------------------
// Performance probe
+ private static final boolean PERF_PROBE = false;
private long mWebCoreThreadTime;
+ private long mWebCoreIdleTime;
+
+ /*
+ * If PERF_PROBE is true, this block needs to be added to MessageQueue.java.
+ * startWait() and finishWait() should be called before and after wait().
+
+ private WaitCallback mWaitCallback = null;
+ public static interface WaitCallback {
+ void startWait();
+ void finishWait();
+ }
+ public final void setWaitCallback(WaitCallback callback) {
+ mWaitCallback = callback;
+ }
+ */
+
+ // un-comment this block if PERF_PROBE is true
+ /*
+ private IdleCallback mIdleCallback = new IdleCallback();
+
+ private final class IdleCallback implements MessageQueue.WaitCallback {
+ private long mStartTime = 0;
+
+ public void finishWait() {
+ mWebCoreIdleTime += SystemClock.uptimeMillis() - mStartTime;
+ }
+
+ public void startWait() {
+ mStartTime = SystemClock.uptimeMillis();
+ }
+ }
+ */
public void onPageStarted(String url, Bitmap favicon) {
// Do an unsynchronized quick check to avoid posting if no callback has
@@ -614,9 +775,12 @@
return;
}
// Performance probe
- if (false) {
+ if (PERF_PROBE) {
mWebCoreThreadTime = SystemClock.currentThreadTimeMillis();
+ mWebCoreIdleTime = 0;
Network.getInstance(mContext).startTiming();
+ // un-comment this if PERF_PROBE is true
+// Looper.myQueue().setWaitCallback(mIdleCallback);
}
Message msg = obtainMessage(PAGE_STARTED);
msg.obj = favicon;
@@ -631,10 +795,12 @@
return;
}
// Performance probe
- if (false) {
+ if (PERF_PROBE) {
+ // un-comment this if PERF_PROBE is true
+// Looper.myQueue().setWaitCallback(null);
Log.d("WebCore", "WebCore thread used " +
(SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime)
- + " ms");
+ + " ms and idled " + mWebCoreIdleTime + " ms");
Network.getInstance(mContext).stopTiming();
}
Message msg = obtainMessage(PAGE_FINISHED, url);
@@ -834,7 +1000,7 @@
String password, Message resumeMsg) {
// resumeMsg should be null at this point because we want to create it
// within the CallbackProxy.
- if (WebView.DEBUG) {
+ if (DebugFlags.CALLBACK_PROXY) {
junit.framework.Assert.assertNull(resumeMsg);
}
resumeMsg = obtainMessage(NOTIFY);
@@ -939,6 +1105,21 @@
sendMessage(obtainMessage(RECEIVED_ICON, icon));
}
+ /* package */ void onReceivedTouchIconUrl(String url) {
+ // We should have a current item but we do not want to crash so check
+ // for null.
+ WebHistoryItem i = mBackForwardList.getCurrentItem();
+ if (i != null) {
+ i.setTouchIconUrl(url);
+ }
+ // Do an unsynchronized quick check to avoid posting if no callback has
+ // been set.
+ if (mWebChromeClient == null) {
+ return;
+ }
+ sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL, url));
+ }
+
public void onReceivedTitle(String title) {
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
@@ -1037,6 +1218,127 @@
}
/**
+ * Called by WebViewCore to inform the Java side that the current origin
+ * has overflowed it's database quota. Called in the WebCore thread so
+ * posts a message to the UI thread that will prompt the WebChromeClient
+ * for what to do. On return back to C++ side, the WebCore thread will
+ * sleep pending a new quota value.
+ * @param url The URL that caused the quota overflow.
+ * @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 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
+ * quota has been made.
+ */
+ public void onExceededDatabaseQuota(
+ String url, String databaseIdentifier, long currentQuota,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ if (mWebChromeClient == null) {
+ quotaUpdater.updateQuota(currentQuota);
+ return;
+ }
+
+ Message exceededQuota = obtainMessage(EXCEEDED_DATABASE_QUOTA);
+ HashMap<String, Object> map = new HashMap();
+ map.put("databaseIdentifier", databaseIdentifier);
+ map.put("url", url);
+ map.put("currentQuota", currentQuota);
+ map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ exceededQuota.obj = map;
+ sendMessage(exceededQuota);
+ }
+
+ /**
+ * Called by WebViewCore to inform the Java side that the appcache has
+ * exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @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 a bigger
+ * app cache size has been made.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ if (mWebChromeClient == null) {
+ quotaUpdater.updateQuota(0);
+ return;
+ }
+
+ Message msg = obtainMessage(REACHED_APPCACHE_MAXSIZE);
+ HashMap<String, Object> map = new HashMap();
+ map.put("spaceNeeded", spaceNeeded);
+ map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ msg.obj = map;
+ sendMessage(msg);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to display a prompt to ask
+ * the user to set the Geolocation permission state for the given origin.
+ * @param origin The origin requesting Geolocation permsissions.
+ * @param callback The callback to call once a permission state has been
+ * obtained.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message showMessage =
+ obtainMessage(GEOLOCATION_PERMISSIONS_SHOW_PROMPT);
+ HashMap<String, Object> map = new HashMap();
+ map.put("origin", origin);
+ map.put("callback", callback);
+ showMessage.obj = map;
+ sendMessage(showMessage);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to hide the Geolocation
+ * permissions prompt.
+ * origin.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsHidePrompt() {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message hideMessage = obtainMessage(GEOLOCATION_PERMISSIONS_HIDE_PROMPT);
+ sendMessage(hideMessage);
+ }
+
+ /**
+ * Called by WebViewCore when we have a message to be added to the JavaScript
+ * error console. Sends a message to the Java side with the details.
+ * @param message The message to add to the console.
+ * @param lineNumber The lineNumber of the source file on which the error
+ * occurred.
+ * @param sourceID The filename of the source file in which the error
+ * occurred.
+ * @hide pending API counsel.
+ */
+ public void addMessageToConsole(String message, int lineNumber, String sourceID) {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message msg = obtainMessage(ADD_MESSAGE_TO_CONSOLE);
+ msg.getData().putString("message", message);
+ msg.getData().putString("sourceID", sourceID);
+ msg.getData().putInt("lineNumber", lineNumber);
+ sendMessage(msg);
+ }
+
+ /**
* @hide pending API council approval
*/
public boolean onJsTimeout() {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index e8c2279..fca591f 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -23,9 +23,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* CookieManager manages cookies according to RFC2109 spec.
@@ -190,6 +193,31 @@
}
}
+ private static final CookieComparator COMPARATOR = new CookieComparator();
+
+ private static final class CookieComparator implements Comparator<Cookie> {
+ public int compare(Cookie cookie1, Cookie cookie2) {
+ // According to RFC 2109, multiple cookies are ordered in a way such
+ // that those with more specific Path attributes precede those with
+ // less specific. Ordering with respect to other attributes (e.g.,
+ // Domain) is unspecified.
+ // As Set is not modified if the two objects are same, we do want to
+ // assign different value for each cookie.
+ int diff = cookie2.path.length() - cookie1.path.length();
+ if (diff == 0) {
+ diff = cookie2.domain.length() - cookie1.domain.length();
+ if (diff == 0) {
+ diff = cookie2.name.hashCode() - cookie1.name.hashCode();
+ if (diff == 0) {
+ Log.w(LOGTAG, "Found two cookies with the same value." +
+ "cookie1=" + cookie1 + " , cookie2=" + cookie2);
+ }
+ }
+ }
+ return diff;
+ }
+ }
+
private CookieManager() {
}
@@ -262,7 +290,7 @@
if (!mAcceptCookie || uri == null) {
return;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "setCookie: uri: " + uri + " value: " + value);
}
@@ -401,8 +429,8 @@
long now = System.currentTimeMillis();
boolean secure = HTTPS.equals(uri.mScheme);
Iterator<Cookie> iter = cookieList.iterator();
- StringBuilder ret = new StringBuilder(256);
+ SortedSet<Cookie> cookieSet = new TreeSet<Cookie>(COMPARATOR);
while (iter.hasNext()) {
Cookie cookie = iter.next();
if (cookie.domainMatch(hostAndPath[0]) &&
@@ -413,26 +441,33 @@
&& (!cookie.secure || secure)
&& cookie.mode != Cookie.MODE_DELETED) {
cookie.lastAcessTime = now;
-
- if (ret.length() > 0) {
- ret.append(SEMICOLON);
- // according to RC2109, SEMICOLON is office separator,
- // but when log in yahoo.com, it needs WHITE_SPACE too.
- ret.append(WHITE_SPACE);
- }
-
- ret.append(cookie.name);
- ret.append(EQUAL);
- ret.append(cookie.value);
+ cookieSet.add(cookie);
}
}
+
+ StringBuilder ret = new StringBuilder(256);
+ Iterator<Cookie> setIter = cookieSet.iterator();
+ while (setIter.hasNext()) {
+ Cookie cookie = setIter.next();
+ if (ret.length() > 0) {
+ ret.append(SEMICOLON);
+ // according to RC2109, SEMICOLON is official separator,
+ // but when log in yahoo.com, it needs WHITE_SPACE too.
+ ret.append(WHITE_SPACE);
+ }
+
+ ret.append(cookie.name);
+ ret.append(EQUAL);
+ ret.append(cookie.value);
+ }
+
if (ret.length() > 0) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "getCookie: uri: " + uri + " value: " + ret);
}
return ret.toString();
} else {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "getCookie: uri: " + uri
+ " But can't find cookie.");
}
@@ -588,7 +623,7 @@
Iterator<ArrayList<Cookie>> listIter = cookieLists.iterator();
while (listIter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
ArrayList<Cookie> list = listIter.next();
- if (WebView.DEBUG) {
+ if (DebugFlags.COOKIE_MANAGER) {
Iterator<Cookie> iter = list.iterator();
while (iter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
Cookie cookie = iter.next();
@@ -608,7 +643,7 @@
ArrayList<Cookie> retlist = new ArrayList<Cookie>();
if (mapSize >= MAX_RAM_DOMAIN_COUNT || count >= MAX_RAM_COOKIES_COUNT) {
- if (WebView.DEBUG) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, count + " cookies used " + byteCount
+ " bytes with " + mapSize + " domains");
}
@@ -616,7 +651,7 @@
int toGo = mapSize / 10 + 1;
while (toGo-- > 0){
String domain = domains[toGo].toString();
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "delete domain: " + domain
+ " from RAM cache");
}
@@ -798,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/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index 8d66529..14375d2 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -24,30 +24,39 @@
import java.util.Iterator;
/**
- * The class CookieSyncManager is used to synchronize the browser cookies
- * between RAM and FLASH. To get the best performance, browser cookie is saved
- * in RAM. We use a separate thread to sync the cookies between RAM and FLASH on
- * a timer base.
+ * The CookieSyncManager is used to synchronize the browser cookie store
+ * between RAM and permanent storage. To get the best performance, browser cookies are
+ * saved in RAM. A separate thread saves the cookies between, driven by a timer.
* <p>
+ *
* To use the CookieSyncManager, the host application has to call the following
- * when the application starts.
+ * when the application starts:
* <p>
- * CookieSyncManager.createInstance(context)
+ *
+ * <pre class="prettyprint">CookieSyncManager.createInstance(context)</pre><p>
+ *
+ * To set up for sync, the host application has to call<p>
+ * <pre class="prettyprint">CookieSyncManager.getInstance().startSync()</pre><p>
+ *
+ * in Activity.onResume(), and call
* <p>
- * To set up for sync, the host application has to call
- * <p>
- * CookieSyncManager.getInstance().startSync()
- * <p>
- * in its Activity.onResume(), and call
- * <p>
+ *
+ * <pre class="prettyprint">
* CookieSyncManager.getInstance().stopSync()
- * <p>
- * in its Activity.onStop().
- * <p>
+ * </pre><p>
+ *
+ * in Activity.onPause().<p>
+ *
* To get instant sync instead of waiting for the timer to trigger, the host can
* call
* <p>
- * CookieSyncManager.getInstance().sync()
+ * <pre class="prettyprint">CookieSyncManager.getInstance().sync()</pre><p>
+ *
+ * The sync interval is 5 minutes, so you will want to force syncs
+ * manually anyway, for instance in {@link
+ * WebViewClient#onPageFinished}. Note that even sync() happens
+ * asynchronously, so don't do it just as your activity is shutting
+ * down.
*/
public final class CookieSyncManager extends WebSyncManager {
@@ -90,7 +99,7 @@
}
/**
- * Package level api, called from CookieManager Get all the cookies which
+ * Package level api, called from CookieManager. Get all the cookies which
* matches a given base domain.
* @param domain
* @return A list of Cookie
@@ -161,7 +170,7 @@
}
protected void syncFromRamToFlash() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_SYNC_MANAGER) {
Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
}
@@ -178,7 +187,7 @@
CookieManager.getInstance().deleteLRUDomain();
syncFromRamToFlash(lruList);
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_SYNC_MANAGER) {
Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
}
}
diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java
index dcdc949..6c5d10d 100644
--- a/core/java/android/webkit/DataLoader.java
+++ b/core/java/android/webkit/DataLoader.java
@@ -16,12 +16,10 @@
package android.webkit;
-import org.apache.http.protocol.HTTP;
-
-import android.net.http.Headers;
-
import java.io.ByteArrayInputStream;
+import org.apache.harmony.luni.util.Base64;
+
/**
* This class is a concrete implementation of StreamLoader that uses the
* content supplied as a URL as the source for the stream. The mimetype
@@ -30,8 +28,6 @@
*/
class DataLoader extends StreamLoader {
- private String mContentType; // Content mimetype, if supplied in URL
-
/**
* Constructor uses the dataURL as the source for an InputStream
* @param dataUrl data: URL string optionally containing a mimetype
@@ -41,16 +37,20 @@
super(loadListener);
String url = dataUrl.substring("data:".length());
- String content;
+ byte[] data = null;
int commaIndex = url.indexOf(',');
if (commaIndex != -1) {
- mContentType = url.substring(0, commaIndex);
- content = url.substring(commaIndex + 1);
+ String contentType = url.substring(0, commaIndex);
+ data = url.substring(commaIndex + 1).getBytes();
+ loadListener.parseContentTypeHeader(contentType);
+ if ("base64".equals(loadListener.transferEncoding())) {
+ data = Base64.decode(data);
+ }
} else {
- content = url;
+ data = url.getBytes();
}
- mDataStream = new ByteArrayInputStream(content.getBytes());
- mContentLength = content.length();
+ mDataStream = new ByteArrayInputStream(data);
+ mContentLength = data.length;
}
@Override
@@ -60,10 +60,7 @@
}
@Override
- protected void buildHeaders(Headers headers) {
- if (mContentType != null) {
- headers.setContentType(mContentType);
- }
+ protected void buildHeaders(android.net.http.Headers h) {
}
/**
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 750403b..c46702e 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -43,9 +43,6 @@
private static final int NUM_DAYS_AGO = 5;
- Date mDate = new Date();
- Calendar mCal = Calendar.getInstance();
-
/**
* @param context Application context
*/
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
new file mode 100644
index 0000000..8e25395
--- /dev/null
+++ b/core/java/android/webkit/DebugFlags.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * This class is a container for all of the debug flags used in the Java
+ * components of webkit. These flags must be final in order to ensure that
+ * the compiler optimizes the code that uses them out of the final executable.
+ *
+ * The name of each flags maps directly to the name of the class in which that
+ * flag is used.
+ *
+ */
+class DebugFlags {
+
+ public static final boolean BROWSER_FRAME = false;
+ public static final boolean CACHE_MANAGER = false;
+ public static final boolean CALLBACK_PROXY = false;
+ public static final boolean COOKIE_MANAGER = false;
+ public static final boolean COOKIE_SYNC_MANAGER = false;
+ public static final boolean FRAME_LOADER = false;
+ public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
+ public static final boolean LOAD_LISTENER = false;
+ public static final boolean NETWORK = false;
+ public static final boolean SSL_ERROR_HANDLER = false;
+ public static final boolean STREAM_LOADER = false;
+ public static final boolean URL_UTIL = false;
+ public static final boolean WEB_BACK_FORWARD_LIST = false;
+ public static final boolean WEB_SETTINGS = false;
+ public static final boolean WEB_SYNC_MANAGER = false;
+ public static final boolean WEB_TEXT_VIEW = false;
+ public static final boolean WEB_VIEW = false;
+ public static final boolean WEB_VIEW_CORE = false;
+
+}
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 66ab021..c1eeb3b 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -28,7 +28,6 @@
private final LoadListener mListener;
private final String mMethod;
- private final boolean mIsHighPriority;
private final WebSettings mSettings;
private Map<String, String> mHeaders;
private byte[] mPostData;
@@ -52,11 +51,10 @@
private static final String LOGTAG = "webkit";
FrameLoader(LoadListener listener, WebSettings settings,
- String method, boolean highPriority) {
+ String method) {
mListener = listener;
mHeaders = null;
mMethod = method;
- mIsHighPriority = highPriority;
mCacheMode = WebSettings.LOAD_NORMAL;
mSettings = settings;
}
@@ -97,17 +95,6 @@
public boolean executeLoad() {
String url = mListener.url();
- // Attempt to decode the percent-encoded url.
- try {
- url = new String(URLUtil.decode(url.getBytes()));
- } catch (IllegalArgumentException e) {
- // Fail with a bad url error if the decode fails.
- mListener.error(EventHandler.ERROR_BAD_URL,
- mListener.getContext().getString(
- com.android.internal.R.string.httpErrorBadUrl));
- return false;
- }
-
if (URLUtil.isNetworkUrl(url)){
if (mSettings.getBlockNetworkLoads()) {
mListener.error(EventHandler.ERROR_BAD_URL,
@@ -115,12 +102,19 @@
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
+ // Make sure it is correctly URL encoded before sending the request
+ if (!URLUtil.verifyURLEncoding(url)) {
+ mListener.error(EventHandler.ERROR_BAD_URL,
+ mListener.getContext().getString(
+ com.android.internal.R.string.httpErrorBadUrl));
+ return false;
+ }
mNetwork = Network.getInstance(mListener.getContext());
return handleHTTPLoad();
} else if (handleLocalFile(url, mListener, mSettings)) {
return true;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
+ mListener.url());
}
@@ -134,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());
@@ -166,21 +172,17 @@
populateStaticHeaders();
populateHeaders();
- // response was handled by UrlIntercept, don't issue HTTP request
- if (handleUrlIntercept()) return true;
-
// response was handled by Cache, don't issue HTTP request
if (handleCache()) {
// push the request data down to the LoadListener
// as response from the cache could be a redirect
// and we may need to initiate a network request if the cache
// can't satisfy redirect URL
- mListener.setRequestData(mMethod, mHeaders, mPostData,
- mIsHighPriority);
+ mListener.setRequestData(mMethod, mHeaders, mPostData);
return true;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
+ mListener.url());
}
@@ -190,7 +192,7 @@
try {
ret = mNetwork.requestURL(mMethod, mHeaders,
- mPostData, mListener, mIsHighPriority);
+ mPostData, mListener);
} catch (android.net.ParseException ex) {
error = EventHandler.ERROR_BAD_URL;
} catch (java.lang.RuntimeException ex) {
@@ -207,11 +209,11 @@
}
/*
- * This function is used by handleUrlInterecpt and handleCache to
+ * This function is used by handleCache to
* setup a load from the byte stream in a CacheResult.
*/
private void startCacheLoad(CacheResult result) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: loading from cache: "
+ mListener.url());
}
@@ -223,30 +225,6 @@
}
/*
- * This function is used by handleHTTPLoad to allow URL
- * interception. This can be used to provide alternative load
- * methods such as locally stored versions or for debugging.
- *
- * Returns true if the response was handled by UrlIntercept.
- */
- private boolean handleUrlIntercept() {
- // Check if the URL can be served from UrlIntercept. If
- // successful, return the data just like a cache hit.
-
- PluginData data = UrlInterceptRegistry.getPluginData(
- mListener.url(), mHeaders);
-
- if(data != null) {
- PluginContentLoader loader =
- new PluginContentLoader(mListener, data);
- loader.load();
- return true;
- }
- // Not intercepted. Carry on as normal.
- return false;
- }
-
- /*
* This function is used by the handleHTTPLoad to setup the cache headers
* correctly.
* Returns true if the response was handled from the cache
@@ -285,7 +263,7 @@
// of it's state. If it is not in the cache, then go to the
// network.
case WebSettings.LOAD_CACHE_ELSE_NETWORK: {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: checking cache: "
+ mListener.url());
}
diff --git a/core/java/android/webkit/GearsPermissionsManager.java b/core/java/android/webkit/GearsPermissionsManager.java
deleted file mode 100644
index 6549cb8..0000000
--- a/core/java/android/webkit/GearsPermissionsManager.java
+++ /dev/null
@@ -1,246 +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.webkit;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.database.ContentObserver;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.io.File;
-import java.util.HashSet;
-
-/**
- * Donut-specific hack to keep Gears permissions in sync with the
- * system location setting.
- */
-class GearsPermissionsManager {
- // The application context.
- Context mContext;
- // The path to gears.so.
- private String mGearsPath;
-
- // The Gears permissions database directory.
- private final static String GEARS_DATABASE_DIR = "gears";
- // The Gears permissions database file name.
- private final static String GEARS_DATABASE_FILE = "permissions.db";
- // The Gears location permissions table.
- private final static String GEARS_LOCATION_ACCESS_TABLE_NAME =
- "LocationAccess";
- // The Gears storage access permissions table.
- private final static String GEARS_STORAGE_ACCESS_TABLE_NAME = "Access";
- // The Gears permissions db schema version table.
- private final static String GEARS_SCHEMA_VERSION_TABLE_NAME =
- "VersionInfo";
- // The Gears permission value that denotes "allow access to location".
- private static final int GEARS_ALLOW_LOCATION_ACCESS = 1;
- // The shared pref name.
- private static final String LAST_KNOWN_LOCATION_SETTING =
- "lastKnownLocationSystemSetting";
- // The Browser package name.
- private static final String BROWSER_PACKAGE_NAME = "com.android.browser";
- // The Secure Settings observer that will be notified when the system
- // location setting changes.
- private SecureSettingsObserver mSettingsObserver;
- // The Google URLs whitelisted for Gears location access.
- private static HashSet<String> sGearsWhiteList;
-
- static {
- sGearsWhiteList = new HashSet<String>();
- // NOTE: DO NOT ADD A "/" AT THE END!
- sGearsWhiteList.add("http://www.google.com");
- sGearsWhiteList.add("http://www.google.co.uk");
- }
-
- private static final String LOGTAG = "webcore";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
-
- GearsPermissionsManager(Context context, String gearsPath) {
- mContext = context;
- mGearsPath = gearsPath;
- }
-
- public void doCheckAndStartObserver() {
- // Are we running in the browser?
- if (!BROWSER_PACKAGE_NAME.equals(mContext.getPackageName())) {
- return;
- }
- // Do the check.
- checkGearsPermissions();
- // Install the observer.
- mSettingsObserver = new SecureSettingsObserver();
- mSettingsObserver.observe();
- }
-
- private void checkGearsPermissions() {
- // Get the current system settings.
- int setting = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USE_LOCATION_FOR_SERVICES, -1);
- // Check if we need to set the Gears permissions.
- if (setting != -1 && locationSystemSettingChanged(setting)) {
- setGearsPermissionForGoogleDomains(setting);
- }
- }
-
- private boolean locationSystemSettingChanged(int newSetting) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(mContext);
- int oldSetting = 0;
- oldSetting = prefs.getInt(LAST_KNOWN_LOCATION_SETTING, oldSetting);
- if (oldSetting == newSetting) {
- return false;
- }
- Editor ed = prefs.edit();
- ed.putInt(LAST_KNOWN_LOCATION_SETTING, newSetting);
- ed.commit();
- return true;
- }
-
- private void setGearsPermissionForGoogleDomains(int systemPermission) {
- // Transform the system permission into a boolean flag. When this
- // flag is true, it means the origins in gGearsWhiteList are added
- // to the Gears location permission table with permission 1 (allowed).
- // When the flag is false, the origins in gGearsWhiteList are removed
- // from the Gears location permission table. Next time the user
- // navigates to one of these origins, she will see the normal Gears
- // permission prompt.
- boolean addToGearsLocationTable = (systemPermission == 1 ? true : false);
- // Build the path to the Gears library.
-
- File file = new File(mGearsPath).getParentFile();
- if (file == null) {
- return;
- }
- // Build the Gears database file name.
- file = new File(file.getAbsolutePath() + File.separator
- + GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE);
- // Remember whether or not we need to create the LocationAccess table.
- boolean needToCreateTables = false;
- if (!file.exists()) {
- needToCreateTables = true;
- // Create the path or else SQLiteDatabase.openOrCreateDatabase()
- // may throw on the device.
- file.getParentFile().mkdirs();
- }
- // If the database file does not yet exist and the system location
- // setting says that the Gears origins need to be removed from the
- // location permission table, it means that we don't actually need
- // to do anything at all.
- if (needToCreateTables && !addToGearsLocationTable) {
- return;
- }
- // Try opening the Gears database.
- SQLiteDatabase permissions;
- try {
- permissions = SQLiteDatabase.openOrCreateDatabase(file, null);
- } catch (SQLiteException e) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Could not open Gears permission DB: "
- + e.getMessage());
- }
- // Just bail out.
- return;
- }
- // We now have a database open. Begin a transaction.
- permissions.beginTransaction();
- try {
- if (needToCreateTables) {
- // Create the tables. Note that this creates the
- // Gears tables for the permissions DB schema version 2.
- // The Gears schema upgrade process will take care of the rest.
- // First, the storage access table.
- SQLiteStatement statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_STORAGE_ACCESS_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Next the location access table.
- statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_LOCATION_ACCESS_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Finally, the schema version table.
- statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_SCHEMA_VERSION_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Set the schema version to 2.
- ContentValues schema = new ContentValues();
- schema.put("Name", "Version");
- schema.put("Value", 2);
- permissions.insert(GEARS_SCHEMA_VERSION_TABLE_NAME, null,
- schema);
- }
-
- if (addToGearsLocationTable) {
- ContentValues permissionValues = new ContentValues();
-
- for (String url : sGearsWhiteList) {
- permissionValues.put("Name", url);
- permissionValues.put("Value", GEARS_ALLOW_LOCATION_ACCESS);
- permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
- permissionValues);
- permissionValues.clear();
- }
- } else {
- for (String url : sGearsWhiteList) {
- permissions.delete(GEARS_LOCATION_ACCESS_TABLE_NAME, "Name=?",
- new String[] { url });
- }
- }
- // Commit the transaction.
- permissions.setTransactionSuccessful();
- } catch (SQLiteException e) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Could not set the Gears permissions: "
- + e.getMessage());
- }
- } finally {
- permissions.endTransaction();
- permissions.close();
- }
- }
-
- class SecureSettingsObserver extends ContentObserver {
- SecureSettingsObserver() {
- super(new Handler());
- }
-
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- checkGearsPermissions();
- }
- }
-}
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
new file mode 100755
index 0000000..d06d7e2
--- /dev/null
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -0,0 +1,202 @@
+/*
+ * 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;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.Set;
+
+
+/**
+ * Implements the Java side of GeolocationPermissions. Simply marshalls calls
+ * from the UI thread to the WebKit thread.
+ * @hide
+ */
+public final class GeolocationPermissions {
+ /**
+ * Callback interface used by the browser to report a Geolocation permission
+ * state set by the user in response to a permissions prompt.
+ */
+ public interface Callback {
+ public void invoke(String origin, boolean allow, boolean remember);
+ };
+
+ // Log tag
+ private static final String TAG = "geolocationPermissions";
+
+ // Global instance
+ private static GeolocationPermissions sInstance;
+
+ private Handler mHandler;
+
+ // Members used to transfer the origins and permissions between threads.
+ private Set<String> mOrigins;
+ private boolean mAllowed;
+ private static Lock mLock = new ReentrantLock();
+ private static boolean mUpdated;
+ private static Condition mUpdatedCondition = mLock.newCondition();
+
+ // Message ids
+ static final int GET_ORIGINS = 0;
+ static final int GET_ALLOWED = 1;
+ static final int CLEAR = 2;
+ static final int CLEAR_ALL = 3;
+
+ /**
+ * Gets the singleton instance of the class.
+ */
+ public static GeolocationPermissions getInstance() {
+ if (sInstance == null) {
+ sInstance = new GeolocationPermissions();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Creates the message handler. Must be called on the WebKit thread.
+ */
+ public void createHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // Runs on the WebKit thread.
+ switch (msg.what) {
+ case GET_ORIGINS:
+ getOriginsImpl();
+ break;
+ case GET_ALLOWED:
+ getAllowedImpl((String) msg.obj);
+ break;
+ case CLEAR:
+ nativeClear((String) msg.obj);
+ break;
+ case CLEAR_ALL:
+ nativeClearAll();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * Utility function to send a message to our handler.
+ */
+ private void postMessage(Message msg) {
+ assert(mHandler != null);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Gets the set of origins for which Geolocation permissions are stored.
+ * Note that we represent the origins as strings. These are created using
+ * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
+ * (Database, Geolocation etc) do so, it's safe to match up origins for the
+ * purposes of displaying UI.
+ */
+ public Set getOrigins() {
+ // Called on the UI thread.
+ Set origins = null;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ORIGINS));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ origins = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return origins;
+ }
+
+ /**
+ * Helper method to get the set of origins.
+ */
+ private void getOriginsImpl() {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mOrigins = nativeGetOrigins();
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Gets the permission state for the specified origin.
+ */
+ public boolean getAllowed(String origin) {
+ // Called on the UI thread.
+ boolean allowed = false;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ALLOWED, origin));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ allowed = mAllowed;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return allowed;
+ }
+
+ /**
+ * Helper method to get the permission state.
+ */
+ private void getAllowedImpl(String origin) {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mAllowed = nativeGetAllowed(origin);
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Clears the permission state for the specified origin.
+ */
+ public void clear(String origin) {
+ // Called on the UI thread.
+ postMessage(Message.obtain(null, CLEAR, origin));
+ }
+
+ /**
+ * Clears the permission state for all origins.
+ */
+ public void clearAll() {
+ // Called on the UI thread.
+ postMessage(Message.obtain(null, CLEAR_ALL));
+ }
+
+ // Native functions, run on the WebKit thread.
+ private static native Set nativeGetOrigins();
+ private static native boolean nativeGetAllowed(String origin);
+ private static native void nativeClear(String origin);
+ private static native void nativeClearAll();
+}
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
new file mode 100755
index 0000000..78b25ba
--- /dev/null
+++ b/core/java/android/webkit/GeolocationService.java
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+import android.app.ActivityThread;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewCore;
+
+
+/**
+ * Implements the Java side of GeolocationServiceAndroid.
+ * @hide Pending API council review.
+ */
+public final class GeolocationService implements LocationListener {
+
+ // Log tag
+ private static final String TAG = "geolocationService";
+
+ private long mNativeObject;
+ private LocationManager mLocationManager;
+ private boolean mIsGpsEnabled;
+ private boolean mIsRunning;
+ private boolean mIsNetworkProviderAvailable;
+ private boolean mIsGpsProviderAvailable;
+
+ /**
+ * Constructor
+ * @param nativeObject The native object to which this object will report position updates and
+ * errors.
+ */
+ public GeolocationService(long nativeObject) {
+ mNativeObject = nativeObject;
+ // Register newLocationAvailable with platform service.
+ ActivityThread thread = ActivityThread.systemMain();
+ Context context = thread.getApplication();
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ if (mLocationManager == null) {
+ Log.e(TAG, "Could not get location manager.");
+ }
+ }
+
+ /**
+ * Start listening for location updates.
+ */
+ public void start() {
+ registerForLocationUpdates();
+ mIsRunning = true;
+ }
+
+ /**
+ * Stop listening for location updates.
+ */
+ public void stop() {
+ unregisterFromLocationUpdates();
+ mIsRunning = false;
+ }
+
+ /**
+ * Sets whether to use the GPS.
+ * @param enable Whether to use the GPS.
+ */
+ public void setEnableGps(boolean enable) {
+ if (mIsGpsEnabled != enable) {
+ mIsGpsEnabled = enable;
+ if (mIsRunning) {
+ // There's no way to unregister from a single provider, so we can
+ // only unregister from all, then reregister with all but the GPS.
+ unregisterFromLocationUpdates();
+ registerForLocationUpdates();
+ }
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the location has changed.
+ * @param location The new location, as a Location object.
+ */
+ public void onLocationChanged(Location location) {
+ // Callbacks from the system location sevice are queued to this thread, so it's possible
+ // that we receive callbacks after unregistering. At this point, the native object will no
+ // longer exist.
+ if (mIsRunning) {
+ nativeNewLocationAvailable(mNativeObject, location);
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider status changes.
+ * @param provider The name of the provider.
+ * @param status The new status of the provider.
+ * @param extras an optional Bundle with provider specific data.
+ */
+ public void onStatusChanged(String providerName, int status, Bundle extras) {
+ boolean isAvailable = (status == LocationProvider.AVAILABLE);
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = isAvailable;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = isAvailable;
+ }
+ maybeReportError("The last location provider is no longer available");
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider is enabled.
+ * @param provider The name of the location provider that is now enabled.
+ */
+ public void onProviderEnabled(String providerName) {
+ // No need to notify the native side. It's enough to start sending
+ // valid position fixes again.
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = true;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = true;
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider is disabled.
+ * @param provider The name of the location provider that is now disabled.
+ */
+ public void onProviderDisabled(String providerName) {
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = false;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = false;
+ }
+ maybeReportError("The last location provider was disabled");
+ }
+
+ /**
+ * Registers this object with the location service.
+ */
+ private void registerForLocationUpdates() {
+ mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+ mIsNetworkProviderAvailable = true;
+ if (mIsGpsEnabled) {
+ mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+ mIsGpsProviderAvailable = true;
+ }
+ }
+
+ /**
+ * Unregisters this object from the location service.
+ */
+ private void unregisterFromLocationUpdates() {
+ mLocationManager.removeUpdates(this);
+ }
+
+ /**
+ * Reports an error if neither the network nor the GPS provider is available.
+ */
+ private void maybeReportError(String message) {
+ // Callbacks from the system location sevice are queued to this thread, so it's possible
+ // that we receive callbacks after unregistering. At this point, the native object will no
+ // longer exist.
+ if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) {
+ nativeNewErrorAvailable(mNativeObject, message);
+ }
+ }
+
+ // Native functions
+ private static native void nativeNewLocationAvailable(long nativeObject, Location location);
+ private static native void nativeNewErrorAvailable(long nativeObject, String message);
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
new file mode 100644
index 0000000..5a164f8
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -0,0 +1,232 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.ViewManager.ChildView;
+import android.widget.AbsoluteLayout;
+import android.widget.MediaController;
+import android.widget.VideoView;
+
+import java.util.HashMap;
+
+/**
+ * <p>Proxy for HTML5 video views.
+ */
+class HTML5VideoViewProxy extends Handler {
+ // Logging tag.
+ private static final String LOGTAG = "HTML5VideoViewProxy";
+
+ // Message Ids for WebCore thread -> UI thread communication.
+ private static final int INIT = 100;
+ private static final int PLAY = 101;
+
+ // The WebView instance that created this view.
+ private WebView mWebView;
+ // The ChildView instance used by the ViewManager.
+ private ChildView mChildView;
+ // The VideoView instance. Note that we could
+ // also access this via mChildView.mView but it would
+ // always require cast, so it is more convenient to store
+ // it here as well.
+ private HTML5VideoView mVideoView;
+
+ // A VideoView subclass that responds to double-tap
+ // events by going fullscreen.
+ class HTML5VideoView extends VideoView {
+ // Used to save the layout parameters if the view
+ // is changed to fullscreen.
+ private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
+ // Flag that denotes whether the view is fullscreen or not.
+ private boolean mIsFullscreen;
+ // Used to save the current playback position when
+ // transitioning to/from fullscreen.
+ private int mPlaybackPosition;
+ // The callback object passed to the host application. This callback
+ // is invoked when the host application dismisses our VideoView
+ // (e.g. the user presses the back key).
+ private WebChromeClient.CustomViewCallback mCallback =
+ new WebChromeClient.CustomViewCallback() {
+ public void onCustomViewHidden() {
+ playEmbedded();
+ }
+ };
+
+ // The OnPreparedListener, used to automatically resume
+ // playback when transitioning to/from fullscreen.
+ private MediaPlayer.OnPreparedListener mPreparedListener =
+ new MediaPlayer.OnPreparedListener() {
+ public void onPrepared(MediaPlayer mp) {
+ resumePlayback();
+ }
+ };
+
+ HTML5VideoView(Context context) {
+ super(context);
+ }
+
+ void savePlaybackPosition() {
+ if (isPlaying()) {
+ mPlaybackPosition = getCurrentPosition();
+ }
+ }
+
+ void resumePlayback() {
+ seekTo(mPlaybackPosition);
+ start();
+ setOnPreparedListener(null);
+ }
+
+ void playEmbedded() {
+ // Attach to the WebView.
+ mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
+ // Make sure we're visible
+ setVisibility(View.VISIBLE);
+ // Set the onPrepared listener so we start
+ // playing when the video view is reattached
+ // and its surface is recreated.
+ setOnPreparedListener(mPreparedListener);
+ mIsFullscreen = false;
+ }
+
+ void playFullScreen() {
+ WebChromeClient client = mWebView.getWebChromeClient();
+ if (client == null) {
+ return;
+ }
+ // Save the current layout params.
+ mEmbeddedLayoutParams =
+ (AbsoluteLayout.LayoutParams) getLayoutParams();
+ // Detach from the WebView.
+ mChildView.removeViewOnUIThread();
+ // Attach to the browser UI.
+ client.onShowCustomView(this, mCallback);
+ // Set the onPrepared listener so we start
+ // playing when after the video view is reattached
+ // and its surface is recreated.
+ setOnPreparedListener(mPreparedListener);
+ mIsFullscreen = true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // TODO: implement properly (i.e. detect double tap)
+ if (mIsFullscreen || !isPlaying()) {
+ return super.onTouchEvent(ev);
+ }
+ playFullScreen();
+ return true;
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ savePlaybackPosition();
+ }
+ }
+
+ /**
+ * Private constructor.
+ * @param context is the application context.
+ */
+ private HTML5VideoViewProxy(WebView webView) {
+ // This handler is for the main (UI) thread.
+ super(Looper.getMainLooper());
+ // Save the WebView object.
+ mWebView = webView;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ // This executes on the UI thread.
+ switch (msg.what) {
+ case INIT:
+ // Create the video view and set a default controller.
+ mVideoView = new HTML5VideoView(mWebView.getContext());
+ // This is needed because otherwise there will be a black square
+ // stuck on the screen.
+ mVideoView.setWillNotDraw(false);
+ mVideoView.setMediaController(new MediaController(mWebView.getContext()));
+ mChildView.mView = mVideoView;
+ break;
+ case PLAY:
+ if (mVideoView == null) {
+ return;
+ }
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String url = (String) map.get("url");
+ mVideoView.setVideoURI(Uri.parse(url));
+ mVideoView.start();
+ break;
+ }
+ }
+
+ /**
+ * Play a video stream.
+ * @param url is the URL of the video stream.
+ * @param webview is the WebViewCore that is requesting the playback.
+ */
+ public void play(String url) {
+ // We need to know the webview that is requesting the playback.
+ Message message = obtainMessage(PLAY);
+ HashMap<String, Object> map = new HashMap();
+ map.put("url", url);
+ message.obj = map;
+ sendMessage(message);
+ }
+
+ public void createView() {
+ mChildView = mWebView.mViewManager.createView();
+ sendMessage(obtainMessage(INIT));
+ }
+
+ public void attachView(int x, int y, int width, int height) {
+ if (mChildView == null) {
+ return;
+ }
+ mChildView.attachView(x, y, width, height);
+ }
+
+ public void removeView() {
+ if (mChildView == null) {
+ return;
+ }
+ mChildView.removeView();
+ }
+
+ /**
+ * The factory for HTML5VideoViewProxy instances.
+ * @param webViewCore is the WebViewCore that is requesting the proxy.
+ *
+ * @return a new HTML5VideoViewProxy object.
+ */
+ public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore) {
+ return new HTML5VideoViewProxy(webViewCore.getWebView());
+ }
+}
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 84dc9f0..1c17575 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -49,8 +49,8 @@
// Message id for handling the user response
- private final int AUTH_PROCEED = 100;
- private final int AUTH_CANCEL = 200;
+ private static final int AUTH_PROCEED = 100;
+ private static final int AUTH_CANCEL = 200;
/**
* Creates a new HTTP authentication handler with an empty
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index c6ec2d2..00b2731 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -23,7 +23,8 @@
import java.util.regex.Pattern;
-class HttpDateTime {
+/** {@hide} */
+public final class HttpDateTime {
/*
* Regular expression for parsing HTTP-date.
@@ -47,14 +48,16 @@
* Wdy, DD Mon YYYY HH:MM:SS
* Wdy Mon (SP)D HH:MM:SS YYYY
* Wdy Mon DD HH:MM:SS YYYY GMT
+ *
+ * HH can be H if the first digit is zero.
*/
private static final String HTTP_DATE_RFC_REGEXP =
"([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])";
+ + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
private static final String HTTP_DATE_ANSIC_REGEXP =
"[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
+ + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
/**
* The compiled version of the HTTP-date regular expressions.
@@ -65,6 +68,12 @@
Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
private static class TimeOfDay {
+ TimeOfDay(int h, int m, int s) {
+ this.hour = h;
+ this.minute = m;
+ this.second = s;
+ }
+
int hour;
int minute;
int second;
@@ -76,7 +85,7 @@
int date = 1;
int month = Calendar.JANUARY;
int year = 1970;
- TimeOfDay timeOfDay = new TimeOfDay();
+ TimeOfDay timeOfDay;
Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
if (rfcMatcher.find()) {
@@ -183,13 +192,22 @@
}
private static TimeOfDay getTime(String timeString) {
- TimeOfDay time = new TimeOfDay();
- time.hour = (timeString.charAt(0) - '0') * 10
- + (timeString.charAt(1) - '0');
- time.minute = (timeString.charAt(3) - '0') * 10
- + (timeString.charAt(4) - '0');
- time.second = (timeString.charAt(6) - '0') * 10
- + (timeString.charAt(7) - '0');
- return time;
+ // HH might be H
+ int i = 0;
+ int hour = timeString.charAt(i++) - '0';
+ if (timeString.charAt(i) != ':')
+ hour = hour * 10 + (timeString.charAt(i++) - '0');
+ // Skip ':'
+ i++;
+
+ int minute = (timeString.charAt(i++) - '0') * 10
+ + (timeString.charAt(i++) - '0');
+ // Skip ':'
+ i++;
+
+ int second = (timeString.charAt(i++) - '0') * 10
+ + (timeString.charAt(i++) - '0');
+
+ return new TimeOfDay(hour, minute, second);
}
}
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 1dbd007..21bcdf17 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -34,9 +34,16 @@
// Instant timer is used to implement a timer that needs to fire almost
// immediately.
private boolean mHasInstantTimer;
+
// Reference count the pause/resume of timers
private int mPauseTimerRefCount;
+ private boolean mTimerPaused;
+ private boolean mHasDeferredTimers;
+
+ /* package */
+ static final int REFRESH_PLUGINS = 100;
+
/**
* Construct a new JWebCoreJavaBridge to interface with
* WebCore timers and cookies.
@@ -51,6 +58,17 @@
}
/**
+ * Call native timer callbacks.
+ */
+ private void fireSharedTimer() {
+ PerfChecker checker = new PerfChecker();
+ // clear the flag so that sharedTimerFired() can set a new timer
+ mHasInstantTimer = false;
+ sharedTimerFired();
+ checker.responseAlert("sharedTimer");
+ }
+
+ /**
* handleMessage
* @param msg The dispatched message.
*
@@ -60,16 +78,21 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case TIMER_MESSAGE: {
- PerfChecker checker = new PerfChecker();
- // clear the flag so that sharedTimerFired() can set a new timer
- mHasInstantTimer = false;
- sharedTimerFired();
- checker.responseAlert("sharedTimer");
+ if (mTimerPaused) {
+ mHasDeferredTimers = true;
+ } else {
+ fireSharedTimer();
+ }
break;
}
case FUNCPTR_MESSAGE:
nativeServiceFuncPtrQueue();
break;
+ case REFRESH_PLUGINS:
+ nativeUpdatePluginDirectories(PluginManager.getInstance(null)
+ .getPluginDirecoties(), ((Boolean) msg.obj)
+ .booleanValue());
+ break;
}
}
@@ -86,7 +109,8 @@
*/
public void pause() {
if (--mPauseTimerRefCount == 0) {
- setDeferringTimers(true);
+ mTimerPaused = true;
+ mHasDeferredTimers = false;
}
}
@@ -95,7 +119,11 @@
*/
public void resume() {
if (++mPauseTimerRefCount == 1) {
- setDeferringTimers(false);
+ mTimerPaused = false;
+ if (mHasDeferredTimers) {
+ mHasDeferredTimers = false;
+ fireSharedTimer();
+ }
}
}
@@ -108,10 +136,9 @@
/**
* Store a cookie string associated with a url.
* @param url The url to be used as a key for the cookie.
- * @param docUrl The policy base url used by WebCore.
* @param value The cookie string to be stored.
*/
- private void setCookies(String url, String docUrl, String value) {
+ private void setCookies(String url, String value) {
if (value.contains("\r") || value.contains("\n")) {
// for security reason, filter out '\r' and '\n' from the cookie
int size = value.length();
@@ -152,11 +179,25 @@
}
/**
+ * Returns an array of plugin directoies
+ */
+ private String[] getPluginDirectories() {
+ return PluginManager.getInstance(null).getPluginDirecoties();
+ }
+
+ /**
+ * Returns the path of the plugin data directory
+ */
+ private String getPluginSharedDataDirectory() {
+ return PluginManager.getInstance(null).getPluginSharedDataDirectory();
+ }
+
+ /**
* setSharedTimer
* @param timemillis The relative time when the timer should fire
*/
private void setSharedTimer(long timemillis) {
- if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "setSharedTimer " + timemillis);
+ if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) Log.v(LOGTAG, "setSharedTimer " + timemillis);
if (timemillis <= 0) {
// we don't accumulate the sharedTimer unless it is a delayed
@@ -180,11 +221,12 @@
* Stop the shared timer.
*/
private void stopSharedTimer() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) {
Log.v(LOGTAG, "stopSharedTimer removing all timers");
}
removeMessages(TIMER_MESSAGE);
mHasInstantTimer = false;
+ mHasDeferredTimers = false;
}
private String[] getKeyStrengthList() {
@@ -199,6 +241,7 @@
private native void nativeConstructor();
private native void nativeFinalize();
private native void sharedTimerFired();
- private native void setDeferringTimers(boolean defer);
+ private native void nativeUpdatePluginDirectories(String[] directories,
+ boolean reload);
public native void setNetworkOnLine(boolean online);
}
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index c3f3594..7fff014 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -43,8 +43,6 @@
import java.util.regex.Pattern;
import java.util.regex.Matcher;
-import org.apache.commons.codec.binary.Base64;
-
class LoadListener extends Handler implements EventHandler {
private static final String LOGTAG = "webkit";
@@ -113,7 +111,6 @@
private String mMethod;
private Map<String, String> mRequestHeaders;
private byte[] mPostData;
- private boolean mIsHighPriority;
// Flag to indicate that this load is synchronous.
private boolean mSynchronous;
private Vector<Message> mMessageQueue;
@@ -142,15 +139,13 @@
LoadListener(Context context, BrowserFrame frame, String url,
int nativeLoader, boolean synchronous, boolean isMainPageLoader) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener constructor url=" + url);
}
mContext = context;
mBrowserFrame = frame;
setUrl(url);
mNativeLoader = nativeLoader;
- mMimeType = "";
- mEncoding = "";
mSynchronous = synchronous;
if (synchronous) {
mMessageQueue = new Vector<Message>();
@@ -293,7 +288,7 @@
* directly
*/
public void headers(Headers headers) {
- if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "LoadListener.headers");
+ if (DebugFlags.LOAD_LISTENER) Log.v(LOGTAG, "LoadListener.headers");
sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
}
@@ -301,8 +296,6 @@
private void handleHeaders(Headers headers) {
if (mCancelled) return;
mHeaders = headers;
- mMimeType = "";
- mEncoding = "";
ArrayList<String> cookies = headers.getSetCookie();
for (int i = 0; i < cookies.size(); ++i) {
@@ -322,8 +315,8 @@
// If we have one of "generic" MIME types, try to deduce
// the right MIME type from the file extension (if any):
- if (mMimeType.equalsIgnoreCase("text/plain") ||
- mMimeType.equalsIgnoreCase("application/octet-stream")) {
+ if (mMimeType.equals("text/plain") ||
+ mMimeType.equals("application/octet-stream")) {
// for attachment, use the filename in the Content-Disposition
// to guess the mimetype
@@ -339,17 +332,14 @@
if (newMimeType != null) {
mMimeType = newMimeType;
}
- } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
+ } else if (mMimeType.equals("text/vnd.wap.wml")) {
// As we don't support wml, render it as plain text
mMimeType = "text/plain";
} else {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
// It seems that xhtml+xml and vnd.wap.xhtml+xml mime
// subtypes are used interchangeably. So treat them the same.
- if (mMimeType.equalsIgnoreCase("application/xhtml+xml") ||
- mMimeType.equals("application/vnd.wap.xhtml+xml")) {
- mMimeType = "text/html";
+ if (mMimeType.equals("application/vnd.wap.xhtml+xml")) {
+ mMimeType = "application/xhtml+xml";
}
}
} else {
@@ -450,7 +440,7 @@
*/
public void status(int majorVersion, int minorVersion,
int code, /* Status-Code value */ String reasonPhrase) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener: from: " + mUrl
+ " major: " + majorVersion
+ " minor: " + minorVersion
@@ -464,6 +454,9 @@
status.put("reason", reasonPhrase);
// New status means new data. Clear the old.
mDataBuilder.clear();
+ mMimeType = "";
+ mEncoding = "";
+ mTransferEncoding = "";
sendMessageInternal(obtainMessage(MSG_STATUS, status));
}
@@ -507,7 +500,7 @@
* directly
*/
public void error(int id, String description) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.error url:" +
url() + " id:" + id + " description:" + description);
}
@@ -535,23 +528,10 @@
* mDataBuilder is a thread-safe structure.
*/
public void data(byte[] data, int length) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.data(): url: " + url());
}
- // Decode base64 data
- // Note: It's fine that we only decode base64 here and not in the other
- // data call because the only caller of the stream version is not
- // base64 encoded.
- if ("base64".equalsIgnoreCase(mTransferEncoding)) {
- if (length < data.length) {
- byte[] trimmedData = new byte[length];
- System.arraycopy(data, 0, trimmedData, 0, length);
- data = trimmedData;
- }
- data = Base64.decodeBase64(data);
- length = data.length;
- }
// Synchronize on mData because commitLoad may write mData to WebCore
// and we don't want to replace mData or mDataLength at the same time
// as a write.
@@ -573,7 +553,7 @@
* directly
*/
public void endData() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
}
sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
@@ -626,7 +606,7 @@
// before calling it.
if (mCacheLoader != null) {
mCacheLoader.load();
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener cache load url=" + url());
}
return;
@@ -676,7 +656,7 @@
CacheManager.HEADER_KEY_IFNONEMATCH) &&
!headers.containsKey(
CacheManager.HEADER_KEY_IFMODIFIEDSINCE)) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "FrameLoader: HTTP URL in cache " +
"and usable: " + url());
}
@@ -695,7 +675,7 @@
* directly
*/
public boolean handleSslErrorRequest(SslError error) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG,
"LoadListener.handleSslErrorRequest(): url:" + url() +
" primary error: " + error.getPrimaryError() +
@@ -773,7 +753,7 @@
* are null, cancel the request.
*/
void handleAuthResponse(String username, String password) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.handleAuthResponse: url: " + mUrl
+ " username: " + username
+ " password: " + password);
@@ -823,14 +803,12 @@
* @param method
* @param headers
* @param postData
- * @param isHighPriority
*/
void setRequestData(String method, Map<String, String> headers,
- byte[] postData, boolean isHighPriority) {
+ byte[] postData) {
mMethod = method;
mRequestHeaders = headers;
mPostData = postData;
- mIsHighPriority = isHighPriority;
}
/**
@@ -870,7 +848,7 @@
}
void attachRequestHandle(RequestHandle requestHandle) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.attachRequestHandle(): " +
"requestHandle: " + requestHandle);
}
@@ -878,7 +856,7 @@
}
void detachRequestHandle() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.detachRequestHandle(): " +
"requestHandle: " + mRequestHandle);
}
@@ -917,7 +895,7 @@
*/
static boolean willLoadFromCache(String url) {
boolean inCache = CacheManager.getCacheFile(url, null) != null;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "willLoadFromCache: " + url + " in cache: " +
inCache);
}
@@ -938,6 +916,10 @@
return mMimeType;
}
+ String transferEncoding() {
+ return mTransferEncoding;
+ }
+
/*
* Return the size of the content being downloaded. This represents the
* full content size, even under the situation where the download has been
@@ -992,8 +974,7 @@
// pass content-type content-length and content-encoding
final int nativeResponse = nativeCreateResponse(
mUrl, statusCode, mStatusText,
- mMimeType, mContentLength, mEncoding,
- mCacheResult == null ? 0 : mCacheResult.expires / 1000);
+ mMimeType, mContentLength, mEncoding);
if (mHeaders != null) {
mHeaders.getHeaders(new Headers.HeaderCallback() {
public void header(String name, String value) {
@@ -1115,7 +1096,7 @@
* EventHandler's method call.
*/
public void cancel() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
if (mRequestHandle == null) {
Log.v(LOGTAG, "LoadListener.cancel(): no requestHandle");
} else {
@@ -1221,7 +1202,7 @@
// Network.requestURL.
Network network = Network.getInstance(getContext());
if (!network.requestURL(mMethod, mRequestHeaders,
- mPostData, this, mIsHighPriority)) {
+ mPostData, this)) {
// Signal a bad url error if we could not load the
// redirection.
handleError(EventHandler.ERROR_BAD_URL,
@@ -1247,7 +1228,7 @@
tearDown();
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " +
redirectTo);
}
@@ -1260,8 +1241,8 @@
private static final Pattern CONTENT_TYPE_PATTERN =
Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
- private void parseContentTypeHeader(String contentType) {
- if (WebView.LOGV_ENABLED) {
+ /* package */ void parseContentTypeHeader(String contentType) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
"contentType: " + contentType);
}
@@ -1282,13 +1263,14 @@
mEncoding = contentType.substring(i + 1);
}
// Trim excess whitespace.
- mEncoding = mEncoding.trim();
+ mEncoding = mEncoding.trim().toLowerCase();
if (i < contentType.length() - 1) {
// for data: uri the mimeType and encoding have
// the form image/jpeg;base64 or text/plain;charset=utf-8
// or text/html;charset=utf-8;base64
- mTransferEncoding = contentType.substring(i + 1).trim();
+ mTransferEncoding =
+ contentType.substring(i + 1).trim().toLowerCase();
}
} else {
mMimeType = contentType;
@@ -1308,6 +1290,8 @@
guessMimeType();
}
}
+ // Ensure mMimeType is lower case.
+ mMimeType = mMimeType.toLowerCase();
}
/**
@@ -1397,7 +1381,8 @@
*/
private boolean ignoreCallbacks() {
return (mCancelled || mAuthHeader != null ||
- (mStatusCode > 300 && mStatusCode < 400));
+ // Allow 305 (Use Proxy) to call through.
+ (mStatusCode > 300 && mStatusCode < 400 && mStatusCode != 305));
}
/**
@@ -1438,7 +1423,7 @@
mMimeType = "text/html";
String newMimeType = guessMimeTypeFromExtension(mUrl);
if (newMimeType != null) {
- mMimeType = newMimeType;
+ mMimeType = newMimeType;
}
}
}
@@ -1448,23 +1433,12 @@
*/
private String guessMimeTypeFromExtension(String url) {
// PENDING: need to normalize url
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "guessMimeTypeFromExtension: url = " + url);
}
- String mimeType =
- MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(url));
-
- if (mimeType != null) {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
- if (mimeType.equals("application/xhtml+xml")) {
- mimeType = "text/html";
- }
- }
-
- return mimeType;
+ return MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ MimeTypeMap.getFileExtensionFromUrl(url));
}
/**
@@ -1483,7 +1457,7 @@
* Cycle through our messages for synchronous loads.
*/
/* package */ void loadSynchronousMessages() {
- if (WebView.DEBUG && !mSynchronous) {
+ if (DebugFlags.LOAD_LISTENER && !mSynchronous) {
throw new AssertionError();
}
// Note: this can be called twice if it is a synchronous network load,
@@ -1510,12 +1484,11 @@
* @param expectedLength An estimate of the content length or the length
* given by the server.
* @param encoding HTTP encoding.
- * @param expireTime HTTP expires converted to seconds since the epoch.
* @return The native response pointer.
*/
private native int nativeCreateResponse(String url, int statusCode,
String statusText, String mimeType, long expectedLength,
- String encoding, long expireTime);
+ String encoding);
/**
* Add a response header to the native object.
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 9fdde61..a55dbc8 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -22,7 +22,7 @@
/**
* Two-way map that maps MIME-types to file extensions and vice versa.
*/
-public /* package */ class MimeTypeMap {
+public class MimeTypeMap {
/**
* Singleton MIME-type map instance:
@@ -39,7 +39,6 @@
*/
private HashMap<String, String> mExtensionToMimeTypeMap;
-
/**
* Creates a new MIME-type map.
*/
@@ -50,7 +49,10 @@
/**
* Returns the file extension or an empty string iff there is no
- * extension.
+ * extension. This method is a convenience method for obtaining the
+ * extension of a url and has undefined results for other Strings.
+ * @param url
+ * @return The file extension of the given url.
*/
public static String getFileExtensionFromUrl(String url) {
if (url != null && url.length() > 0) {
@@ -80,8 +82,7 @@
* Load an entry into the map. This does not check if the item already
* exists, it trusts the caller!
*/
- private void loadEntry(String mimeType, String extension,
- boolean textType) {
+ private void loadEntry(String mimeType, String extension) {
//
// if we have an existing x --> y mapping, we do not want to
// override it with another mapping x --> ?
@@ -94,18 +95,12 @@
mMimeTypeToExtensionMap.put(mimeType, extension);
}
- //
- // here, we don't want to map extensions to text MIME types;
- // otherwise, we will start replacing generic text/plain and
- // text/html with text MIME types that our platform does not
- // understand.
- //
- if (!textType) {
- mExtensionToMimeTypeMap.put(extension, mimeType);
- }
+ mExtensionToMimeTypeMap.put(extension, mimeType);
}
/**
+ * Return true if the given MIME type has an entry in the map.
+ * @param mimeType A MIME type (i.e. text/plain)
* @return True iff there is a mimeType entry in the map.
*/
public boolean hasMimeType(String mimeType) {
@@ -117,7 +112,9 @@
}
/**
- * @return The extension for the MIME type or null iff there is none.
+ * Return the MIME type for the given extension.
+ * @param extension A file extension without the leading '.'
+ * @return The MIME type for the given extension or null iff there is none.
*/
public String getMimeTypeFromExtension(String extension) {
if (extension != null && extension.length() > 0) {
@@ -128,18 +125,23 @@
}
/**
+ * Return true if the given extension has a registered MIME type.
+ * @param extension A file extension without the leading '.'
* @return True iff there is an extension entry in the map.
*/
public boolean hasExtension(String extension) {
if (extension != null && extension.length() > 0) {
return mExtensionToMimeTypeMap.containsKey(extension);
}
-
return false;
}
/**
- * @return The MIME type for the extension or null iff there is none.
+ * Return the registered extension for the given MIME type. Note that some
+ * MIME types map to multiple extensions. This call will return the most
+ * common extension for the given MIME type.
+ * @param mimeType A MIME type (i.e. text/plain)
+ * @return The extension for the given MIME type or null iff there is none.
*/
public String getExtensionFromMimeType(String mimeType) {
if (mimeType != null && mimeType.length() > 0) {
@@ -150,6 +152,7 @@
}
/**
+ * Get the singleton instance of MimeTypeMap.
* @return The singleton instance of the MIME-type map.
*/
public static MimeTypeMap getSingleton() {
@@ -164,341 +167,312 @@
// mail.google.com/a/google.com
//
// and "active" MIME types (due to potential security issues).
- //
- // Also, notice that not all data from this table is actually
- // added (see loadEntry method for more details).
- sMimeTypeMap.loadEntry("application/andrew-inset", "ez", false);
- sMimeTypeMap.loadEntry("application/dsptype", "tsp", false);
- sMimeTypeMap.loadEntry("application/futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/hta", "hta", false);
- sMimeTypeMap.loadEntry("application/mac-binhex40", "hqx", false);
- sMimeTypeMap.loadEntry("application/mac-compactpro", "cpt", false);
- sMimeTypeMap.loadEntry("application/mathematica", "nb", false);
- sMimeTypeMap.loadEntry("application/msaccess", "mdb", false);
- sMimeTypeMap.loadEntry("application/oda", "oda", false);
- sMimeTypeMap.loadEntry("application/ogg", "ogg", false);
- sMimeTypeMap.loadEntry("application/pdf", "pdf", false);
- sMimeTypeMap.loadEntry("application/pgp-keys", "key", false);
- sMimeTypeMap.loadEntry("application/pgp-signature", "pgp", false);
- sMimeTypeMap.loadEntry("application/pics-rules", "prf", false);
- sMimeTypeMap.loadEntry("application/rar", "rar", false);
- sMimeTypeMap.loadEntry("application/rdf+xml", "rdf", false);
- sMimeTypeMap.loadEntry("application/rss+xml", "rss", false);
- sMimeTypeMap.loadEntry("application/zip", "zip", false);
+ sMimeTypeMap.loadEntry("application/andrew-inset", "ez");
+ sMimeTypeMap.loadEntry("application/dsptype", "tsp");
+ sMimeTypeMap.loadEntry("application/futuresplash", "spl");
+ sMimeTypeMap.loadEntry("application/hta", "hta");
+ sMimeTypeMap.loadEntry("application/mac-binhex40", "hqx");
+ sMimeTypeMap.loadEntry("application/mac-compactpro", "cpt");
+ sMimeTypeMap.loadEntry("application/mathematica", "nb");
+ sMimeTypeMap.loadEntry("application/msaccess", "mdb");
+ sMimeTypeMap.loadEntry("application/oda", "oda");
+ sMimeTypeMap.loadEntry("application/ogg", "ogg");
+ sMimeTypeMap.loadEntry("application/pdf", "pdf");
+ sMimeTypeMap.loadEntry("application/pgp-keys", "key");
+ sMimeTypeMap.loadEntry("application/pgp-signature", "pgp");
+ sMimeTypeMap.loadEntry("application/pics-rules", "prf");
+ sMimeTypeMap.loadEntry("application/rar", "rar");
+ sMimeTypeMap.loadEntry("application/rdf+xml", "rdf");
+ sMimeTypeMap.loadEntry("application/rss+xml", "rss");
+ sMimeTypeMap.loadEntry("application/zip", "zip");
sMimeTypeMap.loadEntry("application/vnd.android.package-archive",
- "apk", false);
- sMimeTypeMap.loadEntry("application/vnd.cinderella", "cdy", false);
- sMimeTypeMap.loadEntry("application/vnd.ms-pki.stl", "stl", false);
+ "apk");
+ sMimeTypeMap.loadEntry("application/vnd.cinderella", "cdy");
+ sMimeTypeMap.loadEntry("application/vnd.ms-pki.stl", "stl");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.database", "odb",
- false);
+ "application/vnd.oasis.opendocument.database", "odb");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.formula", "odf",
- false);
+ "application/vnd.oasis.opendocument.formula", "odf");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.graphics", "odg",
- false);
+ "application/vnd.oasis.opendocument.graphics", "odg");
sMimeTypeMap.loadEntry(
"application/vnd.oasis.opendocument.graphics-template",
- "otg", false);
+ "otg");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.image", "odi", false);
+ "application/vnd.oasis.opendocument.image", "odi");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.spreadsheet", "ods",
- false);
+ "application/vnd.oasis.opendocument.spreadsheet", "ods");
sMimeTypeMap.loadEntry(
"application/vnd.oasis.opendocument.spreadsheet-template",
- "ots", false);
+ "ots");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text", "odt", false);
+ "application/vnd.oasis.opendocument.text", "odt");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-master", "odm",
- false);
+ "application/vnd.oasis.opendocument.text-master", "odm");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-template", "ott",
- false);
+ "application/vnd.oasis.opendocument.text-template", "ott");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-web", "oth",
- false);
- sMimeTypeMap.loadEntry("application/vnd.rim.cod", "cod", false);
- sMimeTypeMap.loadEntry("application/vnd.smaf", "mmf", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.calc", "sdc",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.draw", "sda",
- false);
+ "application/vnd.oasis.opendocument.text-web", "oth");
+ sMimeTypeMap.loadEntry("application/vnd.rim.cod", "cod");
+ sMimeTypeMap.loadEntry("application/vnd.smaf", "mmf");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.calc", "sdc");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.draw", "sda");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdd", false);
+ "application/vnd.stardivision.impress", "sdd");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdp", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.math", "smf",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "sdw",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "vor",
- false);
+ "application/vnd.stardivision.impress", "sdp");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.math", "smf");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.writer",
+ "sdw");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.writer",
+ "vor");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.writer-global", "sgl", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.calc", "sxc",
- false);
+ "application/vnd.stardivision.writer-global", "sgl");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.calc", "sxc");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.calc.template", "stc", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.draw", "sxd",
- false);
+ "application/vnd.sun.xml.calc.template", "stc");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.draw", "sxd");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.draw.template", "std", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.impress", "sxi",
- false);
+ "application/vnd.sun.xml.draw.template", "std");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.impress", "sxi");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.impress.template", "sti", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.math", "sxm",
- false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.writer", "sxw",
- false);
+ "application/vnd.sun.xml.impress.template", "sti");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.math", "sxm");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.writer", "sxw");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.global", "sxg", false);
+ "application/vnd.sun.xml.writer.global", "sxg");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.template", "stw", false);
- sMimeTypeMap.loadEntry("application/vnd.visio", "vsd", false);
- sMimeTypeMap.loadEntry("application/x-abiword", "abw", false);
- sMimeTypeMap.loadEntry("application/x-apple-diskimage", "dmg",
- false);
- sMimeTypeMap.loadEntry("application/x-bcpio", "bcpio", false);
- sMimeTypeMap.loadEntry("application/x-bittorrent", "torrent",
- false);
- sMimeTypeMap.loadEntry("application/x-cdf", "cdf", false);
- sMimeTypeMap.loadEntry("application/x-cdlink", "vcd", false);
- sMimeTypeMap.loadEntry("application/x-chess-pgn", "pgn", false);
- sMimeTypeMap.loadEntry("application/x-cpio", "cpio", false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "deb",
- false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "udeb",
- false);
- sMimeTypeMap.loadEntry("application/x-director", "dcr", false);
- sMimeTypeMap.loadEntry("application/x-director", "dir", false);
- sMimeTypeMap.loadEntry("application/x-director", "dxr", false);
- sMimeTypeMap.loadEntry("application/x-dms", "dms", false);
- sMimeTypeMap.loadEntry("application/x-doom", "wad", false);
- sMimeTypeMap.loadEntry("application/x-dvi", "dvi", false);
- sMimeTypeMap.loadEntry("application/x-flac", "flac", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfa", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfb", false);
- sMimeTypeMap.loadEntry("application/x-font", "gsf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf.Z", false);
- sMimeTypeMap.loadEntry("application/x-freemind", "mm", false);
- sMimeTypeMap.loadEntry("application/x-futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/x-gnumeric", "gnumeric", false);
- sMimeTypeMap.loadEntry("application/x-go-sgf", "sgf", false);
- sMimeTypeMap.loadEntry("application/x-graphing-calculator", "gcf",
- false);
- sMimeTypeMap.loadEntry("application/x-gtar", "gtar", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "tgz", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "taz", false);
- sMimeTypeMap.loadEntry("application/x-hdf", "hdf", false);
- sMimeTypeMap.loadEntry("application/x-ica", "ica", false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "ins",
- false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "isp",
- false);
- sMimeTypeMap.loadEntry("application/x-iphone", "iii", false);
- sMimeTypeMap.loadEntry("application/x-iso9660-image", "iso", false);
- sMimeTypeMap.loadEntry("application/x-jmol", "jmz", false);
- sMimeTypeMap.loadEntry("application/x-kchart", "chrt", false);
- sMimeTypeMap.loadEntry("application/x-killustrator", "kil", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skp", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skd", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skt", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skm", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpr", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpt", false);
- sMimeTypeMap.loadEntry("application/x-kspread", "ksp", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwd", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwt", false);
- sMimeTypeMap.loadEntry("application/x-latex", "latex", false);
- sMimeTypeMap.loadEntry("application/x-lha", "lha", false);
- sMimeTypeMap.loadEntry("application/x-lzh", "lzh", false);
- sMimeTypeMap.loadEntry("application/x-lzx", "lzx", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frm", false);
- sMimeTypeMap.loadEntry("application/x-maker", "maker", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frame", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fb", false);
- sMimeTypeMap.loadEntry("application/x-maker", "book", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fbdoc", false);
- sMimeTypeMap.loadEntry("application/x-mif", "mif", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmd", "wmd", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmz", "wmz", false);
- sMimeTypeMap.loadEntry("application/x-msi", "msi", false);
- sMimeTypeMap.loadEntry("application/x-ns-proxy-autoconfig", "pac",
- false);
- sMimeTypeMap.loadEntry("application/x-nwc", "nwc", false);
- sMimeTypeMap.loadEntry("application/x-object", "o", false);
- sMimeTypeMap.loadEntry("application/x-oz-application", "oza",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs12", "p12", false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl", false);
- sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl",
- false);
- sMimeTypeMap.loadEntry("application/x-shar", "shar", false);
- sMimeTypeMap.loadEntry("application/x-stuffit", "sit", false);
- sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio", false);
- sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc", false);
- sMimeTypeMap.loadEntry("application/x-tar", "tar", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texinfo", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texi", false);
- sMimeTypeMap.loadEntry("application/x-troff", "t", false);
- sMimeTypeMap.loadEntry("application/x-troff", "roff", false);
- sMimeTypeMap.loadEntry("application/x-troff-man", "man", false);
- sMimeTypeMap.loadEntry("application/x-ustar", "ustar", false);
- sMimeTypeMap.loadEntry("application/x-wais-source", "src", false);
- sMimeTypeMap.loadEntry("application/x-wingz", "wz", false);
- sMimeTypeMap.loadEntry(
- "application/x-webarchive", "webarchive", false); // added
- sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false);
- sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt", false);
- sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false);
- sMimeTypeMap.loadEntry("application/x-xfig", "fig", false);
- sMimeTypeMap.loadEntry("audio/basic", "snd", false);
- sMimeTypeMap.loadEntry("audio/midi", "mid", false);
- sMimeTypeMap.loadEntry("audio/midi", "midi", false);
- sMimeTypeMap.loadEntry("audio/midi", "kar", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpga", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpega", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp2", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp3", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "m4a", false);
- sMimeTypeMap.loadEntry("audio/mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/prs.sid", "sid", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aif", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aiff", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aifc", false);
- sMimeTypeMap.loadEntry("audio/x-gsm", "gsm", false);
- sMimeTypeMap.loadEntry("audio/x-mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wma", "wma", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wax", "wax", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "rm", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ram", false);
- sMimeTypeMap.loadEntry("audio/x-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-scpls", "pls", false);
- sMimeTypeMap.loadEntry("audio/x-sd2", "sd2", false);
- sMimeTypeMap.loadEntry("audio/x-wav", "wav", false);
- sMimeTypeMap.loadEntry("image/bmp", "bmp", false); // added
- sMimeTypeMap.loadEntry("image/gif", "gif", false);
- sMimeTypeMap.loadEntry("image/ico", "cur", false); // added
- sMimeTypeMap.loadEntry("image/ico", "ico", false); // added
- sMimeTypeMap.loadEntry("image/ief", "ief", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpeg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpe", false);
- sMimeTypeMap.loadEntry("image/pcx", "pcx", false);
- sMimeTypeMap.loadEntry("image/png", "png", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svg", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svgz", false);
- sMimeTypeMap.loadEntry("image/tiff", "tiff", false);
- sMimeTypeMap.loadEntry("image/tiff", "tif", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djvu", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djv", false);
- sMimeTypeMap.loadEntry("image/vnd.wap.wbmp", "wbmp", false);
- sMimeTypeMap.loadEntry("image/x-cmu-raster", "ras", false);
- sMimeTypeMap.loadEntry("image/x-coreldraw", "cdr", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawpattern", "pat", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawtemplate", "cdt", false);
- sMimeTypeMap.loadEntry("image/x-corelphotopaint", "cpt", false);
- sMimeTypeMap.loadEntry("image/x-icon", "ico", false);
- sMimeTypeMap.loadEntry("image/x-jg", "art", false);
- sMimeTypeMap.loadEntry("image/x-jng", "jng", false);
- sMimeTypeMap.loadEntry("image/x-ms-bmp", "bmp", false);
- sMimeTypeMap.loadEntry("image/x-photoshop", "psd", false);
- sMimeTypeMap.loadEntry("image/x-portable-anymap", "pnm", false);
- sMimeTypeMap.loadEntry("image/x-portable-bitmap", "pbm", false);
- sMimeTypeMap.loadEntry("image/x-portable-graymap", "pgm", false);
- sMimeTypeMap.loadEntry("image/x-portable-pixmap", "ppm", false);
- sMimeTypeMap.loadEntry("image/x-rgb", "rgb", false);
- sMimeTypeMap.loadEntry("image/x-xbitmap", "xbm", false);
- sMimeTypeMap.loadEntry("image/x-xpixmap", "xpm", false);
- sMimeTypeMap.loadEntry("image/x-xwindowdump", "xwd", false);
- sMimeTypeMap.loadEntry("model/iges", "igs", false);
- sMimeTypeMap.loadEntry("model/iges", "iges", false);
- sMimeTypeMap.loadEntry("model/mesh", "msh", false);
- sMimeTypeMap.loadEntry("model/mesh", "mesh", false);
- sMimeTypeMap.loadEntry("model/mesh", "silo", false);
- sMimeTypeMap.loadEntry("text/calendar", "ics", true);
- sMimeTypeMap.loadEntry("text/calendar", "icz", true);
- sMimeTypeMap.loadEntry("text/comma-separated-values", "csv", true);
- sMimeTypeMap.loadEntry("text/css", "css", true);
- sMimeTypeMap.loadEntry("text/h323", "323", true);
- sMimeTypeMap.loadEntry("text/iuls", "uls", true);
- sMimeTypeMap.loadEntry("text/mathml", "mml", true);
+ "application/vnd.sun.xml.writer.template", "stw");
+ sMimeTypeMap.loadEntry("application/vnd.visio", "vsd");
+ sMimeTypeMap.loadEntry("application/x-abiword", "abw");
+ sMimeTypeMap.loadEntry("application/x-apple-diskimage", "dmg");
+ sMimeTypeMap.loadEntry("application/x-bcpio", "bcpio");
+ sMimeTypeMap.loadEntry("application/x-bittorrent", "torrent");
+ sMimeTypeMap.loadEntry("application/x-cdf", "cdf");
+ sMimeTypeMap.loadEntry("application/x-cdlink", "vcd");
+ sMimeTypeMap.loadEntry("application/x-chess-pgn", "pgn");
+ sMimeTypeMap.loadEntry("application/x-cpio", "cpio");
+ sMimeTypeMap.loadEntry("application/x-debian-package", "deb");
+ sMimeTypeMap.loadEntry("application/x-debian-package", "udeb");
+ sMimeTypeMap.loadEntry("application/x-director", "dcr");
+ sMimeTypeMap.loadEntry("application/x-director", "dir");
+ sMimeTypeMap.loadEntry("application/x-director", "dxr");
+ sMimeTypeMap.loadEntry("application/x-dms", "dms");
+ sMimeTypeMap.loadEntry("application/x-doom", "wad");
+ sMimeTypeMap.loadEntry("application/x-dvi", "dvi");
+ sMimeTypeMap.loadEntry("application/x-flac", "flac");
+ sMimeTypeMap.loadEntry("application/x-font", "pfa");
+ sMimeTypeMap.loadEntry("application/x-font", "pfb");
+ sMimeTypeMap.loadEntry("application/x-font", "gsf");
+ sMimeTypeMap.loadEntry("application/x-font", "pcf");
+ sMimeTypeMap.loadEntry("application/x-font", "pcf.Z");
+ sMimeTypeMap.loadEntry("application/x-freemind", "mm");
+ sMimeTypeMap.loadEntry("application/x-futuresplash", "spl");
+ sMimeTypeMap.loadEntry("application/x-gnumeric", "gnumeric");
+ sMimeTypeMap.loadEntry("application/x-go-sgf", "sgf");
+ sMimeTypeMap.loadEntry("application/x-graphing-calculator", "gcf");
+ sMimeTypeMap.loadEntry("application/x-gtar", "gtar");
+ sMimeTypeMap.loadEntry("application/x-gtar", "tgz");
+ sMimeTypeMap.loadEntry("application/x-gtar", "taz");
+ sMimeTypeMap.loadEntry("application/x-hdf", "hdf");
+ sMimeTypeMap.loadEntry("application/x-ica", "ica");
+ sMimeTypeMap.loadEntry("application/x-internet-signup", "ins");
+ sMimeTypeMap.loadEntry("application/x-internet-signup", "isp");
+ sMimeTypeMap.loadEntry("application/x-iphone", "iii");
+ sMimeTypeMap.loadEntry("application/x-iso9660-image", "iso");
+ sMimeTypeMap.loadEntry("application/x-jmol", "jmz");
+ sMimeTypeMap.loadEntry("application/x-kchart", "chrt");
+ sMimeTypeMap.loadEntry("application/x-killustrator", "kil");
+ sMimeTypeMap.loadEntry("application/x-koan", "skp");
+ sMimeTypeMap.loadEntry("application/x-koan", "skd");
+ sMimeTypeMap.loadEntry("application/x-koan", "skt");
+ sMimeTypeMap.loadEntry("application/x-koan", "skm");
+ sMimeTypeMap.loadEntry("application/x-kpresenter", "kpr");
+ sMimeTypeMap.loadEntry("application/x-kpresenter", "kpt");
+ sMimeTypeMap.loadEntry("application/x-kspread", "ksp");
+ sMimeTypeMap.loadEntry("application/x-kword", "kwd");
+ sMimeTypeMap.loadEntry("application/x-kword", "kwt");
+ sMimeTypeMap.loadEntry("application/x-latex", "latex");
+ sMimeTypeMap.loadEntry("application/x-lha", "lha");
+ sMimeTypeMap.loadEntry("application/x-lzh", "lzh");
+ sMimeTypeMap.loadEntry("application/x-lzx", "lzx");
+ sMimeTypeMap.loadEntry("application/x-maker", "frm");
+ sMimeTypeMap.loadEntry("application/x-maker", "maker");
+ sMimeTypeMap.loadEntry("application/x-maker", "frame");
+ sMimeTypeMap.loadEntry("application/x-maker", "fb");
+ sMimeTypeMap.loadEntry("application/x-maker", "book");
+ sMimeTypeMap.loadEntry("application/x-maker", "fbdoc");
+ sMimeTypeMap.loadEntry("application/x-mif", "mif");
+ sMimeTypeMap.loadEntry("application/x-ms-wmd", "wmd");
+ sMimeTypeMap.loadEntry("application/x-ms-wmz", "wmz");
+ sMimeTypeMap.loadEntry("application/x-msi", "msi");
+ sMimeTypeMap.loadEntry("application/x-ns-proxy-autoconfig", "pac");
+ sMimeTypeMap.loadEntry("application/x-nwc", "nwc");
+ sMimeTypeMap.loadEntry("application/x-object", "o");
+ sMimeTypeMap.loadEntry("application/x-oz-application", "oza");
+ sMimeTypeMap.loadEntry("application/x-pkcs12", "p12");
+ sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r");
+ sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl");
+ sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl");
+ sMimeTypeMap.loadEntry("application/x-shar", "shar");
+ sMimeTypeMap.loadEntry("application/x-stuffit", "sit");
+ sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio");
+ sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc");
+ sMimeTypeMap.loadEntry("application/x-tar", "tar");
+ sMimeTypeMap.loadEntry("application/x-texinfo", "texinfo");
+ sMimeTypeMap.loadEntry("application/x-texinfo", "texi");
+ sMimeTypeMap.loadEntry("application/x-troff", "t");
+ sMimeTypeMap.loadEntry("application/x-troff", "roff");
+ sMimeTypeMap.loadEntry("application/x-troff-man", "man");
+ sMimeTypeMap.loadEntry("application/x-ustar", "ustar");
+ sMimeTypeMap.loadEntry("application/x-wais-source", "src");
+ sMimeTypeMap.loadEntry("application/x-wingz", "wz");
+ sMimeTypeMap.loadEntry("application/x-webarchive", "webarchive");
+ sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt");
+ sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt");
+ sMimeTypeMap.loadEntry("application/x-xcf", "xcf");
+ sMimeTypeMap.loadEntry("application/x-xfig", "fig");
+ sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml");
+ sMimeTypeMap.loadEntry("audio/basic", "snd");
+ sMimeTypeMap.loadEntry("audio/midi", "mid");
+ sMimeTypeMap.loadEntry("audio/midi", "midi");
+ sMimeTypeMap.loadEntry("audio/midi", "kar");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mpga");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mpega");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mp2");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mp3");
+ sMimeTypeMap.loadEntry("audio/mpeg", "m4a");
+ sMimeTypeMap.loadEntry("audio/mpegurl", "m3u");
+ sMimeTypeMap.loadEntry("audio/prs.sid", "sid");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aif");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aiff");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aifc");
+ sMimeTypeMap.loadEntry("audio/x-gsm", "gsm");
+ sMimeTypeMap.loadEntry("audio/x-mpegurl", "m3u");
+ sMimeTypeMap.loadEntry("audio/x-ms-wma", "wma");
+ sMimeTypeMap.loadEntry("audio/x-ms-wax", "wax");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ra");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "rm");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ram");
+ sMimeTypeMap.loadEntry("audio/x-realaudio", "ra");
+ sMimeTypeMap.loadEntry("audio/x-scpls", "pls");
+ sMimeTypeMap.loadEntry("audio/x-sd2", "sd2");
+ sMimeTypeMap.loadEntry("audio/x-wav", "wav");
+ sMimeTypeMap.loadEntry("image/bmp", "bmp");
+ sMimeTypeMap.loadEntry("image/gif", "gif");
+ sMimeTypeMap.loadEntry("image/ico", "cur");
+ sMimeTypeMap.loadEntry("image/ico", "ico");
+ sMimeTypeMap.loadEntry("image/ief", "ief");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpeg");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpg");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpe");
+ sMimeTypeMap.loadEntry("image/pcx", "pcx");
+ sMimeTypeMap.loadEntry("image/png", "png");
+ sMimeTypeMap.loadEntry("image/svg+xml", "svg");
+ sMimeTypeMap.loadEntry("image/svg+xml", "svgz");
+ sMimeTypeMap.loadEntry("image/tiff", "tiff");
+ sMimeTypeMap.loadEntry("image/tiff", "tif");
+ sMimeTypeMap.loadEntry("image/vnd.djvu", "djvu");
+ sMimeTypeMap.loadEntry("image/vnd.djvu", "djv");
+ sMimeTypeMap.loadEntry("image/vnd.wap.wbmp", "wbmp");
+ sMimeTypeMap.loadEntry("image/x-cmu-raster", "ras");
+ sMimeTypeMap.loadEntry("image/x-coreldraw", "cdr");
+ sMimeTypeMap.loadEntry("image/x-coreldrawpattern", "pat");
+ sMimeTypeMap.loadEntry("image/x-coreldrawtemplate", "cdt");
+ sMimeTypeMap.loadEntry("image/x-corelphotopaint", "cpt");
+ sMimeTypeMap.loadEntry("image/x-icon", "ico");
+ sMimeTypeMap.loadEntry("image/x-jg", "art");
+ sMimeTypeMap.loadEntry("image/x-jng", "jng");
+ sMimeTypeMap.loadEntry("image/x-ms-bmp", "bmp");
+ sMimeTypeMap.loadEntry("image/x-photoshop", "psd");
+ sMimeTypeMap.loadEntry("image/x-portable-anymap", "pnm");
+ sMimeTypeMap.loadEntry("image/x-portable-bitmap", "pbm");
+ sMimeTypeMap.loadEntry("image/x-portable-graymap", "pgm");
+ sMimeTypeMap.loadEntry("image/x-portable-pixmap", "ppm");
+ sMimeTypeMap.loadEntry("image/x-rgb", "rgb");
+ sMimeTypeMap.loadEntry("image/x-xbitmap", "xbm");
+ sMimeTypeMap.loadEntry("image/x-xpixmap", "xpm");
+ sMimeTypeMap.loadEntry("image/x-xwindowdump", "xwd");
+ sMimeTypeMap.loadEntry("model/iges", "igs");
+ sMimeTypeMap.loadEntry("model/iges", "iges");
+ sMimeTypeMap.loadEntry("model/mesh", "msh");
+ sMimeTypeMap.loadEntry("model/mesh", "mesh");
+ sMimeTypeMap.loadEntry("model/mesh", "silo");
+ sMimeTypeMap.loadEntry("text/calendar", "ics");
+ sMimeTypeMap.loadEntry("text/calendar", "icz");
+ sMimeTypeMap.loadEntry("text/comma-separated-values", "csv");
+ sMimeTypeMap.loadEntry("text/css", "css");
+ sMimeTypeMap.loadEntry("text/h323", "323");
+ sMimeTypeMap.loadEntry("text/iuls", "uls");
+ sMimeTypeMap.loadEntry("text/mathml", "mml");
// add it first so it will be the default for ExtensionFromMimeType
- sMimeTypeMap.loadEntry("text/plain", "txt", true);
- sMimeTypeMap.loadEntry("text/plain", "asc", true);
- sMimeTypeMap.loadEntry("text/plain", "text", true);
- sMimeTypeMap.loadEntry("text/plain", "diff", true);
- sMimeTypeMap.loadEntry("text/plain", "pot", true);
- sMimeTypeMap.loadEntry("text/richtext", "rtx", true);
- sMimeTypeMap.loadEntry("text/rtf", "rtf", true);
- sMimeTypeMap.loadEntry("text/texmacs", "ts", true);
- sMimeTypeMap.loadEntry("text/text", "phps", true);
- sMimeTypeMap.loadEntry("text/tab-separated-values", "tsv", true);
- sMimeTypeMap.loadEntry("text/x-bibtex", "bib", true);
- sMimeTypeMap.loadEntry("text/x-boo", "boo", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "h++", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hpp", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hxx", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hh", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "c++", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cpp", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cxx", true);
- sMimeTypeMap.loadEntry("text/x-chdr", "h", true);
- sMimeTypeMap.loadEntry("text/x-component", "htc", true);
- sMimeTypeMap.loadEntry("text/x-csh", "csh", true);
- sMimeTypeMap.loadEntry("text/x-csrc", "c", true);
- sMimeTypeMap.loadEntry("text/x-dsrc", "d", true);
- sMimeTypeMap.loadEntry("text/x-haskell", "hs", true);
- sMimeTypeMap.loadEntry("text/x-java", "java", true);
- sMimeTypeMap.loadEntry("text/x-literate-haskell", "lhs", true);
- sMimeTypeMap.loadEntry("text/x-moc", "moc", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "p", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "pas", true);
- sMimeTypeMap.loadEntry("text/x-pcs-gcd", "gcd", true);
- sMimeTypeMap.loadEntry("text/x-setext", "etx", true);
- sMimeTypeMap.loadEntry("text/x-tcl", "tcl", true);
- sMimeTypeMap.loadEntry("text/x-tex", "tex", true);
- sMimeTypeMap.loadEntry("text/x-tex", "ltx", true);
- sMimeTypeMap.loadEntry("text/x-tex", "sty", true);
- sMimeTypeMap.loadEntry("text/x-tex", "cls", true);
- sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs", true);
- sMimeTypeMap.loadEntry("text/x-vcard", "vcf", true);
- sMimeTypeMap.loadEntry("video/3gpp", "3gp", false);
- sMimeTypeMap.loadEntry("video/3gpp", "3g2", false);
- sMimeTypeMap.loadEntry("video/dl", "dl", false);
- sMimeTypeMap.loadEntry("video/dv", "dif", false);
- sMimeTypeMap.loadEntry("video/dv", "dv", false);
- sMimeTypeMap.loadEntry("video/fli", "fli", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpeg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpe", false);
- sMimeTypeMap.loadEntry("video/mp4", "mp4", false);
- sMimeTypeMap.loadEntry("video/mpeg", "VOB", false);
- sMimeTypeMap.loadEntry("video/quicktime", "qt", false);
- sMimeTypeMap.loadEntry("video/quicktime", "mov", false);
- sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsf", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsx", false);
- sMimeTypeMap.loadEntry("video/x-mng", "mng", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asf", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wm", "wm", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmv", "wmv", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmx", "wmx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wvx", "wvx", false);
- sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false);
- sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false);
- sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false);
- sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx", false);
+ sMimeTypeMap.loadEntry("text/plain", "txt");
+ sMimeTypeMap.loadEntry("text/plain", "asc");
+ sMimeTypeMap.loadEntry("text/plain", "text");
+ sMimeTypeMap.loadEntry("text/plain", "diff");
+ sMimeTypeMap.loadEntry("text/plain", "pot");
+ sMimeTypeMap.loadEntry("text/richtext", "rtx");
+ sMimeTypeMap.loadEntry("text/rtf", "rtf");
+ sMimeTypeMap.loadEntry("text/texmacs", "ts");
+ sMimeTypeMap.loadEntry("text/text", "phps");
+ sMimeTypeMap.loadEntry("text/tab-separated-values", "tsv");
+ sMimeTypeMap.loadEntry("text/x-bibtex", "bib");
+ sMimeTypeMap.loadEntry("text/x-boo", "boo");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "h++");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hpp");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hxx");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hh");
+ sMimeTypeMap.loadEntry("text/x-c++src", "c++");
+ sMimeTypeMap.loadEntry("text/x-c++src", "cpp");
+ sMimeTypeMap.loadEntry("text/x-c++src", "cxx");
+ sMimeTypeMap.loadEntry("text/x-chdr", "h");
+ sMimeTypeMap.loadEntry("text/x-component", "htc");
+ sMimeTypeMap.loadEntry("text/x-csh", "csh");
+ sMimeTypeMap.loadEntry("text/x-csrc", "c");
+ sMimeTypeMap.loadEntry("text/x-dsrc", "d");
+ sMimeTypeMap.loadEntry("text/x-haskell", "hs");
+ sMimeTypeMap.loadEntry("text/x-java", "java");
+ sMimeTypeMap.loadEntry("text/x-literate-haskell", "lhs");
+ sMimeTypeMap.loadEntry("text/x-moc", "moc");
+ sMimeTypeMap.loadEntry("text/x-pascal", "p");
+ sMimeTypeMap.loadEntry("text/x-pascal", "pas");
+ sMimeTypeMap.loadEntry("text/x-pcs-gcd", "gcd");
+ sMimeTypeMap.loadEntry("text/x-setext", "etx");
+ sMimeTypeMap.loadEntry("text/x-tcl", "tcl");
+ sMimeTypeMap.loadEntry("text/x-tex", "tex");
+ sMimeTypeMap.loadEntry("text/x-tex", "ltx");
+ sMimeTypeMap.loadEntry("text/x-tex", "sty");
+ sMimeTypeMap.loadEntry("text/x-tex", "cls");
+ sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs");
+ sMimeTypeMap.loadEntry("text/x-vcard", "vcf");
+ sMimeTypeMap.loadEntry("video/3gpp", "3gp");
+ sMimeTypeMap.loadEntry("video/3gpp", "3g2");
+ sMimeTypeMap.loadEntry("video/dl", "dl");
+ sMimeTypeMap.loadEntry("video/dv", "dif");
+ sMimeTypeMap.loadEntry("video/dv", "dv");
+ sMimeTypeMap.loadEntry("video/fli", "fli");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpeg");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpg");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpe");
+ sMimeTypeMap.loadEntry("video/mp4", "mp4");
+ sMimeTypeMap.loadEntry("video/mpeg", "VOB");
+ sMimeTypeMap.loadEntry("video/quicktime", "qt");
+ sMimeTypeMap.loadEntry("video/quicktime", "mov");
+ sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu");
+ sMimeTypeMap.loadEntry("video/x-la-asf", "lsf");
+ sMimeTypeMap.loadEntry("video/x-la-asf", "lsx");
+ sMimeTypeMap.loadEntry("video/x-mng", "mng");
+ sMimeTypeMap.loadEntry("video/x-ms-asf", "asf");
+ sMimeTypeMap.loadEntry("video/x-ms-asf", "asx");
+ sMimeTypeMap.loadEntry("video/x-ms-wm", "wm");
+ sMimeTypeMap.loadEntry("video/x-ms-wmv", "wmv");
+ sMimeTypeMap.loadEntry("video/x-ms-wmx", "wmx");
+ sMimeTypeMap.loadEntry("video/x-ms-wvx", "wvx");
+ sMimeTypeMap.loadEntry("video/x-msvideo", "avi");
+ sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie");
+ sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice");
+ sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx");
}
return sMimeTypeMap;
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 c9b80ce..0b9e596 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -132,11 +132,11 @@
* XXX: Must be created in the same thread as WebCore!!!!!
*/
private Network(Context context) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(Thread.currentThread().
getName().equals(WebViewCore.THREAD_NAME));
}
- mSslErrorHandler = new SslErrorHandler(this);
+ mSslErrorHandler = new SslErrorHandler();
mHttpAuthHandler = new HttpAuthHandler(this);
mRequestQueue = new RequestQueue(context);
@@ -149,14 +149,12 @@
* @param headers The http headers.
* @param postData The body of the request.
* @param loader A LoadListener for receiving the results of the request.
- * @param isHighPriority True if this is high priority request.
* @return True if the request was successfully queued.
*/
public boolean requestURL(String method,
Map<String, String> headers,
byte [] postData,
- LoadListener loader,
- boolean isHighPriority) {
+ LoadListener loader) {
String url = loader.url();
@@ -188,7 +186,7 @@
RequestHandle handle = q.queueRequest(
url, loader.getWebAddress(), method, headers, loader,
- bodyProvider, bodyLength, isHighPriority);
+ bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
if (loader.isSynchronous()) {
@@ -232,7 +230,7 @@
* connecting through the proxy.
*/
public synchronized void setProxyUsername(String proxyUsername) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -252,7 +250,7 @@
* connecting through the proxy.
*/
public synchronized void setProxyPassword(String proxyPassword) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -266,7 +264,7 @@
* @return True iff succeeds.
*/
public boolean saveState(Bundle outState) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.NETWORK) {
Log.v(LOGTAG, "Network.saveState()");
}
@@ -280,7 +278,7 @@
* @return True iff succeeds.
*/
public boolean restoreState(Bundle inState) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.NETWORK) {
Log.v(LOGTAG, "Network.restoreState()");
}
@@ -300,7 +298,7 @@
* @param loader The loader that resulted in SSL errors.
*/
public void handleSslErrorRequest(LoadListener loader) {
- if (WebView.DEBUG) Assert.assertNotNull(loader);
+ if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
if (loader != null) {
mSslErrorHandler.handleSslErrorRequest(loader);
}
@@ -313,7 +311,7 @@
* authentication request.
*/
public void handleAuthRequest(LoadListener loader) {
- if (WebView.DEBUG) Assert.assertNotNull(loader);
+ if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
if (loader != null) {
mHttpAuthHandler.handleAuthRequest(loader);
}
diff --git a/core/java/android/webkit/Plugin.java b/core/java/android/webkit/Plugin.java
index f83da99..302bea2 100644
--- a/core/java/android/webkit/Plugin.java
+++ b/core/java/android/webkit/Plugin.java
@@ -26,7 +26,11 @@
/**
* 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, so is this class.
*/
+@Deprecated
public class Plugin {
public interface PreferencesClickHandler {
public void handleClickEvent(Context context);
@@ -38,6 +42,10 @@
private String mDescription;
private PreferencesClickHandler mHandler;
+ /**
+ * @deprecated
+ */
+ @Deprecated
public Plugin(String name,
String path,
String fileName,
@@ -49,49 +57,92 @@
mHandler = new DefaultClickHandler();
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public String toString() {
return mName;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public String getName() {
return mName;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public String getPath() {
return mPath;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public String getFileName() {
return mFileName;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public String getDescription() {
return mDescription;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void setName(String name) {
mName = name;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void setPath(String path) {
mPath = path;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void setFileName(String fileName) {
mFileName = fileName;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void setDescription(String description) {
mDescription = description;
}
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void setClickHandler(PreferencesClickHandler handler) {
mHandler = handler;
}
/**
* Invokes the click handler for this plugin.
+ *
+ * @deprecated
*/
+ @Deprecated
public void dispatchClickEvent(Context context) {
if (mHandler != null) {
mHandler.handleClickEvent(context);
@@ -100,11 +151,14 @@
/**
* Default click handler. The plugins should implement their own.
+ *
+ * @deprecated
*/
+ @Deprecated
private class DefaultClickHandler implements PreferencesClickHandler,
DialogInterface.OnClickListener {
private AlertDialog mDialog;
-
+ @Deprecated
public void handleClickEvent(Context context) {
// Show a simple popup dialog containing the description
// string of the plugin.
@@ -117,7 +171,10 @@
.show();
}
}
-
+ /**
+ * @deprecated
+ */
+ @Deprecated
public void onClick(DialogInterface dialog, int which) {
mDialog.dismiss();
mDialog = null;
diff --git a/core/java/android/webkit/PluginContentLoader.java b/core/java/android/webkit/PluginContentLoader.java
deleted file mode 100644
index 2069599..0000000
--- a/core/java/android/webkit/PluginContentLoader.java
+++ /dev/null
@@ -1,96 +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.webkit;
-
-import android.net.http.Headers;
-
-import java.io.InputStream;
-import java.util.*;
-
-import org.apache.http.util.CharArrayBuffer;
-
-/**
- * This class is a concrete implementation of StreamLoader that uses a
- * PluginData object as the source for the stream.
- */
-class PluginContentLoader extends StreamLoader {
-
- private PluginData mData; // Content source
-
- /**
- * Constructs a PluginDataLoader for use when loading content from
- * a plugin.
- *
- * @param loadListener LoadListener to pass the content to
- * @param data PluginData used as the source for the content.
- */
- PluginContentLoader(LoadListener loadListener, PluginData data) {
- super(loadListener);
- mData = data;
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- mDataStream = mData.getInputStream();
- mContentLength = mData.getContentLength();
- mHandler.status(1, 1, mData.getStatusCode(), "OK");
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- // Crate a CharArrayBuffer with an arbitrary initial capacity.
- CharArrayBuffer buffer = new CharArrayBuffer(100);
- Iterator<Map.Entry<String, String[]>> responseHeadersIt =
- mData.getHeaders().entrySet().iterator();
- while (responseHeadersIt.hasNext()) {
- Map.Entry<String, String[]> entry = responseHeadersIt.next();
- // Headers.parseHeader() expects lowercase keys, so keys
- // such as "Accept-Ranges" will fail to parse.
- //
- // UrlInterceptHandler instances supply a mapping of
- // lowercase key to [ unmodified key, value ], so for
- // Headers.parseHeader() to succeed, we need to construct
- // a string using the key (i.e. entry.getKey()) and the
- // element denoting the header value in the
- // [ unmodified key, value ] pair (i.e. entry.getValue()[1).
- //
- // The reason why UrlInterceptHandler instances supply such a
- // mapping in the first place is historical. Early versions of
- // the Gears plugin used java.net.HttpURLConnection, which always
- // returned headers names as capitalized strings. When these were
- // fed back into webkit, they failed to parse.
- //
- // Mewanwhile, Gears was modified to use Apache HTTP library
- // instead, so this design is now obsolete. Changing it however,
- // would require changes to the Gears C++ codebase and QA-ing and
- // submitting a new binary to the Android tree. Given the
- // timelines for the next Android release, we will not do this
- // for now.
- //
- // TODO: fix C++ Gears to remove the need for this
- // design.
- String keyValue = entry.getKey() + ": " + entry.getValue()[1];
- buffer.ensureCapacity(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- headers.parseHeader(buffer);
- // Clear the buffer
- buffer.clear();
- }
- }
-}
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index 2b539fe..d9b196a 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -28,7 +28,10 @@
* 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, so is this class.
*/
+@Deprecated
public final class PluginData {
/**
* The content stream.
@@ -47,10 +50,6 @@
private Map<String, String[]> mHeaders;
/**
- * The index of the header value in the above mapping.
- */
- private int mHeaderValueIndex;
- /**
* The associated HTTP response code.
*/
private int mStatusCode;
@@ -63,7 +62,10 @@
* @param headers The response headers. Map of
* lowercase header name to [ unmodified header name, header value]
* @param length The HTTP response status code.
+ *
+ * @deprecated
*/
+ @Deprecated
public PluginData(
InputStream stream,
long length,
@@ -79,7 +81,10 @@
* Returns the input stream that contains the plugin content.
*
* @return An InputStream instance with the plugin content.
+ *
+ * @deprecated
*/
+ @Deprecated
public InputStream getInputStream() {
return mStream;
}
@@ -88,7 +93,10 @@
* Returns the length of the plugin content.
*
* @return the length of the plugin content.
+ *
+ * @deprecated
*/
+ @Deprecated
public long getContentLength() {
return mContentLength;
}
@@ -100,7 +108,10 @@
* @return A Map<String, String[]> containing all headers. The
* mapping is 'lowercase header name' to ['unmodified header
* name', header value].
+ *
+ * @deprecated
*/
+ @Deprecated
public Map<String, String[]> getHeaders() {
return mHeaders;
}
@@ -109,7 +120,10 @@
* Returns the HTTP status code for the response.
*
* @return The HTTP statue code, e.g 200.
+ *
+ * @deprecated
*/
+ @Deprecated
public int getStatusCode() {
return mStatusCode;
}
diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java
index a9d3d8c..5b65b9a 100644
--- a/core/java/android/webkit/PluginList.java
+++ b/core/java/android/webkit/PluginList.java
@@ -24,27 +24,40 @@
* A simple list of initialized plugins. This list gets
* 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, so is this class.
*/
+@Deprecated
public class PluginList {
private ArrayList<Plugin> mPlugins;
/**
* Public constructor. Initializes the list of plugins.
+ *
+ * @deprecated
*/
+ @Deprecated
public PluginList() {
mPlugins = new ArrayList<Plugin>();
}
/**
* Returns the list of plugins as a java.util.List.
+ *
+ * @deprecated
*/
+ @Deprecated
public synchronized List getList() {
return mPlugins;
}
/**
* Adds a plugin to the list.
+ *
+ * @deprecated
*/
+ @Deprecated
public synchronized void addPlugin(Plugin plugin) {
if (!mPlugins.contains(plugin)) {
mPlugins.add(plugin);
@@ -53,7 +66,10 @@
/**
* Removes a plugin from the list.
+ *
+ * @deprecated
*/
+ @Deprecated
public synchronized void removePlugin(Plugin plugin) {
int location = mPlugins.indexOf(plugin);
if (location != -1) {
@@ -63,14 +79,20 @@
/**
* Clears the plugin list.
+ *
+ * @deprecated
*/
+ @Deprecated
public synchronized void clear() {
mPlugins.clear();
}
/**
* Dispatches the click event to the appropriate plugin.
+ *
+ * @deprecated
*/
+ @Deprecated
public synchronized void pluginClicked(Context context, int position) {
try {
Plugin plugin = mPlugins.get(position);
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
new file mode 100644
index 0000000..cd34192
--- /dev/null
+++ b/core/java/android/webkit/PluginManager.java
@@ -0,0 +1,156 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+/**
+ * Class for managing the relationship between the {@link WebView} and installed
+ * plugins in the system. You can find this class through
+ * {@link PluginManager#getInstance}.
+ *
+ * @hide pending API solidification
+ */
+public class PluginManager {
+
+ /**
+ * Service Action: A plugin wishes to be loaded in the WebView must provide
+ * {@link android.content.IntentFilter IntentFilter} that accepts this
+ * action in their AndroidManifest.xml.
+ * <p>
+ * TODO: we may change this to a new PLUGIN_ACTION if this is going to be
+ * public.
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
+
+ /**
+ * A plugin wishes to be loaded in the WebView must provide this permission
+ * in their AndroidManifest.xml.
+ */
+ public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
+
+ private static final String LOGTAG = "webkit";
+
+ private static PluginManager mInstance = null;
+
+ private final Context mContext;
+
+ private PluginManager(Context context) {
+ mContext = context;
+ }
+
+ public static synchronized PluginManager getInstance(Context context) {
+ if (mInstance == null) {
+ if (context == null) {
+ throw new IllegalStateException(
+ "First call to PluginManager need a valid context.");
+ }
+ mInstance = new PluginManager(context);
+ }
+ return mInstance;
+ }
+
+ /**
+ * Signal the WebCore thread to refresh its list of plugins. Use this if the
+ * directory contents of one of the plugin directories has been modified and
+ * needs its changes reflecting. May cause plugin load and/or unload.
+ *
+ * @param reloadOpenPages Set to true to reload all open pages.
+ */
+ public void refreshPlugins(boolean reloadOpenPages) {
+ BrowserFrame.sJavaBridge.obtainMessage(
+ JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages)
+ .sendToTarget();
+ }
+
+ String[] getPluginDirecoties() {
+ ArrayList<String> directories = new ArrayList<String>();
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
+ PLUGIN_ACTION), PackageManager.GET_SERVICES);
+ for (ResolveInfo info : plugins) {
+ ServiceInfo serviceInfo = info.serviceInfo;
+ if (serviceInfo == null) {
+ Log.w(LOGTAG, "Ignore bad plugin");
+ continue;
+ }
+ PackageInfo pkgInfo;
+ try {
+ pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
+ PackageManager.GET_PERMISSIONS
+ | PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
+ continue;
+ }
+ if (pkgInfo == null) {
+ continue;
+ }
+ String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+ if (directories.contains(directory)) {
+ continue;
+ }
+ String permissions[] = pkgInfo.requestedPermissions;
+ if (permissions == null) {
+ continue;
+ }
+ boolean permissionOk = false;
+ for (String permit : permissions) {
+ if (PLUGIN_PERMISSION.equals(permit)) {
+ permissionOk = true;
+ break;
+ }
+ }
+ if (!permissionOk) {
+ continue;
+ }
+ Signature signatures[] = pkgInfo.signatures;
+ if (signatures == null) {
+ continue;
+ }
+ boolean signatureMatch = false;
+ for (Signature signature : signatures) {
+ // TODO: check signature against Google provided one
+ signatureMatch = true;
+ break;
+ }
+ if (!signatureMatch) {
+ continue;
+ }
+ directories.add(directory);
+ }
+ return directories.toArray(new String[directories.size()]);
+ }
+
+ String getPluginSharedDataDirectory() {
+ return mContext.getDir("plugins", 0).getPath();
+ }
+}
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 5f84bbe..5011244 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -42,11 +42,6 @@
private static final String LOGTAG = "network";
/**
- * Network.
- */
- private Network mNetwork;
-
- /**
* Queue of loaders that experience SSL-related problems.
*/
private LinkedList<LoadListener> mLoaderQueue;
@@ -57,7 +52,7 @@
private Bundle mSslPrefTable;
// Message id for handling the response
- private final int HANDLE_RESPONSE = 100;
+ private static final int HANDLE_RESPONSE = 100;
@Override
public void handleMessage(Message msg) {
@@ -72,9 +67,7 @@
/**
* Creates a new error handler with an empty loader queue.
*/
- /* package */ SslErrorHandler(Network network) {
- mNetwork = network;
-
+ /* package */ SslErrorHandler() {
mLoaderQueue = new LinkedList<LoadListener>();
mSslPrefTable = new Bundle();
}
@@ -120,7 +113,7 @@
* Handles SSL error(s) on the way up to the user.
*/
/* package */ synchronized void handleSslErrorRequest(LoadListener loader) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Log.v(LOGTAG, "SslErrorHandler.handleSslErrorRequest(): " +
"url=" + loader.url());
}
@@ -157,14 +150,14 @@
SslError error = loader.sslError();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(error);
}
int primary = error.getPrimaryError();
String host = loader.host();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertTrue(host != null && primary != 0);
}
@@ -205,11 +198,11 @@
*/
/* package */ synchronized void handleSslErrorResponse(boolean proceed) {
LoadListener loader = mLoaderQueue.poll();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(loader);
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():"
+ " proceed: " + proceed
+ " url:" + loader.url());
@@ -221,13 +214,13 @@
int primary = loader.sslError().getPrimaryError();
String host = loader.host();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertTrue(host != null && primary != 0);
}
boolean hasKey = mSslPrefTable.containsKey(host);
if (!hasKey ||
primary > mSslPrefTable.getInt(host)) {
- mSslPrefTable.putInt(host, new Integer(primary));
+ mSslPrefTable.putInt(host, primary);
}
}
loader.handleSslErrorResponse(proceed);
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index 705157c..eab3350 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -102,7 +102,7 @@
// to pass data to the loader
mData = new byte[8192];
sendHeaders();
- while (!sendData());
+ while (!sendData() && !mHandler.cancelled());
closeStreamAndSendEndData();
mHandler.loadSynchronousMessages();
}
@@ -113,9 +113,13 @@
* @see android.os.Handler#handleMessage(android.os.Message)
*/
public void handleMessage(Message msg) {
- if (WebView.DEBUG && mHandler.isSynchronous()) {
+ if (DebugFlags.STREAM_LOADER && mHandler.isSynchronous()) {
throw new AssertionError();
}
+ if (mHandler.cancelled()) {
+ closeStreamAndSendEndData();
+ return;
+ }
switch(msg.what) {
case MSG_STATUS:
if (setupStreamAndSendStatus()) {
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
deleted file mode 100644
index 99de56d..0000000
--- a/core/java/android/webkit/TextDialog.java
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.method.MovementMethod;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsoluteLayout.LayoutParams;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * TextDialog is a specialized version of EditText used by WebView
- * to overlay html textfields (and textareas) to use our standard
- * text editing.
- */
-/* package */ class TextDialog extends AutoCompleteTextView {
-
- private WebView mWebView;
- private boolean mSingle;
- private int mWidthSpec;
- private int mHeightSpec;
- private int mNodePointer;
- // FIXME: This is a hack for blocking unmatched key ups, in particular
- // on the enter key. The method for blocking unmatched key ups prevents
- // the shift key from working properly.
- private boolean mGotEnterDown;
- // mScrollToAccommodateCursor being set to false prevents us from scrolling
- // the cursor on screen when using the trackball to select a textfield.
- private boolean mScrollToAccommodateCursor;
- private int mMaxLength;
- // Keep track of the text before the change so we know whether we actually
- // need to send down the DOM events.
- private String mPreChange;
- // Array to store the final character added in onTextChanged, so that its
- // KeyEvents may be determined.
- private char[] mCharacter = new char[1];
- // This is used to reset the length filter when on a textfield
- // with no max length.
- // FIXME: This can be replaced with TextView.NO_FILTERS if that
- // is made public/protected.
- private static final InputFilter[] NO_FILTERS = new InputFilter[0];
-
- /**
- * Create a new TextDialog.
- * @param context The Context for this TextDialog.
- * @param webView The WebView that created this.
- */
- /* package */ TextDialog(Context context, WebView webView) {
- super(context);
- mWebView = webView;
- ShapeDrawable background = new ShapeDrawable(new RectShape());
- Paint shapePaint = background.getPaint();
- shapePaint.setStyle(Paint.Style.STROKE);
- ColorDrawable color = new ColorDrawable(Color.WHITE);
- Drawable[] array = new Drawable[2];
- array[0] = color;
- array[1] = background;
- LayerDrawable layers = new LayerDrawable(array);
- // Hide WebCore's text behind this and allow the WebView
- // to draw its own focusring.
- setBackgroundDrawable(layers);
- // Align the text better with the text behind it, so moving
- // off of the textfield will not appear to move the text.
- setPadding(3, 2, 0, 0);
- mMaxLength = -1;
- // Turn on subpixel text, and turn off kerning, so it better matches
- // the text in webkit.
- TextPaint paint = getPaint();
- int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
- Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
- paint.setFlags(flags);
- // Set the text color to black, regardless of the theme. This ensures
- // that other applications that use embedded WebViews will properly
- // display the text in textfields.
- setTextColor(Color.BLACK);
- setImeOptions(EditorInfo.IME_ACTION_NONE);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.isSystem()) {
- return super.dispatchKeyEvent(event);
- }
- // Treat ACTION_DOWN and ACTION MULTIPLE the same
- boolean down = event.getAction() != KeyEvent.ACTION_UP;
- int keyCode = event.getKeyCode();
- Spannable text = (Spannable) getText();
- int oldLength = text.length();
- // Normally the delete key's dom events are sent via onTextChanged.
- // However, if the length is zero, the text did not change, so we
- // go ahead and pass the key down immediately.
- if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
- sendDomEvent(event);
- return true;
- }
-
- if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) {
- if (isPopupShowing()) {
- return super.dispatchKeyEvent(event);
- }
- if (!down) {
- // Hide the keyboard, since the user has just submitted this
- // form. The submission happens thanks to the two calls
- // to sendDomEvent.
- InputMethodManager.getInstance(mContext)
- .hideSoftInputFromWindow(getWindowToken(), 0);
- sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- sendDomEvent(event);
- }
- return super.dispatchKeyEvent(event);
- } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- // Note that this handles center key and trackball.
- if (isPopupShowing()) {
- return super.dispatchKeyEvent(event);
- }
- // Center key should be passed to a potential onClick
- if (!down) {
- mWebView.shortPressOnTextField();
- }
- // Pass to super to handle longpress.
- return super.dispatchKeyEvent(event);
- }
-
- // Ensure there is a layout so arrow keys are handled properly.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- int oldStart = Selection.getSelectionStart(text);
- int oldEnd = Selection.getSelectionEnd(text);
-
- boolean maxedOut = mMaxLength != -1 && oldLength == mMaxLength;
- // If we are at max length, and there is a selection rather than a
- // cursor, we need to store the text to compare later, since the key
- // may have changed the string.
- String oldText;
- if (maxedOut && oldEnd != oldStart) {
- oldText = text.toString();
- } else {
- oldText = "";
- }
- if (super.dispatchKeyEvent(event)) {
- // If the TextDialog handled the key it was either an alphanumeric
- // key, a delete, or a movement within the text. All of those are
- // ok to pass to javascript.
-
- // UNLESS there is a max length determined by the html. In that
- // case, if the string was already at the max length, an
- // alphanumeric key will be erased by the LengthFilter,
- // so do not pass down to javascript, and instead
- // return true. If it is an arrow key or a delete key, we can go
- // ahead and pass it down.
- boolean isArrowKey;
- switch(keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- isArrowKey = true;
- break;
- case KeyEvent.KEYCODE_ENTER:
- // For multi-line text boxes, newlines will
- // trigger onTextChanged for key down (which will send both
- // key up and key down) but not key up.
- mGotEnterDown = true;
- default:
- isArrowKey = false;
- break;
- }
- if (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
- if (oldEnd == oldStart) {
- // Return true so the key gets dropped.
- mScrollToAccommodateCursor = true;
- return true;
- } else if (!oldText.equals(getText().toString())) {
- // FIXME: This makes the text work properly, but it
- // does not pass down the key event, so it may not
- // work for a textfield that has the type of
- // behavior of GoogleSuggest. That said, it is
- // unlikely that a site would combine the two in
- // one textfield.
- Spannable span = (Spannable) getText();
- int newStart = Selection.getSelectionStart(span);
- int newEnd = Selection.getSelectionEnd(span);
- mWebView.replaceTextfieldText(0, oldLength, span.toString(),
- newStart, newEnd);
- mScrollToAccommodateCursor = true;
- return true;
- }
- }
- if (isArrowKey) {
- // Arrow key does not change the text, but we still want to send
- // the DOM events.
- sendDomEvent(event);
- }
- mScrollToAccommodateCursor = true;
- return true;
- }
- // FIXME: TextViews return false for up and down key events even though
- // they change the selection. Since we don't want the get out of sync
- // with WebCore's notion of the current selection, reset the selection
- // to what it was before the key event.
- Selection.setSelection(text, oldStart, oldEnd);
- // Ignore the key up event for newlines. This prevents
- // multiple newlines in the native textarea.
- if (mGotEnterDown && !down) {
- return true;
- }
- // if it is a navigation key, pass it to WebView
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
- || keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- // WebView check the trackballtime in onKeyDown to avoid calling
- // native from both trackball and key handling. As this is called
- // from TextDialog, we always want WebView to check with native.
- // Reset trackballtime to ensure it.
- mWebView.resetTrackballTime();
- return down ? mWebView.onKeyDown(keyCode, event) : mWebView
- .onKeyUp(keyCode, event);
- }
- return false;
- }
-
- /**
- * Create a fake touch up event at (x,y) with respect to this TextDialog.
- * This is used by WebView to act as though a touch event which happened
- * before we placed the TextDialog actually hit it, so that it can place
- * the cursor accordingly.
- */
- /* package */ void fakeTouchEvent(float x, float y) {
- // We need to ensure that there is a Layout, since the Layout is used
- // in determining where to place the cursor.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- // Create a fake touch up, which is used to place the cursor.
- MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
- x, y, 0);
- onTouchEvent(ev);
- ev.recycle();
- }
-
- /**
- * Determine whether this TextDialog currently represents the node
- * represented by ptr.
- * @param ptr Pointer to a node to compare to.
- * @return boolean Whether this TextDialog already represents the node
- * pointed to by ptr.
- */
- /* package */ boolean isSameTextField(int ptr) {
- return ptr == mNodePointer;
- }
-
- @Override
- public boolean onPreDraw() {
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- return super.onPreDraw();
- }
-
- @Override
- protected void onTextChanged(CharSequence s,int start,int before,int count){
- super.onTextChanged(s, start, before, count);
- String postChange = s.toString();
- // Prevent calls to setText from invoking onTextChanged (since this will
- // mean we are on a different textfield). Also prevent the change when
- // going from a textfield with a string of text to one with a smaller
- // limit on text length from registering the onTextChanged event.
- if (mPreChange == null || mPreChange.equals(postChange) ||
- (mMaxLength > -1 && mPreChange.length() > mMaxLength &&
- mPreChange.substring(0, mMaxLength).equals(postChange))) {
- return;
- }
- mPreChange = postChange;
- // This was simply a delete or a cut, so just delete the
- // selection.
- if (before > 0 && 0 == count) {
- mWebView.deleteSelection(start, start + before);
- // For this and all changes to the text, update our cache
- updateCachedTextfield();
- return;
- }
- // Find the last character being replaced. If it can be represented by
- // events, we will pass them to native (after replacing the beginning
- // of the changed text), so we can see javascript events.
- // Otherwise, replace the text being changed (including the last
- // character) in the textfield.
- TextUtils.getChars(s, start + count - 1, start + count, mCharacter, 0);
- KeyCharacterMap kmap =
- KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
- KeyEvent[] events = kmap.getEvents(mCharacter);
- boolean cannotUseKeyEvents = null == events;
- int charactersFromKeyEvents = cannotUseKeyEvents ? 0 : 1;
- if (count > 1 || cannotUseKeyEvents) {
- String replace = s.subSequence(start,
- start + count - charactersFromKeyEvents).toString();
- mWebView.replaceTextfieldText(start, start + before, replace,
- start + count - charactersFromKeyEvents,
- start + count - charactersFromKeyEvents);
- } else {
- // This corrects the selection which may have been affected by the
- // trackball or auto-correct.
- mWebView.setSelection(start, start + before);
- }
- updateCachedTextfield();
- if (cannotUseKeyEvents) {
- return;
- }
- int length = events.length;
- for (int i = 0; i < length; i++) {
- // We never send modifier keys to native code so don't send them
- // here either.
- if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
- sendDomEvent(events[i]);
- }
- }
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- if (isPopupShowing()) {
- return super.onTrackballEvent(event);
- }
- if (event.getAction() != MotionEvent.ACTION_MOVE) {
- return false;
- }
- Spannable text = (Spannable) getText();
- MovementMethod move = getMovementMethod();
- if (move != null && getLayout() != null &&
- move.onTrackballEvent(this, text, event)) {
- // Need to pass down the selection, which has changed.
- // FIXME: This should work, but does not, so we set the selection
- // in onTextChanged.
- //int start = Selection.getSelectionStart(text);
- //int end = Selection.getSelectionEnd(text);
- //mWebView.setSelection(start, end);
- return true;
- }
- // If the user is in a textfield, and the movement method is not
- // handling the trackball events, it means they are at the end of the
- // field and continuing to move the trackball. In this case, we should
- // not scroll the cursor on screen bc the user may be attempting to
- // scroll the page, possibly in the opposite direction of the cursor.
- mScrollToAccommodateCursor = false;
- return false;
- }
-
- /**
- * Remove this TextDialog from its host WebView, and return
- * focus to the host.
- */
- /* package */ void remove() {
- // hide the soft keyboard when the edit text is out of focus
- InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
- getWindowToken(), 0);
- mWebView.removeView(this);
- mWebView.requestFocus();
- mScrollToAccommodateCursor = false;
- }
-
- /* package */ void enableScrollOnScreen(boolean enable) {
- mScrollToAccommodateCursor = enable;
- }
-
- /* package */ void bringIntoView() {
- if (getLayout() != null) {
- bringPointIntoView(Selection.getSelectionEnd(getText()));
- }
- }
-
- @Override
- public boolean requestRectangleOnScreen(Rect rectangle) {
- if (mScrollToAccommodateCursor) {
- return super.requestRectangleOnScreen(rectangle);
- }
- return false;
- }
-
- /**
- * Send the DOM events for the specified event.
- * @param event KeyEvent to be translated into a DOM event.
- */
- private void sendDomEvent(KeyEvent event) {
- mWebView.passToJavaScript(getText().toString(), event);
- }
-
- /**
- * Always use this instead of setAdapter, as this has features specific to
- * the TextDialog.
- */
- public void setAdapterCustom(AutoCompleteAdapter adapter) {
- if (adapter != null) {
- setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
- adapter.setTextView(this);
- }
- super.setAdapter(adapter);
- }
-
- /**
- * This is a special version of ArrayAdapter which changes its text size
- * to match the text size of its host TextView.
- */
- public static class AutoCompleteAdapter extends ArrayAdapter<String> {
- private TextView mTextView;
-
- public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
- super(context, com.android.internal.R.layout
- .search_dropdown_item_1line, entries);
- }
-
- /**
- * {@inheritDoc}
- */
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView tv =
- (TextView) super.getView(position, convertView, parent);
- if (tv != null && mTextView != null) {
- tv.setTextSize(mTextView.getTextSize());
- }
- return tv;
- }
-
- /**
- * Set the TextView so we can match its text size.
- */
- private void setTextView(TextView tv) {
- mTextView = tv;
- }
- }
-
- /**
- * Determine whether to use the system-wide password disguising method,
- * or to use none.
- * @param inPassword True if the textfield is a password field.
- */
- /* package */ void setInPassword(boolean inPassword) {
- if (inPassword) {
- setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
- TYPE_TEXT_VARIATION_PASSWORD);
- }
- }
-
- /* package */ void setMaxLength(int maxLength) {
- mMaxLength = maxLength;
- if (-1 == maxLength) {
- setFilters(NO_FILTERS);
- } else {
- setFilters(new InputFilter[] {
- new InputFilter.LengthFilter(maxLength) });
- }
- }
-
- /**
- * Set the pointer for this node so it can be determined which node this
- * TextDialog represents.
- * @param ptr Integer representing the pointer to the node which this
- * TextDialog represents.
- */
- /* package */ void setNodePointer(int ptr) {
- mNodePointer = ptr;
- }
-
- /**
- * Determine the position and size of TextDialog, and add it to the
- * WebView's view heirarchy. All parameters are presumed to be in
- * view coordinates. Also requests Focus and sets the cursor to not
- * request to be in view.
- * @param x x-position of the textfield.
- * @param y y-position of the textfield.
- * @param width width of the textfield.
- * @param height height of the textfield.
- */
- /* package */ void setRect(int x, int y, int width, int height) {
- LayoutParams lp = (LayoutParams) getLayoutParams();
- if (null == lp) {
- lp = new LayoutParams(width, height, x, y);
- } else {
- lp.x = x;
- lp.y = y;
- lp.width = width;
- lp.height = height;
- }
- if (getParent() == null) {
- mWebView.addView(this, lp);
- } else {
- setLayoutParams(lp);
- }
- // Set up a measure spec so a layout can always be recreated.
- mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
- mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- requestFocus();
- }
-
- /**
- * Set whether this is a single-line textfield or a multi-line textarea.
- * Textfields scroll horizontally, and do not handle the enter key.
- * Textareas behave oppositely.
- * Do NOT call this after calling setInPassword(true). This will result in
- * removing the password input type.
- */
- public void setSingleLine(boolean single) {
- int inputType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
- if (!single) {
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
- | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
- | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
- }
- mSingle = single;
- setHorizontallyScrolling(single);
- setInputType(inputType);
- }
-
- /**
- * Set the text for this TextDialog, and set the selection to (start, end)
- * @param text Text to go into this TextDialog.
- * @param start Beginning of the selection.
- * @param end End of the selection.
- */
- /* package */ void setText(CharSequence text, int start, int end) {
- mPreChange = text.toString();
- setText(text);
- Spannable span = (Spannable) getText();
- int length = span.length();
- if (end > length) {
- end = length;
- }
- if (start < 0) {
- start = 0;
- } else if (start > length) {
- start = length;
- }
- Selection.setSelection(span, start, end);
- }
-
- /**
- * Set the text to the new string, but use the old selection, making sure
- * to keep it within the new string.
- * @param text The new text to place in the textfield.
- */
- /* package */ void setTextAndKeepSelection(String text) {
- mPreChange = text.toString();
- Editable edit = (Editable) getText();
- edit.replace(0, edit.length(), text);
- updateCachedTextfield();
- }
-
- /**
- * Update the cache to reflect the current text.
- */
- /* package */ void updateCachedTextfield() {
- mWebView.updateCachedTextfield(getText().toString());
- }
-}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 9889fe9..5ed42e9 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -61,7 +61,7 @@
webAddress = new WebAddress(inUrl);
} catch (ParseException ex) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.URL_UTIL) {
Log.v(LOGTAG, "smartUrlFilter: failed to parse url = " + inUrl);
}
return retVal;
@@ -126,6 +126,32 @@
return retData;
}
+ /**
+ * @return True iff the url is correctly URL encoded
+ */
+ static boolean verifyURLEncoding(String url) {
+ int count = url.length();
+ if (count == 0) {
+ return false;
+ }
+
+ int index = url.indexOf('%');
+ while (index >= 0 && index < count) {
+ if (index < count - 2) {
+ try {
+ parseHex((byte) url.charAt(++index));
+ parseHex((byte) url.charAt(++index));
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ index = url.indexOf('%', index + 1);
+ }
+ return true;
+ }
+
private static int parseHex(byte b) {
if (b >= '0' && b <= '9') return (b - '0');
if (b >= 'A' && b <= 'F') return (b - 'A' + 10);
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index 9216413..78bab04 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -20,6 +20,11 @@
import android.webkit.PluginData;
import java.util.Map;
+/**
+ * @deprecated This interface was inteded to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+@Deprecated
public interface UrlInterceptHandler {
/**
@@ -30,8 +35,8 @@
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The CacheResult containing the surrogate response.
- * @Deprecated Use PluginData getPluginData(String url,
- * Map<String, String> headers); instead
+ *
+ * @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
public CacheResult service(String url, Map<String, String> headers);
@@ -44,6 +49,9 @@
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The PluginData containing the surrogate response.
+ *
+ * @deprecated Do not use, this interface is deprecated.
*/
+ @Deprecated
public PluginData getPluginData(String url, Map<String, String> headers);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index 6051f29..6e2a482 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -24,6 +24,11 @@
import java.util.LinkedList;
import java.util.Map;
+/**
+ * @deprecated This class was inteded to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+@Deprecated
public final class UrlInterceptRegistry {
private final static String LOGTAG = "intercept";
@@ -42,7 +47,10 @@
* set the flag to control whether url intercept is enabled or disabled
*
* @param disabled true to disable the cache
+ *
+ * @deprecated
*/
+ @Deprecated
public static synchronized void setUrlInterceptDisabled(boolean disabled) {
mDisabled = disabled;
}
@@ -51,7 +59,10 @@
* get the state of the url intercept, enabled or disabled
*
* @return return if it is disabled
+ *
+ * @deprecated
*/
+ @Deprecated
public static synchronized boolean urlInterceptDisabled() {
return mDisabled;
}
@@ -62,7 +73,10 @@
*
* @param handler The new UrlInterceptHandler object
* @return true if the handler was not previously registered.
+ *
+ * @deprecated
*/
+ @Deprecated
public static synchronized boolean registerHandler(
UrlInterceptHandler handler) {
if (!getHandlers().contains(handler)) {
@@ -78,7 +92,10 @@
*
* @param handler A previously registered UrlInterceptHandler.
* @return true if the handler was found and removed from the list.
+ *
+ * @deprecated
*/
+ @Deprecated
public static synchronized boolean unregisterHandler(
UrlInterceptHandler handler) {
return getHandlers().remove(handler);
@@ -89,8 +106,8 @@
* UrlInterceptHandler interested, or null if none are.
*
* @return A CacheResult containing surrogate content.
- * @Deprecated Use PluginData getPluginData( String url,
- * Map<String, String> headers) instead.
+ *
+ * @deprecated
*/
@Deprecated
public static synchronized CacheResult getSurrogate(
@@ -115,7 +132,10 @@
* intercepts are disabled.
*
* @return A PluginData instance containing surrogate content.
+ *
+ * @deprecated
*/
+ @Deprecated
public static synchronized PluginData getPluginData(
String url, Map<String, String> headers) {
if (urlInterceptDisabled()) {
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
new file mode 100644
index 0000000..af33b4f
--- /dev/null
+++ b/core/java/android/webkit/ViewManager.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.AbsoluteLayout;
+
+import java.util.ArrayList;
+
+class ViewManager {
+ private final WebView mWebView;
+ private final ArrayList<ChildView> mChildren = new ArrayList<ChildView>();
+ private boolean mHidden;
+
+ class ChildView {
+ int x;
+ int y;
+ int width;
+ int height;
+ View mView; // generic view to show
+
+ ChildView() {
+ }
+
+ void setBounds(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ void attachView(int x, int y, int width, int height) {
+ if (mView == null) {
+ return;
+ }
+ setBounds(x, y, width, height);
+ final AbsoluteLayout.LayoutParams lp =
+ new AbsoluteLayout.LayoutParams(ctv(width), ctv(height),
+ ctv(x), ctv(y));
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ // This method may be called multiple times. If the view is
+ // already attached, just set the new LayoutParams,
+ // otherwise attach the view and add it to the list of
+ // children.
+ if (mView.getParent() != null) {
+ mView.setLayoutParams(lp);
+ } else {
+ attachViewOnUIThread(lp);
+ }
+ }
+ });
+ }
+
+ void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) {
+ mWebView.addView(mView, lp);
+ mChildren.add(this);
+ }
+
+ void removeView() {
+ if (mView == null) {
+ return;
+ }
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ removeViewOnUIThread();
+ }
+ });
+ }
+
+ void removeViewOnUIThread() {
+ mWebView.removeView(mView);
+ mChildren.remove(this);
+ }
+ }
+
+ ViewManager(WebView w) {
+ mWebView = w;
+ }
+
+ ChildView createView() {
+ return new ChildView();
+ }
+
+ // contentToView shorthand.
+ private int ctv(int val) {
+ return mWebView.contentToView(val);
+ }
+
+ void scaleAll() {
+ for (ChildView v : mChildren) {
+ View view = v.mView;
+ AbsoluteLayout.LayoutParams lp =
+ (AbsoluteLayout.LayoutParams) view.getLayoutParams();
+ lp.width = ctv(v.width);
+ lp.height = ctv(v.height);
+ lp.x = ctv(v.x);
+ lp.y = ctv(v.y);
+ view.setLayoutParams(lp);
+ }
+ }
+
+ void hideAll() {
+ if (mHidden) {
+ return;
+ }
+ for (ChildView v : mChildren) {
+ v.mView.setVisibility(View.GONE);
+ }
+ mHidden = true;
+ }
+
+ void showAll() {
+ if (!mHidden) {
+ return;
+ }
+ for (ChildView v : mChildren) {
+ v.mView.setVisibility(View.VISIBLE);
+ }
+ mHidden = false;
+ }
+}
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index ffd6a11..62a5531 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -137,7 +137,7 @@
// when removing the first item, we can assert that the index is 0.
// This lets us change the current index without having to query the
// native BackForwardList.
- if (WebView.DEBUG && (index != 0)) {
+ if (DebugFlags.WEB_BACK_FORWARD_LIST && (index != 0)) {
throw new AssertionError();
}
final WebHistoryItem h = mArray.remove(index);
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 9d9763c..e1c8d4d 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -18,10 +18,20 @@
import android.graphics.Bitmap;
import android.os.Message;
+import android.view.View;
public class WebChromeClient {
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param toZoomedOut If true, the WebView has zoomed out so that the page
+ * fits the screen. If false, it is zoomed to the setting
+ * specified by the user.
+ * @hide
+ */
+ public void onChangeViewingMode(boolean toZoomedOut) {}
+
+ /**
* 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
@@ -44,6 +54,47 @@
public void onReceivedIcon(WebView view, Bitmap icon) {}
/**
+ * Notify the host application of the url for an apple-touch-icon.
+ * @param view The WebView that initiated the callback.
+ * @param url The icon url.
+ * @hide pending council approval
+ */
+ public void onReceivedTouchIconUrl(WebView view, String url) {}
+
+ /**
+ * A callback interface used by the host application to notify
+ * the current page that its custom view has been dismissed.
+ *
+ * @hide pending council approval
+ */
+ public interface CustomViewCallback {
+ /**
+ * Invoked when the host application dismisses the
+ * custom view.
+ */
+ public void onCustomViewHidden();
+ }
+
+ /**
+ * Notify the host application that the current page would
+ * like to show a custom View.
+ * @param view is the View object to be shown.
+ * @param callback is the callback to be invoked if and when the view
+ * is dismissed.
+ *
+ * @hide pending council approval
+ */
+ public void onShowCustomView(View view, CustomViewCallback callback) {};
+
+ /**
+ * Notify the host application that the current page would
+ * like to hide its custom view.
+ *
+ * @hide pending council approval
+ */
+ public void onHideCustomView() {}
+
+ /**
* Request the host application to create a new Webview. The host
* application should handle placement of the new WebView in the view
* system. The default behavior returns null.
@@ -158,6 +209,54 @@
return false;
}
+ /**
+ * Tell the client that the database quota for the origin has been exceeded.
+ * @param url The URL that triggered the notification
+ * @param databaseIdentifier The identifier of the database that caused the
+ * quota overflow.
+ * @param currentQuota The current quota for the origin.
+ * @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,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ // This default implementation passes the current quota back to WebCore.
+ // WebCore will interpret this that new quota was declined.
+ quotaUpdater.updateQuota(currentQuota);
+ }
+
+ /**
+ * Tell the client that the Application Cache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * app cache size is available. This callback must always be executed at
+ * some point to ensure that the sleeping WebCore thread is woken up.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ quotaUpdater.updateQuota(0);
+ }
+
+ /**
+ * Instructs the client to show a prompt to ask the user to set the
+ * Geolocation permission state for the specified origin.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {}
+
+ /**
+ * Instructs the client to hide the Geolocation permissions prompt.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsHidePrompt() {}
+
/**
* Tell the client that a JavaScript execution timeout has occured. And the
* client may decide whether or not to interrupt the execution. If the
@@ -172,4 +271,14 @@
public boolean onJsTimeout() {
return true;
}
+
+ /**
+ * Add a JavaScript error message to the console. Clients should override
+ * this to process the log message as they see fit.
+ * @param message The error message to report.
+ * @param lineNumber The line number of the error.
+ * @param sourceID The name of the source file that caused the error.
+ * @hide pending API council.
+ */
+ public void addMessageToConsole(String message, int lineNumber, String sourceID) {}
}
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index fd26b98..abd8237 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -39,6 +39,8 @@
private Bitmap mFavicon;
// The pre-flattened data used for saving the state.
private byte[] mFlattenedData;
+ // The apple-touch-icon url for use when adding the site to the home screen
+ private String mTouchIconUrl;
/**
* Basic constructor that assigns a unique id to the item. Called by JNI
@@ -127,6 +129,14 @@
}
/**
+ * Return the touch icon url.
+ * @hide
+ */
+ public String getTouchIconUrl() {
+ return mTouchIconUrl;
+ }
+
+ /**
* Set the favicon.
* @param icon A Bitmap containing the favicon for this history item.
* Note: The VM ensures 32-bit atomic read/write operations so we don't have
@@ -137,6 +147,14 @@
}
/**
+ * Set the touch icon url.
+ * @hide
+ */
+ /*package*/ void setTouchIconUrl(String url) {
+ mTouchIconUrl = url;
+ }
+
+ /**
* Get the pre-flattened data.
* Note: The VM ensures 32-bit atomic read/write operations so we don't have
* to synchronize this method.
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index d284f5e..6cc6bb4 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -37,7 +37,7 @@
private final EventHandler mEventHandler = new EventHandler();
// Class to handle messages before WebCore is ready
- private class EventHandler extends Handler {
+ private static class EventHandler extends Handler {
// Message ids
static final int OPEN = 0;
static final int CLOSE = 1;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index a038b55..eeac1d2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -22,9 +22,7 @@
import android.os.Handler;
import android.os.Message;
import android.provider.Checkin;
-
import java.lang.SecurityException;
-
import java.util.Locale;
/**
@@ -130,9 +128,13 @@
private boolean mSyncPending = false;
// Custom handler that queues messages until the WebCore thread is active.
private final EventHandler mEventHandler;
+
// Private settings so we don't have to go into native code to
// retrieve the values. After setXXX, postSync() needs to be called.
- // XXX: The default values need to match those in WebSettings.cpp
+ //
+ // The default values need to match those in WebSettings.cpp
+ // If the defaults change, please also update the JavaDocs so developers
+ // know what they are.
private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
private Context mContext;
private TextSize mTextSize = TextSize.NORMAL;
@@ -146,7 +148,6 @@
private String mUserAgent;
private boolean mUseDefaultUserAgent;
private String mAcceptLanguage;
- private String mPluginsPath = "";
private int mMinimumFontSize = 8;
private int mMinimumLogicalFontSize = 8;
private int mDefaultFontSize = 16;
@@ -161,6 +162,15 @@
private boolean mUseWideViewport = false;
private boolean mSupportMultipleWindows = false;
private boolean mShrinksStandaloneImagesToFit = false;
+ // HTML5 API flags
+ private boolean mAppCacheEnabled = false;
+ private boolean mDatabaseEnabled = false;
+ private boolean mDomStorageEnabled = false;
+ private boolean mWorkersEnabled = false; // only affects V8.
+ // HTML5 configuration parameters
+ private long mAppCacheMaxSize = Long.MAX_VALUE;
+ private String mAppCachePath = "";
+ private String mDatabasePath = "";
// 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.
@@ -175,9 +185,7 @@
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
-
- // The Gears permissions manager. Only in Donut.
- static GearsPermissionsManager sGearsPermissionsManager;
+ private boolean mLoadWithOverviewMode = true;
// Class to handle messages before WebCore is ready.
private class EventHandler {
@@ -199,7 +207,6 @@
switch (msg.what) {
case SYNC:
synchronized (WebSettings.this) {
- checkGearsPermissions();
if (mBrowserFrame.mNativeFrame != 0) {
nativeSync(mBrowserFrame.mNativeFrame);
}
@@ -247,13 +254,13 @@
// User agent strings.
private static final String DESKTOP_USERAGENT =
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Safari/525.20.1";
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)"
+ + " AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0"
+ + " Safari/530.17";
private static final String IPHONE_USERAGENT =
- "Mozilla/5.0 (iPhone; U; CPU iPhone 2_1 like Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Mobile/5F136 Safari/525.20.1";
+ "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
+ + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0"
+ + " Mobile/7A341 Safari/528.16";
private static Locale sLocale;
private static Object sLockForLocaleSettings;
@@ -421,6 +428,22 @@
}
/**
+ * Set whether the WebView loads a page with overview mode.
+ * @hide Pending API council approval
+ */
+ public void setLoadWithOverviewMode(boolean overview) {
+ mLoadWithOverviewMode = overview;
+ }
+
+ /**
+ * Returns true if this WebView loads page with overview mode
+ * @hide Pending API council approval
+ */
+ public boolean getLoadWithOverviewMode() {
+ return mLoadWithOverviewMode;
+ }
+
+ /**
* Store whether the WebView is saving form data.
*/
public void setSaveFormData(boolean save) {
@@ -511,24 +534,21 @@
}
/**
- * Tell the WebView to use the double tree rendering algorithm.
- * @param use True if the WebView is to use double tree rendering, false
- * otherwise.
+ * @deprecated This setting controlled a rendering optimization
+ * that is no longer present. Setting it now has no effect.
*/
+ @Deprecated
public synchronized void setUseDoubleTree(boolean use) {
- if (mUseDoubleTree != use) {
- mUseDoubleTree = use;
- postSync();
- }
+ return;
}
/**
- * Return true if the WebView is using the double tree rendering algorithm.
- * @return True if the WebView is using the double tree rendering
- * algorithm.
+ * @deprecated This setting controlled a rendering optimization
+ * that is no longer present. Setting it now has no effect.
*/
+ @Deprecated
public synchronized boolean getUseDoubleTree() {
- return mUseDoubleTree;
+ return false;
}
/**
@@ -633,7 +653,7 @@
}
/**
- * Return the current layout algorithm.
+ * Return the current layout algorithm. The default is NARROW_COLUMNS.
* @return LayoutAlgorithm enum value describing the layout algorithm
* being used.
* @see WebSettings.LayoutAlgorithm
@@ -654,7 +674,7 @@
}
/**
- * Get the standard font family name.
+ * Get the standard font family name. The default is "sans-serif".
* @return The standard font family name as a string.
*/
public synchronized String getStandardFontFamily() {
@@ -673,7 +693,7 @@
}
/**
- * Get the fixed font family name.
+ * Get the fixed font family name. The default is "monospace".
* @return The fixed font family name as a string.
*/
public synchronized String getFixedFontFamily() {
@@ -700,7 +720,7 @@
}
/**
- * Set the serif font family name.
+ * Set the serif font family name. The default is "sans-serif".
* @param font A font family name.
*/
public synchronized void setSerifFontFamily(String font) {
@@ -711,7 +731,7 @@
}
/**
- * Get the serif font family name.
+ * Get the serif font family name. The default is "serif".
* @return The serif font family name as a string.
*/
public synchronized String getSerifFontFamily() {
@@ -730,7 +750,7 @@
}
/**
- * Get the cursive font family name.
+ * Get the cursive font family name. The default is "cursive".
* @return The cursive font family name as a string.
*/
public synchronized String getCursiveFontFamily() {
@@ -749,7 +769,7 @@
}
/**
- * Get the fantasy font family name.
+ * Get the fantasy font family name. The default is "fantasy".
* @return The fantasy font family name as a string.
*/
public synchronized String getFantasyFontFamily() {
@@ -770,7 +790,7 @@
}
/**
- * Get the minimum font size.
+ * Get the minimum font size. The default is 8.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getMinimumFontSize() {
@@ -791,7 +811,7 @@
}
/**
- * Get the minimum logical font size.
+ * Get the minimum logical font size. The default is 8.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getMinimumLogicalFontSize() {
@@ -812,7 +832,7 @@
}
/**
- * Get the default font size.
+ * Get the default font size. The default is 16.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getDefaultFontSize() {
@@ -833,7 +853,7 @@
}
/**
- * Get the default fixed font size.
+ * Get the default fixed font size. The default is 16.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getDefaultFixedFontSize() {
@@ -853,6 +873,7 @@
/**
* Return true if the WebView will load image resources automatically.
+ * The default is true.
* @return True if the WebView loads images automatically.
*/
public synchronized boolean getLoadsImagesAutomatically() {
@@ -872,16 +893,16 @@
}
/**
- * Return true if the WebView will block network image.
+ * Return true if the WebView will block network image. The default is false.
* @return True if the WebView blocks network image.
*/
public synchronized boolean getBlockNetworkImage() {
return mBlockNetworkImage;
}
-
+
/**
* @hide
- * Tell the WebView to block all network load requests.
+ * Tell the WebView to block all network load requests.
* @param flag True if the WebView should block all network loads
*/
public synchronized void setBlockNetworkLoads(boolean flag) {
@@ -894,13 +915,14 @@
/**
* @hide
* Return true if the WebView will block all network loads.
+ * The default is false.
* @return True if the WebView blocks all network loads.
*/
public synchronized boolean getBlockNetworkLoads() {
return mBlockNetworkLoads;
}
-
-
+
+
private void verifyNetworkAccess() {
if (!mBlockNetworkLoads) {
if (mContext.checkPermission("android.permission.INTERNET",
@@ -936,19 +958,131 @@
}
/**
- * Set a custom path to plugins used by the WebView. The client
- * must ensure it exists before this call.
- * @param pluginsPath String path to the directory containing plugins.
+ * TODO: need to add @Deprecated
*/
public synchronized void setPluginsPath(String pluginsPath) {
- if (pluginsPath != null && !pluginsPath.equals(mPluginsPath)) {
- mPluginsPath = pluginsPath;
+ }
+
+ /**
+ * Set the path to where database storage API databases should be saved.
+ * This will update WebCore when the Sync runs in the C++ side.
+ * @param databasePath String path to the directory where databases should
+ * be saved. May be the empty string but should never be null.
+ */
+ public synchronized void setDatabasePath(String databasePath) {
+ if (databasePath != null && !databasePath.equals(mDatabasePath)) {
+ mDatabasePath = databasePath;
postSync();
}
}
/**
- * Return true if javascript is enabled.
+ * Tell the WebView to enable Application Caches API.
+ * @param flag True if the WebView should enable Application Caches.
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCacheEnabled(boolean flag) {
+ if (mAppCacheEnabled != flag) {
+ mAppCacheEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Set a custom path to the Application Caches files. The client
+ * must ensure it exists before this call.
+ * @param appCachePath String path to the directory containing Application
+ * Caches files. The appCache path can be the empty string but should not
+ * be null. Passing null for this parameter will result in a no-op.
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCachePath(String appCachePath) {
+ if (appCachePath != null && !appCachePath.equals(mAppCachePath)) {
+ mAppCachePath = appCachePath;
+ postSync();
+ }
+ }
+
+ /**
+ * Set the maximum size for the Application Caches content.
+ * @param appCacheMaxSize the maximum size in bytes.
+ *
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
+ if (appCacheMaxSize != mAppCacheMaxSize) {
+ mAppCacheMaxSize = appCacheMaxSize;
+ postSync();
+ }
+ }
+
+ /**
+ * Set whether the database storage API is enabled.
+ * @param flag boolean True if the WebView should use the database storage
+ * API.
+ */
+ public synchronized void setDatabaseEnabled(boolean flag) {
+ if (mDatabaseEnabled != flag) {
+ mDatabaseEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Set whether the DOM storage API is enabled.
+ * @param flag boolean True if the WebView should use the DOM storage
+ * API.
+ * @hide pending API council.
+ */
+ public synchronized void setDomStorageEnabled(boolean flag) {
+ if (mDomStorageEnabled != flag) {
+ mDomStorageEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Returns true if the DOM Storage API's are enabled.
+ * @return True if the DOM Storage API's are enabled.
+ * @hide pending API council.
+ */
+ public synchronized boolean getDomStorageEnabled() {
+ return mDomStorageEnabled;
+ }
+
+ /**
+ * Return the path to where database storage API databases are saved for
+ * the current WebView.
+ * @return the String path to the database storage API databases.
+ */
+ public synchronized String getDatabasePath() {
+ return mDatabasePath;
+ }
+
+ /**
+ * Returns true if database storage API is enabled.
+ * @return True if the database storage API is enabled.
+ */
+ public synchronized boolean getDatabaseEnabled() {
+ return mDatabaseEnabled;
+ }
+
+ /**
+ * Tell the WebView to enable WebWorkers API.
+ * @param flag True if the WebView should enable WebWorkers.
+ * Note that this flag only affects V8. JSC does not have
+ * an equivalent setting.
+ * @hide pending api council approval
+ */
+ public synchronized void setWorkersEnabled(boolean flag) {
+ if (mWorkersEnabled != flag) {
+ mWorkersEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Return true if javascript is enabled. <b>Note: The default is false.</b>
* @return True if javascript is enabled.
*/
public synchronized boolean getJavaScriptEnabled() {
@@ -964,11 +1098,10 @@
}
/**
- * Return the current path used for plugins in the WebView.
- * @return The string path to the WebView plugins.
+ * TODO: need to add @Deprecated
*/
public synchronized String getPluginsPath() {
- return mPluginsPath;
+ return "";
}
/**
@@ -985,7 +1118,8 @@
}
/**
- * Return true if javascript can open windows automatically.
+ * Return true if javascript can open windows automatically. The default
+ * is false.
* @return True if javascript can open windows automatically during
* window.open().
*/
@@ -1005,7 +1139,7 @@
}
/**
- * Get the default text encoding name.
+ * Get the default text encoding name. The default is "Latin-1".
* @return The default text encoding name as a string.
*/
public synchronized String getDefaultTextEncodingName() {
@@ -1094,8 +1228,8 @@
/**
* Set the priority of the Render thread. Unlike the other settings, this
- * one only needs to be called once per process.
- *
+ * one only needs to be called once per process. The default is NORMAL.
+ *
* @param priority RenderPriority, can be normal, high or low.
*/
public synchronized void setRenderPriority(RenderPriority priority) {
@@ -1149,10 +1283,9 @@
/*package*/
synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
mBrowserFrame = frame;
- if (WebView.DEBUG) {
+ if (DebugFlags.WEB_SETTINGS) {
junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
}
- checkGearsPermissions();
nativeSync(frame.mNativeFrame);
mSyncPending = false;
mEventHandler.createHandler();
@@ -1168,23 +1301,6 @@
return size;
}
- private void checkGearsPermissions() {
- // Did we already check the permissions at startup?
- if (sGearsPermissionsManager != null) {
- return;
- }
- // Is the pluginsPath sane?
- String pluginsPath = getPluginsPath();
- if (pluginsPath == null || pluginsPath.length() == 0) {
- // We don't yet have a meaningful plugin path, so
- // we can't do anything about the Gears permissions.
- return;
- }
- sGearsPermissionsManager =
- new GearsPermissionsManager(mContext, pluginsPath);
- sGearsPermissionsManager.doCheckAndStartObserver();
- }
-
/* Post a SYNC message to handle syncing the native settings. */
private synchronized void postSync() {
// Only post if a sync is not pending
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
new file mode 100644
index 0000000..ae560fb
--- /dev/null
+++ b/core/java/android/webkit/WebStorage.java
@@ -0,0 +1,311 @@
+/*
+ * 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;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Functionality for manipulating the webstorage databases.
+ */
+public final class WebStorage {
+
+ /**
+ * Encapsulates a callback function to be executed when a new quota is made
+ * available. We primarily want this to allow us to call back the sleeping
+ * WebCore thread from outside the WebViewCore class (as the native call
+ * is private). It is imperative that this the setDatabaseQuota method is
+ * executed once a decision to either allow or deny new quota is made,
+ * otherwise the WebCore thread will remain asleep.
+ */
+ public interface QuotaUpdater {
+ public void updateQuota(long newQuota);
+ };
+
+ // Log tag
+ private static final String TAG = "webstorage";
+
+ // Global instance of a WebStorage
+ private static WebStorage sWebStorage;
+
+ // We keep the origins, quotas and usages as member values
+ // that we protect via a lock and update in syncValues().
+ // This is needed to transfer this data across threads.
+ private static Lock mLock = new ReentrantLock();
+ private static Condition mUpdateCondition = mLock.newCondition();
+ private static boolean mUpdateAvailable;
+
+ // Message ids
+ static final int UPDATE = 0;
+ static final int SET_QUOTA_ORIGIN = 1;
+ static final int DELETE_ORIGIN = 2;
+ static final int DELETE_ALL = 3;
+
+ private Set <String> mOrigins;
+ private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
+ private HashMap <String, Long> mUsages = new HashMap<String, Long>();
+
+ private Handler mHandler = null;
+
+ private static class Origin {
+ String mOrigin = null;
+ long mQuota = 0;
+
+ public Origin(String origin, long quota) {
+ mOrigin = origin;
+ mQuota = quota;
+ }
+
+ public Origin(String origin) {
+ mOrigin = origin;
+ }
+
+ public String getOrigin() {
+ return mOrigin;
+ }
+
+ public long getQuota() {
+ return mQuota;
+ }
+ }
+
+ /**
+ * @hide
+ * Message handler
+ */
+ public void createHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SET_QUOTA_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeSetQuotaForOrigin(website.getOrigin(),
+ website.getQuota());
+ } break;
+
+ case DELETE_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeDeleteOrigin(website.getOrigin());
+ } break;
+
+ case DELETE_ALL:
+ nativeDeleteAllData();
+ break;
+
+ case UPDATE:
+ syncValues();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * @hide
+ * Returns a list of origins having a database
+ */
+ public Set getOrigins() {
+ Set ret = null;
+ mLock.lock();
+ try {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
+ ret = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the use for a given origin
+ */
+ public long getUsageForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
+ Long usage = mUsages.get(origin);
+ if (usage != null) {
+ ret = usage.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the quota for a given origin
+ */
+ public long getQuotaForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.await();
+ }
+ Long quota = mQuotas.get(origin);
+ if (quota != null) {
+ ret = quota.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Set the quota for a given origin
+ */
+ public void setQuotaForOrigin(String origin, long quota) {
+ if (origin != null) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeSetQuotaForOrigin(origin, quota);
+ } else {
+ postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+ new Origin(origin, quota)));
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Delete a given origin
+ */
+ public void deleteOrigin(String origin) {
+ if (origin != null) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteOrigin(origin);
+ } else {
+ postMessage(Message.obtain(null, DELETE_ORIGIN,
+ new Origin(origin)));
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Delete all databases
+ */
+ public void deleteAllData() {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteAllData();
+ } else {
+ postMessage(Message.obtain(null, DELETE_ALL));
+ }
+ }
+
+ /**
+ * Utility function to send a message to our handler
+ */
+ private void postMessage(Message msg) {
+ if (mHandler != null) {
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
+ * @hide
+ * Get the global instance of WebStorage.
+ * @return A single instance of WebStorage.
+ */
+ public static WebStorage getInstance() {
+ if (sWebStorage == null) {
+ sWebStorage = new WebStorage();
+ }
+ return sWebStorage;
+ }
+
+ /**
+ * @hide
+ * Post a Sync request
+ */
+ public void update() {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, UPDATE));
+ }
+ }
+
+ /**
+ * Run on the webcore thread
+ * set the local values with the current ones
+ */
+ private void syncValues() {
+ mLock.lock();
+ Set tmp = nativeGetOrigins();
+ mOrigins = new HashSet<String>();
+ mQuotas.clear();
+ mUsages.clear();
+ Iterator<String> iter = tmp.iterator();
+ while (iter.hasNext()) {
+ String origin = iter.next();
+ mOrigins.add(origin);
+ mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
+ mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+ }
+ mUpdateAvailable = true;
+ mUpdateCondition.signal();
+ mLock.unlock();
+ }
+
+ // Native functions
+ private static native Set nativeGetOrigins();
+ private static native long nativeGetUsageForOrigin(String origin);
+ private static native long nativeGetQuotaForOrigin(String origin);
+ private static native void nativeSetQuotaForOrigin(String origin, long quota);
+ private static native void nativeDeleteOrigin(String origin);
+ private static native void nativeDeleteAllData();
+}
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index ded17ed..d3ec603 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -47,7 +47,7 @@
@Override
public void handleMessage(Message msg) {
if (msg.what == SYNC_MESSAGE) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager sync ***");
}
syncFromRamToFlash();
@@ -94,7 +94,7 @@
* sync() forces sync manager to sync now
*/
public void sync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager sync ***");
}
if (mHandler == null) {
@@ -109,7 +109,7 @@
* resetSync() resets sync manager's timer
*/
public void resetSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager resetSync ***");
}
if (mHandler == null) {
@@ -124,7 +124,7 @@
* startSync() requests sync manager to start sync
*/
public void startSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager startSync ***, Ref count:" +
mStartSyncRefCount);
}
@@ -142,7 +142,7 @@
* the queue to break the sync loop
*/
public void stopSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager stopSync ***, Ref count:" +
mStartSyncRefCount);
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
new file mode 100644
index 0000000..a1f2223
--- /dev/null
+++ b/core/java/android/webkit/WebTextView.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.method.MovementMethod;
+import android.text.method.Touch;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputConnection;
+import android.widget.AbsoluteLayout.LayoutParams;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * WebTextView is a specialized version of EditText used by WebView
+ * to overlay html textfields (and textareas) to use our standard
+ * text editing.
+ */
+/* package */ class WebTextView extends AutoCompleteTextView {
+
+ static final String LOGTAG = "webtextview";
+
+ private WebView mWebView;
+ private boolean mSingle;
+ private int mWidthSpec;
+ private int mHeightSpec;
+ private int mNodePointer;
+ // FIXME: This is a hack for blocking unmatched key ups, in particular
+ // on the enter key. The method for blocking unmatched key ups prevents
+ // the shift key from working properly.
+ private boolean mGotEnterDown;
+ private int mMaxLength;
+ // Keep track of the text before the change so we know whether we actually
+ // need to send down the DOM events.
+ private String mPreChange;
+ private Drawable mBackground;
+ // Variables for keeping track of the touch down, to send to the WebView
+ // when a drag starts
+ private float mDragStartX;
+ private float mDragStartY;
+ private long mDragStartTime;
+ private boolean mDragSent;
+ // True if the most recent drag event has caused either the TextView to
+ // scroll or the web page to scroll. Gets reset after a touch down.
+ private boolean mScrolled;
+ // Gets set to true when the the IME jumps to the next textfield. When this
+ // happens, the next time the user hits a key it is okay for the focus
+ // pointer to not match the WebTextView's node pointer
+ private boolean mOkayForFocusNotToMatch;
+ // Whether or not a selection change was generated from webkit. If it was,
+ // we do not need to pass the selection back to webkit.
+ private boolean mFromWebKit;
+ private boolean mGotTouchDown;
+ // Array to store the final character added in onTextChanged, so that its
+ // KeyEvents may be determined.
+ private char[] mCharacter = new char[1];
+ // This is used to reset the length filter when on a textfield
+ // with no max length.
+ // FIXME: This can be replaced with TextView.NO_FILTERS if that
+ // is made public/protected.
+ private static final InputFilter[] NO_FILTERS = new InputFilter[0];
+
+ /**
+ * Create a new WebTextView.
+ * @param context The Context for this WebTextView.
+ * @param webView The WebView that created this.
+ */
+ /* package */ WebTextView(Context context, WebView webView) {
+ super(context);
+ mWebView = webView;
+ mMaxLength = -1;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.isSystem()) {
+ return super.dispatchKeyEvent(event);
+ }
+ // Treat ACTION_DOWN and ACTION MULTIPLE the same
+ boolean down = event.getAction() != KeyEvent.ACTION_UP;
+ int keyCode = event.getKeyCode();
+
+ boolean isArrowKey = false;
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+ .onKeyUp(keyCode, event);
+
+ }
+ isArrowKey = true;
+ break;
+ }
+ if (!isArrowKey && !mOkayForFocusNotToMatch
+ && mWebView.nativeFocusNodePointer() != mNodePointer) {
+ mWebView.nativeClearCursor();
+ // Do not call remove() here, which hides the soft keyboard. If
+ // the soft keyboard is being displayed, the user will still want
+ // it there.
+ mWebView.removeView(this);
+ mWebView.requestFocus();
+ return mWebView.dispatchKeyEvent(event);
+ }
+ // After a jump to next textfield and the first key press, the cursor
+ // and focus will once again match, so reset this value.
+ mOkayForFocusNotToMatch = false;
+
+ Spannable text = (Spannable) getText();
+ int oldLength = text.length();
+ // Normally the delete key's dom events are sent via onTextChanged.
+ // However, if the length is zero, the text did not change, so we
+ // go ahead and pass the key down immediately.
+ if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
+ sendDomEvent(event);
+ return true;
+ }
+
+ if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) {
+ if (isPopupShowing()) {
+ return super.dispatchKeyEvent(event);
+ }
+ if (!down) {
+ // Hide the keyboard, since the user has just submitted this
+ // form. The submission happens thanks to the two calls
+ // to sendDomEvent.
+ InputMethodManager.getInstance(mContext)
+ .hideSoftInputFromWindow(getWindowToken(), 0);
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ sendDomEvent(event);
+ }
+ return super.dispatchKeyEvent(event);
+ } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
+ // Note that this handles center key and trackball.
+ if (isPopupShowing()) {
+ return super.dispatchKeyEvent(event);
+ }
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+ .onKeyUp(keyCode, event);
+ }
+ // Center key should be passed to a potential onClick
+ if (!down) {
+ mWebView.shortPressOnTextField();
+ }
+ // Pass to super to handle longpress.
+ return super.dispatchKeyEvent(event);
+ }
+
+ // Ensure there is a layout so arrow keys are handled properly.
+ if (getLayout() == null) {
+ measure(mWidthSpec, mHeightSpec);
+ }
+ int oldStart = Selection.getSelectionStart(text);
+ int oldEnd = Selection.getSelectionEnd(text);
+
+ boolean maxedOut = mMaxLength != -1 && oldLength == mMaxLength;
+ // If we are at max length, and there is a selection rather than a
+ // cursor, we need to store the text to compare later, since the key
+ // may have changed the string.
+ String oldText;
+ if (maxedOut && oldEnd != oldStart) {
+ oldText = text.toString();
+ } else {
+ oldText = "";
+ }
+ if (super.dispatchKeyEvent(event)) {
+ // If the WebTextView handled the key it was either an alphanumeric
+ // key, a delete, or a movement within the text. All of those are
+ // ok to pass to javascript.
+
+ // UNLESS there is a max length determined by the html. In that
+ // case, if the string was already at the max length, an
+ // alphanumeric key will be erased by the LengthFilter,
+ // so do not pass down to javascript, and instead
+ // return true. If it is an arrow key or a delete key, we can go
+ // ahead and pass it down.
+ if (KeyEvent.KEYCODE_ENTER == keyCode) {
+ // For multi-line text boxes, newlines will
+ // trigger onTextChanged for key down (which will send both
+ // key up and key down) but not key up.
+ mGotEnterDown = true;
+ }
+ if (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
+ if (oldEnd == oldStart) {
+ // Return true so the key gets dropped.
+ return true;
+ } else if (!oldText.equals(getText().toString())) {
+ // FIXME: This makes the text work properly, but it
+ // does not pass down the key event, so it may not
+ // work for a textfield that has the type of
+ // behavior of GoogleSuggest. That said, it is
+ // unlikely that a site would combine the two in
+ // one textfield.
+ Spannable span = (Spannable) getText();
+ int newStart = Selection.getSelectionStart(span);
+ int newEnd = Selection.getSelectionEnd(span);
+ mWebView.replaceTextfieldText(0, oldLength, span.toString(),
+ newStart, newEnd);
+ return true;
+ }
+ }
+ /* FIXME:
+ * In theory, we would like to send the events for the arrow keys.
+ * However, the TextView can arbitrarily change the selection (i.e.
+ * long press followed by using the trackball). Therefore, we keep
+ * in sync with the TextView via onSelectionChanged. If we also
+ * send the DOM event, we lose the correct selection.
+ if (isArrowKey) {
+ // Arrow key does not change the text, but we still want to send
+ // the DOM events.
+ sendDomEvent(event);
+ }
+ */
+ return true;
+ }
+ // Ignore the key up event for newlines. This prevents
+ // multiple newlines in the native textarea.
+ if (mGotEnterDown && !down) {
+ return true;
+ }
+ // if it is a navigation key, pass it to WebView
+ if (isArrowKey) {
+ // WebView check the trackballtime in onKeyDown to avoid calling
+ // native from both trackball and key handling. As this is called
+ // from WebTextView, we always want WebView to check with native.
+ // Reset trackballtime to ensure it.
+ mWebView.resetTrackballTime();
+ return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+ .onKeyUp(keyCode, event);
+ }
+ return false;
+ }
+
+ /**
+ * Create a fake touch up event at (x,y) with respect to this WebTextView.
+ * This is used by WebView to act as though a touch event which happened
+ * before we placed the WebTextView actually hit it, so that it can place
+ * the cursor accordingly.
+ */
+ /* package */ void fakeTouchEvent(float x, float y) {
+ // We need to ensure that there is a Layout, since the Layout is used
+ // in determining where to place the cursor.
+ if (getLayout() == null) {
+ measure(mWidthSpec, mHeightSpec);
+ }
+ // Create a fake touch up, which is used to place the cursor.
+ MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
+ x, y, 0);
+ onTouchEvent(ev);
+ ev.recycle();
+ }
+
+ /**
+ * Determine whether this WebTextView currently represents the node
+ * represented by ptr.
+ * @param ptr Pointer to a node to compare to.
+ * @return boolean Whether this WebTextView already represents the node
+ * pointed to by ptr.
+ */
+ /* package */ boolean isSameTextField(int ptr) {
+ return ptr == mNodePointer;
+ }
+
+ @Override public InputConnection onCreateInputConnection(
+ EditorInfo outAttrs) {
+ InputConnection connection = super.onCreateInputConnection(outAttrs);
+ if (mWebView != null) {
+ // Use the name of the textfield + the url. Use backslash as an
+ // arbitrary separator.
+ outAttrs.fieldName = mWebView.nativeFocusCandidateName() + "\\"
+ + mWebView.getUrl();
+ }
+ return connection;
+ }
+
+ @Override
+ public void onEditorAction(int actionCode) {
+ switch (actionCode) {
+ case EditorInfo.IME_ACTION_NEXT:
+ mWebView.nativeMoveCursorToNextTextInput();
+ // Preemptively rebuild the WebTextView, so that the action will
+ // be set properly.
+ mWebView.rebuildWebTextView();
+ // Since the cursor will no longer be in the same place as the
+ // focus, set the focus controller back to inactive
+ mWebView.setFocusControllerInactive();
+ mOkayForFocusNotToMatch = true;
+ break;
+ case EditorInfo.IME_ACTION_DONE:
+ super.onEditorAction(actionCode);
+ break;
+ case EditorInfo.IME_ACTION_GO:
+ // Send an enter and hide the soft keyboard
+ InputMethodManager.getInstance(mContext)
+ .hideSoftInputFromWindow(getWindowToken(), 0);
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_ENTER));
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_ENTER));
+
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void onSelectionChanged(int selStart, int selEnd) {
+ if (!mFromWebKit && mWebView != null) {
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
+ + " selEnd=" + selEnd);
+ }
+ mWebView.setSelection(selStart, selEnd);
+ }
+ }
+
+ @Override
+ protected void onTextChanged(CharSequence s,int start,int before,int count){
+ super.onTextChanged(s, start, before, count);
+ String postChange = s.toString();
+ // Prevent calls to setText from invoking onTextChanged (since this will
+ // mean we are on a different textfield). Also prevent the change when
+ // going from a textfield with a string of text to one with a smaller
+ // limit on text length from registering the onTextChanged event.
+ if (mPreChange == null || mPreChange.equals(postChange) ||
+ (mMaxLength > -1 && mPreChange.length() > mMaxLength &&
+ mPreChange.substring(0, mMaxLength).equals(postChange))) {
+ return;
+ }
+ mPreChange = postChange;
+ // This was simply a delete or a cut, so just delete the selection.
+ if (before > 0 && 0 == count) {
+ mWebView.deleteSelection(start, start + before);
+ // For this and all changes to the text, update our cache
+ updateCachedTextfield();
+ return;
+ }
+ // Find the last character being replaced. If it can be represented by
+ // events, we will pass them to native (after replacing the beginning
+ // of the changed text), so we can see javascript events.
+ // Otherwise, replace the text being changed (including the last
+ // character) in the textfield.
+ TextUtils.getChars(s, start + count - 1, start + count, mCharacter, 0);
+ KeyCharacterMap kmap =
+ KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
+ KeyEvent[] events = kmap.getEvents(mCharacter);
+ boolean cannotUseKeyEvents = null == events;
+ int charactersFromKeyEvents = cannotUseKeyEvents ? 0 : 1;
+ if (count > 1 || cannotUseKeyEvents) {
+ String replace = s.subSequence(start,
+ start + count - charactersFromKeyEvents).toString();
+ mWebView.replaceTextfieldText(start, start + before, replace,
+ start + count - charactersFromKeyEvents,
+ start + count - charactersFromKeyEvents);
+ } else {
+ // This corrects the selection which may have been affected by the
+ // trackball or auto-correct.
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "onTextChanged start=" + start
+ + " start + before=" + (start + before));
+ }
+ mWebView.setSelection(start, start + before);
+ }
+ if (!cannotUseKeyEvents) {
+ int length = events.length;
+ for (int i = 0; i < length; i++) {
+ // We never send modifier keys to native code so don't send them
+ // here either.
+ if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
+ sendDomEvent(events[i]);
+ }
+ }
+ }
+ updateCachedTextfield();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ super.onTouchEvent(event);
+ // This event may be the start of a drag, so store it to pass to the
+ // WebView if it is.
+ mDragStartX = event.getX();
+ mDragStartY = event.getY();
+ mDragStartTime = event.getEventTime();
+ mDragSent = false;
+ mScrolled = false;
+ mGotTouchDown = true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ Spannable buffer = getText();
+ int initialScrollX = Touch.getInitialScrollX(this, buffer);
+ int initialScrollY = Touch.getInitialScrollY(this, buffer);
+ super.onTouchEvent(event);
+ if (mScrollX != initialScrollX
+ || mScrollY != initialScrollY) {
+ if (mWebView != null) {
+ mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
+ }
+ mScrolled = true;
+ return true;
+ }
+ if (mWebView != null) {
+ // Only want to set the initial state once.
+ if (!mDragSent) {
+ mWebView.initiateTextFieldDrag(mDragStartX, mDragStartY,
+ mDragStartTime);
+ mDragSent = true;
+ }
+ boolean scrolled = mWebView.textFieldDrag(event);
+ if (scrolled) {
+ mScrolled = true;
+ cancelLongPress();
+ return true;
+ }
+ }
+ return false;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (!mScrolled) {
+ // If the page scrolled, or the TextView scrolled, we do not
+ // want to change the selection
+ cancelLongPress();
+ if (mGotTouchDown && mWebView != null) {
+ mWebView.touchUpOnTextField(event);
+ }
+ }
+ // Necessary for the WebView to reset its state
+ if (mWebView != null && mDragSent) {
+ mWebView.onTouchEvent(event);
+ }
+ mGotTouchDown = false;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ if (isPopupShowing()) {
+ return super.onTrackballEvent(event);
+ }
+ if (event.getAction() != MotionEvent.ACTION_MOVE) {
+ return false;
+ }
+ // If the Cursor is not on the text input, webview should handle the
+ // trackball
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return mWebView.onTrackballEvent(event);
+ }
+ Spannable text = (Spannable) getText();
+ MovementMethod move = getMovementMethod();
+ if (move != null && getLayout() != null &&
+ move.onTrackballEvent(this, text, event)) {
+ // Selection is changed in onSelectionChanged
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove this WebTextView from its host WebView, and return
+ * focus to the host.
+ */
+ /* package */ void remove() {
+ // hide the soft keyboard when the edit text is out of focus
+ InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
+ getWindowToken(), 0);
+ mWebView.removeView(this);
+ mWebView.requestFocus();
+ }
+
+ /* package */ void bringIntoView() {
+ if (getLayout() != null) {
+ bringPointIntoView(Selection.getSelectionEnd(getText()));
+ }
+ }
+
+ /**
+ * Send the DOM events for the specified event.
+ * @param event KeyEvent to be translated into a DOM event.
+ */
+ private void sendDomEvent(KeyEvent event) {
+ mWebView.passToJavaScript(getText().toString(), event);
+ }
+
+ /**
+ * Always use this instead of setAdapter, as this has features specific to
+ * the WebTextView.
+ */
+ public void setAdapterCustom(AutoCompleteAdapter adapter) {
+ if (adapter != null) {
+ setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
+ adapter.setTextView(this);
+ }
+ super.setAdapter(adapter);
+ }
+
+ /**
+ * This is a special version of ArrayAdapter which changes its text size
+ * to match the text size of its host TextView.
+ */
+ public static class AutoCompleteAdapter extends ArrayAdapter<String> {
+ private TextView mTextView;
+
+ public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
+ super(context, com.android.internal.R.layout
+ .search_dropdown_item_1line, entries);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView tv =
+ (TextView) super.getView(position, convertView, parent);
+ if (tv != null && mTextView != null) {
+ tv.setTextSize(mTextView.getTextSize());
+ }
+ return tv;
+ }
+
+ /**
+ * Set the TextView so we can match its text size.
+ */
+ private void setTextView(TextView tv) {
+ mTextView = tv;
+ }
+ }
+
+ /**
+ * Determine whether to use the system-wide password disguising method,
+ * or to use none.
+ * @param inPassword True if the textfield is a password field.
+ */
+ /* package */ void setInPassword(boolean inPassword) {
+ if (inPassword) {
+ setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
+ TYPE_TEXT_VARIATION_PASSWORD);
+ createBackground();
+ }
+ // For password fields, draw the WebTextView. For others, just show
+ // webkit's drawing.
+ setWillNotDraw(!inPassword);
+ setBackgroundDrawable(inPassword ? mBackground : null);
+ // For non-password fields, avoid the invals from TextView's blinking
+ // cursor
+ setCursorVisible(inPassword);
+ }
+
+ /**
+ * Private class used for the background of a password textfield.
+ */
+ private static class OutlineDrawable extends Drawable {
+ public void draw(Canvas canvas) {
+ Rect bounds = getBounds();
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ // Draw the background.
+ paint.setColor(Color.WHITE);
+ canvas.drawRect(bounds, paint);
+ // Draw the outline.
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+ canvas.drawRect(bounds, paint);
+ }
+ // Always want it to be opaque.
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+ // These are needed because they are abstract in Drawable.
+ public void setAlpha(int alpha) { }
+ public void setColorFilter(ColorFilter cf) { }
+ }
+
+ /**
+ * Create a background for the WebTextView and set up the paint for drawing
+ * the text. This way, we can see the password transformation of the
+ * system, which (optionally) shows the actual text before changing to dots.
+ * The background is necessary to hide the webkit-drawn text beneath.
+ */
+ private void createBackground() {
+ if (mBackground != null) {
+ return;
+ }
+ mBackground = new OutlineDrawable();
+
+ setGravity(Gravity.CENTER_VERTICAL);
+ // Turn on subpixel text, and turn off kerning, so it better matches
+ // the text in webkit.
+ TextPaint paint = getPaint();
+ int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
+ Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
+ paint.setFlags(flags);
+ // Set the text color to black, regardless of the theme. This ensures
+ // that other applications that use embedded WebViews will properly
+ // display the text in password textfields.
+ setTextColor(Color.BLACK);
+ }
+
+ /* package */ void setMaxLength(int maxLength) {
+ mMaxLength = maxLength;
+ if (-1 == maxLength) {
+ setFilters(NO_FILTERS);
+ } else {
+ setFilters(new InputFilter[] {
+ new InputFilter.LengthFilter(maxLength) });
+ }
+ }
+
+ /**
+ * Set the pointer for this node so it can be determined which node this
+ * WebTextView represents.
+ * @param ptr Integer representing the pointer to the node which this
+ * WebTextView represents.
+ */
+ /* package */ void setNodePointer(int ptr) {
+ mNodePointer = ptr;
+ }
+
+ /**
+ * Determine the position and size of WebTextView, and add it to the
+ * WebView's view heirarchy. All parameters are presumed to be in
+ * view coordinates. Also requests Focus and sets the cursor to not
+ * request to be in view.
+ * @param x x-position of the textfield.
+ * @param y y-position of the textfield.
+ * @param width width of the textfield.
+ * @param height height of the textfield.
+ */
+ /* package */ void setRect(int x, int y, int width, int height) {
+ LayoutParams lp = (LayoutParams) getLayoutParams();
+ if (null == lp) {
+ lp = new LayoutParams(width, height, x, y);
+ } else {
+ lp.x = x;
+ lp.y = y;
+ lp.width = width;
+ lp.height = height;
+ }
+ if (getParent() == null) {
+ mWebView.addView(this, lp);
+ } else {
+ setLayoutParams(lp);
+ }
+ // Set up a measure spec so a layout can always be recreated.
+ mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ requestFocus();
+ }
+
+ /**
+ * Set the selection, and disable our onSelectionChanged action.
+ */
+ /* package */ void setSelectionFromWebKit(int start, int end) {
+ mFromWebKit = true;
+ Selection.setSelection((Spannable) getText(), start, end);
+ mFromWebKit = false;
+ }
+
+ /**
+ * Set whether this is a single-line textfield or a multi-line textarea.
+ * Textfields scroll horizontally, and do not handle the enter key.
+ * Textareas behave oppositely.
+ * Do NOT call this after calling setInPassword(true). This will result in
+ * removing the password input type.
+ */
+ public void setSingleLine(boolean single) {
+ int inputType = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
+ if (single) {
+ int action = mWebView.nativeTextFieldAction();
+ switch (action) {
+ // Keep in sync with CachedRoot::ImeAction
+ case 0: // NEXT
+ setImeOptions(EditorInfo.IME_ACTION_NEXT);
+ break;
+ case 1: // GO
+ setImeOptions(EditorInfo.IME_ACTION_GO);
+ break;
+ case -1: // FAILURE
+ case 2: // DONE
+ setImeOptions(EditorInfo.IME_ACTION_DONE);
+ break;
+ }
+ } else {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+ | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
+ setImeOptions(EditorInfo.IME_ACTION_NONE);
+ }
+ mSingle = single;
+ setHorizontallyScrolling(single);
+ setInputType(inputType);
+ }
+
+ /**
+ * Set the text for this WebTextView, and set the selection to (start, end)
+ * @param text Text to go into this WebTextView.
+ * @param start Beginning of the selection.
+ * @param end End of the selection.
+ */
+ /* package */ void setText(CharSequence text, int start, int end) {
+ mPreChange = text.toString();
+ setText(text);
+ Spannable span = (Spannable) getText();
+ int length = span.length();
+ if (end > length) {
+ end = length;
+ }
+ if (start < 0) {
+ start = 0;
+ } else if (start > length) {
+ start = length;
+ }
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "setText start=" + start
+ + " end=" + end);
+ }
+ Selection.setSelection(span, start, end);
+ }
+
+ /**
+ * Set the text to the new string, but use the old selection, making sure
+ * to keep it within the new string.
+ * @param text The new text to place in the textfield.
+ */
+ /* package */ void setTextAndKeepSelection(String text) {
+ mPreChange = text.toString();
+ Editable edit = (Editable) getText();
+ edit.replace(0, edit.length(), text);
+ updateCachedTextfield();
+ }
+
+ /**
+ * Update the cache to reflect the current text.
+ */
+ /* package */ void updateCachedTextfield() {
+ mWebView.updateCachedTextfield(getText().toString());
+ }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6936435..f49aab1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -58,7 +58,7 @@
import android.view.ViewTreeObserver;
import android.view.animation.AlphaAnimation;
import android.view.inputmethod.InputMethodManager;
-import android.webkit.TextDialog.AutoCompleteAdapter;
+import android.webkit.WebTextView.AutoCompleteAdapter;
import android.webkit.WebViewCore.EventHub;
import android.widget.AbsoluteLayout;
import android.widget.Adapter;
@@ -80,11 +80,10 @@
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
/**
- * <p>A View that displays web pages. This class is the basis upon which you
+ * <p>A View that displays web pages. This class is the basis upon which you
* can roll your own web browser or simply display some online content within your Activity.
* It uses the WebKit rendering engine to display
* web pages and includes methods to navigate forward and backward
@@ -93,12 +92,109 @@
* {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
* (introduced in API version 3).
* <p>Note that, in order for your Activity to access the Internet and load web pages
- * in a WebView, you must add the <var>INTERNET</var> permissions to your
+ * in a WebView, you must add the <var>INTERNET</var> permissions to your
* Android Manifest file:</p>
* <pre><uses-permission android:name="android.permission.INTERNET" /></pre>
+ *
* <p>This must be a child of the <code><manifest></code> element.</p>
+ *
+ * <h3>Basic usage</h3>
+ *
+ * <p>By default, a WebView provides no browser-like widgets, does not
+ * enable JavaScript and errors will be ignored. If your goal is only
+ * to display some HTML as a part of your UI, this is probably fine;
+ * the user won't need to interact with the web page beyond reading
+ * it, and the web page won't need to interact with the user. If you
+ * actually want a fully blown web browser, then you probably want to
+ * invoke the Browser application with your URL rather than show it
+ * with a WebView. See {@link android.content.Intent} for more information.</p>
+ *
+ * <pre class="prettyprint">
+ * WebView webview = new WebView(this);
+ * setContentView(webview);
+ *
+ * // Simplest usage: note that an exception will NOT be thrown
+ * // if there is an error loading this page (see below).
+ * webview.loadUrl("http://slashdot.org/");
+ *
+ * // Of course you can also load from any string:
+ * String summary = "<html><body>You scored <b>192</b> points.</body></html>";
+ * webview.loadData(summary, "text/html", "utf-8");
+ * // ... although note that there are restrictions on what this HTML can do.
+ * // See the JavaDocs for loadData and loadDataWithBaseUrl for more info.
+ * </pre>
+ *
+ * <p>A WebView has several customization points where you can add your
+ * own behavior. These are:</p>
+ *
+ * <ul>
+ * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
+ * This class is called when something that might impact a
+ * browser UI happens, for instance, progress updates and
+ * JavaScript alerts are sent here.
+ * </li>
+ * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
+ * It will be called when things happen that impact the
+ * rendering of the content, eg, errors or form submissions. You
+ * can also intercept URL loading here.</li>
+ * <li>Via the {@link android.webkit.WebSettings} class, which contains
+ * miscellaneous configuration. </li>
+ * <li>With the {@link android.webkit.WebView#addJavascriptInterface} method.
+ * This lets you bind Java objects into the WebView so they can be
+ * controlled from the web pages JavaScript.</li>
+ * </ul>
+ *
+ * <p>Here's a more complicated example, showing error handling,
+ * settings, and progress notification:</p>
+ *
+ * <pre class="prettyprint">
+ * // Let's display the progress in the activity title bar, like the
+ * // browser app does.
+ * getWindow().requestFeature(Window.FEATURE_PROGRESS);
+ *
+ * webview.getSettings().setJavaScriptEnabled(true);
+ *
+ * final Activity activity = this;
+ * webview.setWebChromeClient(new WebChromeClient() {
+ * public void onProgressChanged(WebView view, int progress) {
+ * // Activities and WebViews measure progress with different scales.
+ * // The progress meter will automatically disappear when we reach 100%
+ * activity.setProgress(progress * 1000);
+ * }
+ * });
+ * webview.setWebViewClient(new WebViewClient() {
+ * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
+ * }
+ * });
+ *
+ * webview.loadUrl("http://slashdot.org/");
+ * </pre>
+ *
+ * <h3>Cookie and window management</h3>
+ *
+ * <p>For obvious security reasons, your application has its own
+ * cache, cookie store etc - it does not share the Browser
+ * applications data. Cookies are managed on a separate thread, so
+ * operations like index building don't block the UI
+ * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
+ * if you want to use cookies in your application.
+ * </p>
+ *
+ * <p>By default, requests by the HTML to open new windows are
+ * ignored. This is true whether they be opened by JavaScript or by
+ * the target attribute on a link. You can customize your
+ * WebChromeClient to provide your own behaviour for opening multiple windows,
+ * and render them in whatever manner you want.</p>
+ *
+ * <p>Standard behavior for an Activity is to be destroyed and
+ * recreated when the devices orientation is changed. This will cause
+ * the WebView to reload the current page. If you don't want that, you
+ * can set your Activity to handle the orientation and keyboardHidden
+ * changes, and then just leave the WebView alone. It'll automatically
+ * re-orient itself as appropriate.</p>
*/
-public class WebView extends AbsoluteLayout
+public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener {
@@ -108,62 +204,61 @@
// true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
private boolean mAutoRedraw;
- // keep debugging parameters near the top of the file
static final String LOGTAG = "webview";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
- private class ExtendedZoomControls extends FrameLayout {
+ private static class ExtendedZoomControls extends FrameLayout {
public ExtendedZoomControls(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
- mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
+ mPlusMinusZoomControls = (ZoomControls) findViewById(
+ com.android.internal.R.id.zoomControls);
mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
}
-
+
public void show(boolean showZoom, boolean canZoomOut) {
- mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
+ mPlusMinusZoomControls.setVisibility(
+ showZoom ? View.VISIBLE : View.GONE);
mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
fade(View.VISIBLE, 0.0f, 1.0f);
}
-
+
public void hide() {
fade(View.GONE, 1.0f, 0.0f);
}
-
+
private void fade(int visibility, float startAlpha, float endAlpha) {
AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
anim.setDuration(500);
startAnimation(anim);
setVisibility(visibility);
}
-
+
public void setIsZoomMagnifyEnabled(boolean isEnabled) {
mZoomMagnify.setEnabled(isEnabled);
}
-
+
public boolean hasFocus() {
- return mZoomControls.hasFocus() || mZoomMagnify.hasFocus();
+ return mPlusMinusZoomControls.hasFocus() || mZoomMagnify.hasFocus();
}
-
+
public void setOnZoomInClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomInClickListener(listener);
+ mPlusMinusZoomControls.setOnZoomInClickListener(listener);
}
-
+
public void setOnZoomOutClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomOutClickListener(listener);
+ mPlusMinusZoomControls.setOnZoomOutClickListener(listener);
}
-
+
public void setOnZoomMagnifyClickListener(OnClickListener listener) {
mZoomMagnify.setOnClickListener(listener);
}
- ZoomControls mZoomControls;
- ImageView mZoomMagnify;
+ ZoomControls mPlusMinusZoomControls;
+ ImageView mZoomMagnify;
}
-
+
/**
* Transportation object for returning WebView across thread boundaries.
*/
@@ -203,13 +298,13 @@
private WebViewCore mWebViewCore;
// Handler for dispatching UI messages.
/* package */ final Handler mPrivateHandler = new PrivateHandler();
- private TextDialog mTextEntry;
+ private WebTextView mWebTextView;
// Used to ignore changes to webkit text that arrives to the UI side after
// more key events.
private int mTextGeneration;
- // The list of loaded plugins.
- private static PluginList sPluginList;
+ // Used by WebViewCore to create child views.
+ /* package */ final ViewManager mViewManager;
/**
* Position of the last touch event.
@@ -229,9 +324,18 @@
/**
* The minimum elapsed time before sending another ACTION_MOVE event to
- * WebViewCore
+ * WebViewCore. This really should be tuned for each type of the devices.
+ * For example in Google Map api test case, it takes Dream device at least
+ * 150ms to do a full cycle in the WebViewCore by processing a touch event,
+ * triggering the layout and drawing the picture. While the same process
+ * takes 60+ms on the current high speed device. If we make
+ * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent
+ * to WebViewCore queue and the real layout and draw events will be pushed
+ * to further, which slows down the refresh rate. Choose 50 to favor the
+ * current high speed devices. For Dream like devices, 100 is a better
+ * choice. Maybe make this in the buildspec later.
*/
- private static final int TOUCH_SENT_INTERVAL = 100;
+ private static final int TOUCH_SENT_INTERVAL = 50;
/**
* Helper class to get velocity for fling
@@ -239,6 +343,9 @@
VelocityTracker mVelocityTracker;
private int mMaximumFling;
+ // use this flag to control whether enabling the new double tap zoom
+ static final boolean ENABLE_DOUBLETAP_ZOOM = true;
+
/**
* Touch mode
*/
@@ -258,6 +365,7 @@
private static final int SCROLL_ZOOM_OUT = 11;
private static final int LAST_SCROLL_ZOOM = 11;
// end of touch mode values specific to scale+scroll
+ private static final int TOUCH_DOUBLE_TAP_MODE = 12;
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
@@ -267,18 +375,23 @@
// take control of touch events unless it says no for touch down event.
private boolean mPreventDrag;
- // If updateTextEntry gets called while we are out of focus, use this
- // variable to remember to do it next time we gain focus.
- private boolean mNeedsUpdateTextEntry = false;
-
- // Whether or not to draw the focus ring.
- private boolean mDrawFocusRing = true;
+ // To keep track of whether the current drag was initiated by a WebTextView,
+ // so that we know not to hide the cursor
+ boolean mDragFromTextInput;
+
+ // Whether or not to draw the cursor ring.
+ private boolean mDrawCursorRing = true;
+
+ // true if onPause has been called (and not onResume)
+ private boolean mIsPaused;
/**
* Customizable constant
*/
// pre-computed square of ViewConfiguration.getScaledTouchSlop()
private int mTouchSlopSquare;
+ // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
+ private int mDoubleTapSlopSquare;
// pre-computed density adjusted navigation slop
private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
@@ -292,7 +405,7 @@
// needed to avoid flinging after a pause of no movement
private static final int MIN_FLING_TIME = 250;
// The time that the Zoom Controls are visible before fading away
- private static final long ZOOM_CONTROLS_TIMEOUT =
+ private static final long ZOOM_CONTROLS_TIMEOUT =
ViewConfiguration.getZoomControlsTimeout();
// The amount of content to overlap between two screens when going through
// pages with the space bar, in pixels.
@@ -313,7 +426,7 @@
private int mContentWidth; // cache of value from WebViewCore
private int mContentHeight; // cache of value from WebViewCore
- // Need to have the separate control for horizontal and vertical scrollbar
+ // Need to have the separate control for horizontal and vertical scrollbar
// style than the View's single scrollbar style
private boolean mOverlayHorizontalScrollbar = true;
private boolean mOverlayVerticalScrollbar = false;
@@ -328,51 +441,49 @@
private boolean mWrapContent;
- // true if we should call webcore to draw the content, false means we have
- // requested something but it isn't ready to draw yet.
- private WebViewCore.FocusData mFocusData;
/**
* Private message ids
*/
- private static final int REMEMBER_PASSWORD = 1;
- private static final int NEVER_REMEMBER_PASSWORD = 2;
- private static final int SWITCH_TO_SHORTPRESS = 3;
- private static final int SWITCH_TO_LONGPRESS = 4;
- private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
- private static final int SWITCH_TO_ENTER = 7;
- private static final int RESUME_WEBCORE_UPDATE = 8;
+ private static final int REMEMBER_PASSWORD = 1;
+ private static final int NEVER_REMEMBER_PASSWORD = 2;
+ private static final int SWITCH_TO_SHORTPRESS = 3;
+ private static final int SWITCH_TO_LONGPRESS = 4;
+ private static final int RELEASE_SINGLE_TAP = 5;
+ private static final int REQUEST_FORM_DATA = 6;
+ private static final int SWITCH_TO_CLICK = 7;
+ private static final int RESUME_WEBCORE_UPDATE = 8;
//! arg1=x, arg2=y
- static final int SCROLL_TO_MSG_ID = 10;
- static final int SCROLL_BY_MSG_ID = 11;
+ static final int SCROLL_TO_MSG_ID = 10;
+ static final int SCROLL_BY_MSG_ID = 11;
//! arg1=x, arg2=y
- static final int SPAWN_SCROLL_TO_MSG_ID = 12;
+ static final int SPAWN_SCROLL_TO_MSG_ID = 12;
//! arg1=x, arg2=y
- static final int SYNC_SCROLL_TO_MSG_ID = 13;
- static final int NEW_PICTURE_MSG_ID = 14;
- static final int UPDATE_TEXT_ENTRY_MSG_ID = 15;
- static final int WEBCORE_INITIALIZED_MSG_ID = 16;
- static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17;
- static final int DID_FIRST_LAYOUT_MSG_ID = 18;
- static final int RECOMPUTE_FOCUS_MSG_ID = 19;
- static final int NOTIFY_FOCUS_SET_MSG_ID = 20;
- static final int MARK_NODE_INVALID_ID = 21;
- static final int UPDATE_CLIPBOARD = 22;
- static final int LONG_PRESS_ENTER = 23;
- static final int PREVENT_TOUCH_ID = 24;
- static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
+ static final int SYNC_SCROLL_TO_MSG_ID = 13;
+ static final int NEW_PICTURE_MSG_ID = 14;
+ static final int UPDATE_TEXT_ENTRY_MSG_ID = 15;
+ static final int WEBCORE_INITIALIZED_MSG_ID = 16;
+ static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17;
+ static final int MOVE_OUT_OF_PLUGIN = 19;
+ static final int CLEAR_TEXT_ENTRY = 20;
+ static final int UPDATE_TEXT_SELECTION_MSG_ID = 21;
+ static final int UPDATE_CLIPBOARD = 22;
+ static final int LONG_PRESS_CENTER = 23;
+ static final int PREVENT_TOUCH_ID = 24;
+ static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
// obj=Rect in doc coordinates
- static final int INVAL_RECT_MSG_ID = 26;
-
+ static final int INVAL_RECT_MSG_ID = 26;
+ static final int REQUEST_KEYBOARD = 27;
+
static final String[] HandlerDebugString = {
- "REMEMBER_PASSWORD", // = 1;
- "NEVER_REMEMBER_PASSWORD", // = 2;
- "SWITCH_TO_SHORTPRESS", // = 3;
- "SWITCH_TO_LONGPRESS", // = 4;
- "5",
- "UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
- "SWITCH_TO_ENTER", // = 7;
- "RESUME_WEBCORE_UPDATE", // = 8;
+ "REMEMBER_PASSWORD", // = 1;
+ "NEVER_REMEMBER_PASSWORD", // = 2;
+ "SWITCH_TO_SHORTPRESS", // = 3;
+ "SWITCH_TO_LONGPRESS", // = 4;
+ "RELEASE_SINGLE_TAP", // = 5;
+ "REQUEST_FORM_DATA", // = 6;
+ "SWITCH_TO_CLICK", // = 7;
+ "RESUME_WEBCORE_UPDATE", // = 8;
"9",
"SCROLL_TO_MSG_ID", // = 10;
"SCROLL_BY_MSG_ID", // = 11;
@@ -382,31 +493,40 @@
"UPDATE_TEXT_ENTRY_MSG_ID", // = 15;
"WEBCORE_INITIALIZED_MSG_ID", // = 16;
"UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17;
- "DID_FIRST_LAYOUT_MSG_ID", // = 18;
- "RECOMPUTE_FOCUS_MSG_ID", // = 19;
- "NOTIFY_FOCUS_SET_MSG_ID", // = 20;
- "MARK_NODE_INVALID_ID", // = 21;
+ "18", // = 18;
+ "MOVE_OUT_OF_PLUGIN", // = 19;
+ "CLEAR_TEXT_ENTRY", // = 20;
+ "UPDATE_TEXT_SELECTION_MSG_ID", // = 21;
"UPDATE_CLIPBOARD", // = 22;
- "LONG_PRESS_ENTER", // = 23;
+ "LONG_PRESS_CENTER", // = 23;
"PREVENT_TOUCH_ID", // = 24;
"WEBCORE_NEED_TOUCH_EVENTS", // = 25;
- "INVAL_RECT_MSG_ID" // = 26;
+ "INVAL_RECT_MSG_ID", // = 26;
+ "REQUEST_KEYBOARD" // = 27;
};
- // width which view is considered to be fully zoomed out
- static final int ZOOM_OUT_WIDTH = 1008;
-
// default scale limit. Depending on the display density
private static float DEFAULT_MAX_ZOOM_SCALE;
private static float DEFAULT_MIN_ZOOM_SCALE;
// scale limit, which can be set through viewport meta tag in the web page
private float mMaxZoomScale;
private float mMinZoomScale;
- private boolean mMinZoomScaleFixed = false;
+ private boolean mMinZoomScaleFixed = true;
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // while in the zoom overview mode, the page's width is fully fit to the
+ // current window. The page is alive, in another words, you can click to
+ // follow the links. Double tap will toggle between zoom overview mode and
+ // the last zoom scale.
+ boolean mInZoomOverview = false;
+
+ // 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;
+ float mLastScale;
+
// default scale. Depending on the display density.
static int DEFAULT_SCALE_PERCENT;
private float mDefaultScale;
@@ -421,6 +541,8 @@
private float mZoomScale;
private float mInvInitialZoomScale;
private float mInvFinalZoomScale;
+ private int mInitialScrollX;
+ private int mInitialScrollY;
private long mZoomStart;
private static final int ZOOM_ANIMATION_LENGTH = 500;
@@ -433,7 +555,7 @@
private static final int SNAP_X_LOCK = 4;
private static final int SNAP_Y_LOCK = 5;
private boolean mSnapPositive;
-
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -456,7 +578,7 @@
* URI scheme for map address
*/
public static final String SCHEME_GEO = "geo:0,0?q=";
-
+
private int mBackgroundColor = Color.WHITE;
// Used to notify listeners of a new picture.
@@ -473,7 +595,8 @@
public void onNewPicture(WebView view, Picture picture);
}
- public class HitTestResult {
+ // FIXME: Want to make this public, but need to change the API file.
+ public /*static*/ class HitTestResult {
/**
* Default HitTestResult, where the target is unknown
*/
@@ -543,8 +666,7 @@
private ExtendedZoomControls mZoomControls;
private Runnable mZoomControlRunnable;
- private ZoomButtonsController mZoomButtonsController;
- private ImageView mZoomOverviewButton;
+ private ZoomButtonsController mZoomButtonsController;
// These keep track of the center point of the zoom. They are used to
// determine the point around which we should zoom.
@@ -567,11 +689,11 @@
} else {
zoomOut();
}
-
+
updateZoomButtonsEnabled();
}
};
-
+
/**
* Construct a new WebView with a Context object.
* @param context A Context object used to access application assets.
@@ -602,18 +724,10 @@
mCallbackProxy = new CallbackProxy(context, this);
mWebViewCore = new WebViewCore(context, this, mCallbackProxy);
mDatabase = WebViewDatabase.getInstance(context);
- mFocusData = new WebViewCore.FocusData();
- mFocusData.mFrame = 0;
- mFocusData.mNode = 0;
- mFocusData.mX = 0;
- mFocusData.mY = 0;
mScroller = new Scroller(context);
- initZoomController(context);
- }
+ mViewManager = new ViewManager(this);
- private void initZoomController(Context context) {
- // Create the buttons controller
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setOnZoomListener(mZoomListener);
// ZoomButtonsController positions the buttons at the bottom, but in
@@ -626,30 +740,11 @@
params;
frameParams.gravity = Gravity.RIGHT;
}
-
- // Create the accessory buttons
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- ViewGroup container = mZoomButtonsController.getContainer();
- inflater.inflate(com.android.internal.R.layout.zoom_browser_accessory_buttons, container);
- mZoomOverviewButton =
- (ImageView) container.findViewById(com.android.internal.R.id.zoom_page_overview);
- mZoomOverviewButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- mZoomButtonsController.setVisible(false);
- zoomScrollOut();
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
- }
- }
- });
}
private void updateZoomButtonsEnabled() {
boolean canZoomIn = mActualScale < mMaxZoomScale;
- boolean canZoomOut = mActualScale > mMinZoomScale;
+ boolean canZoomOut = mActualScale > mMinZoomScale && !mInZoomOverview;
if (!canZoomIn && !canZoomOut) {
// Hide the zoom in and out buttons, as well as the fit to page
// button, if the page cannot zoom
@@ -663,8 +758,6 @@
mZoomButtonsController.setZoomInEnabled(canZoomIn);
mZoomButtonsController.setZoomOutEnabled(canZoomOut);
}
- mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
- View.GONE);
}
private void init() {
@@ -675,9 +768,11 @@
setLongClickable(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- final int slop = configuration.getScaledTouchSlop();
+ int slop = configuration.getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
+ slop = configuration.getScaledDoubleTapSlop();
+ mDoubleTapSlopSquare = slop * slop;
final float density = getContext().getResources().getDisplayMetrics().density;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
@@ -899,7 +994,7 @@
clearTextEntry();
if (mWebViewCore != null) {
// Set the handlers to null before destroying WebViewCore so no
- // more messages will be posted.
+ // more messages will be posted.
mCallbackProxy.setWebViewClient(null);
mCallbackProxy.setWebChromeClient(null);
// Tell WebViewCore to destroy itself
@@ -930,12 +1025,23 @@
/**
* If platform notifications are enabled, this should be called
- * from onPause() or onStop().
+ * from the Activity's onPause() or onStop().
*/
public static void disablePlatformNotifications() {
Network.disablePlatformNotifications();
}
-
+
+ /**
+ * Sets JavaScript engine flags.
+ *
+ * @param flags JS engine flags in a String
+ *
+ * @hide pending API solidification
+ */
+ public void setJsFlags(String flags) {
+ mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
+ }
+
/**
* Inform WebView of the network state. This is used to set
* the javascript property window.navigator.isOnline and
@@ -948,7 +1054,7 @@
}
/**
- * Save the state of this WebView used in
+ * Save the state of this WebView used in
* {@link android.app.Activity#onSaveInstanceState}. Please note that this
* method no longer stores the display data for this WebView. The previous
* behavior could potentially leak files if {@link #restoreState} was never
@@ -1026,6 +1132,9 @@
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
b.putFloat("scale", mActualScale);
+ if (mInZoomOverview) {
+ b.putFloat("lastScale", mLastScale);
+ }
return true;
}
return false;
@@ -1070,6 +1179,13 @@
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ float lastScale = b.getFloat("lastScale", -1.0f);
+ if (lastScale > 0) {
+ mInZoomOverview = true;
+ mLastScale = lastScale;
+ } else {
+ mInZoomOverview = false;
+ }
invalidate();
return true;
}
@@ -1079,10 +1195,10 @@
/**
* Restore the state of this WebView from the given map used in
- * {@link android.app.Activity#onRestoreInstanceState}. This method should
- * be called to restore the state of the WebView before using the object. If
- * it is called after the WebView has had a chance to build state (load
- * pages, create a back/forward list, etc.) there may be undesirable
+ * {@link android.app.Activity#onRestoreInstanceState}. This method should
+ * be called to restore the state of the WebView before using the object. If
+ * it is called after the WebView has had a chance to build state (load
+ * pages, create a back/forward list, etc.) there may be undesirable
* side-effects. Please note that this method no longer restores the
* display data for this WebView. See {@link #savePicture} and {@link
* #restorePicture} for saving and restoring the display data.
@@ -1143,6 +1259,9 @@
* @param url The url of the resource to load.
*/
public void loadUrl(String url) {
+ if (url == null) {
+ return;
+ }
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.LOAD_URL, url);
clearTextEntry();
@@ -1152,18 +1271,16 @@
* Load the url with postData using "POST" method into the WebView. If url
* is not a network url, it will be loaded with {link
* {@link #loadUrl(String)} instead.
- *
+ *
* @param url The url of the resource to load.
* @param postData The data will be passed to "POST" request.
- *
- * @hide pending API solidification
*/
public void postUrl(String url, byte[] postData) {
if (URLUtil.isNetworkUrl(url)) {
switchOutDrawHistory();
- HashMap arg = new HashMap();
- arg.put("url", url);
- arg.put("data", postData);
+ WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
+ arg.mUrl = url;
+ arg.mPostData = postData;
mWebViewCore.sendMessage(EventHub.POST_URL, arg);
clearTextEntry();
} else {
@@ -1197,7 +1314,7 @@
* able to access asset files. If the baseUrl is anything other than
* http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
* sub resources.
- *
+ *
* @param baseUrl Url to resolve relative paths with, if null defaults to
* "about:blank"
* @param data A String of data in the given encoding.
@@ -1208,18 +1325,18 @@
*/
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String failUrl) {
-
+
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
loadData(data, mimeType, encoding);
return;
}
switchOutDrawHistory();
- HashMap arg = new HashMap();
- arg.put("baseUrl", baseUrl);
- arg.put("data", data);
- arg.put("mimeType", mimeType);
- arg.put("encoding", encoding);
- arg.put("failUrl", failUrl);
+ WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
+ arg.mBaseUrl = baseUrl;
+ arg.mData = data;
+ arg.mMimeType = mimeType;
+ arg.mEncoding = encoding;
+ arg.mFailUrl = failUrl;
mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
clearTextEntry();
}
@@ -1329,7 +1446,7 @@
ignoreSnapshot ? 1 : 0);
}
}
-
+
private boolean extendScroll(int y) {
int finalY = mScroller.getFinalY();
int newY = pinLocY(finalY + y);
@@ -1338,7 +1455,7 @@
mScroller.extendDuration(computeDuration(0, y));
return true;
}
-
+
/**
* Scroll the contents of the view up by half the view size
* @param top true to jump to the top of the page
@@ -1348,7 +1465,7 @@
if (mNativeClass == 0) {
return false;
}
- nativeClearFocus(-1, -1);
+ nativeClearCursor(); // start next trackball movement from page edge
if (top) {
// go to the top of the document
return pinScrollTo(mScrollX, 0, true, 0);
@@ -1362,10 +1479,10 @@
y = -h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
-
+
/**
* Scroll the contents of the view down by half the page size
* @param bottom true to jump to bottom of page
@@ -1375,7 +1492,7 @@
if (mNativeClass == 0) {
return false;
}
- nativeClearFocus(-1, -1);
+ nativeClearCursor(); // start next trackball movement from page edge
if (bottom) {
return pinScrollTo(mScrollX, mContentHeight, true, 0);
}
@@ -1388,7 +1505,7 @@
y = h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
@@ -1401,7 +1518,7 @@
mContentHeight = 0;
mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
}
-
+
/**
* Return a new picture that captures the current display of the webview.
* This is a copy of the display, and will be unaffected if the webview
@@ -1412,7 +1529,7 @@
* bounds of the view.
*/
public Picture capturePicture() {
- if (null == mWebViewCore) return null; // check for out of memory tab
+ if (null == mWebViewCore) return null; // check for out of memory tab
return mWebViewCore.copyContentPicture();
}
@@ -1420,17 +1537,17 @@
* Return true if the browser is displaying a TextView for text input.
*/
private boolean inEditingMode() {
- return mTextEntry != null && mTextEntry.getParent() != null
- && mTextEntry.hasFocus();
+ return mWebTextView != null && mWebTextView.getParent() != null
+ && mWebTextView.hasFocus();
}
private void clearTextEntry() {
if (inEditingMode()) {
- mTextEntry.remove();
+ mWebTextView.remove();
}
}
- /**
+ /**
* Return the current scale of the WebView
* @return The current scale.
*/
@@ -1471,7 +1588,7 @@
}
/**
- * Return a HitTestResult based on the current focus node. If a HTML::a tag
+ * Return a HitTestResult based on the current cursor node. If a HTML::a tag
* is found and the anchor has a non-javascript url, the HitTestResult type
* is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
* anchor does not have a url or if it is a javascript url, the type will
@@ -1494,26 +1611,26 @@
}
HitTestResult result = new HitTestResult();
-
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
+ if (nativeHasCursorNode()) {
+ if (nativeCursorIsTextInput()) {
result.setType(HitTestResult.EDIT_TEXT_TYPE);
- } else if (node.mText != null) {
- String text = node.mText;
- if (text.startsWith(SCHEME_TEL)) {
- result.setType(HitTestResult.PHONE_TYPE);
- result.setExtra(text.substring(SCHEME_TEL.length()));
- } else if (text.startsWith(SCHEME_MAILTO)) {
- result.setType(HitTestResult.EMAIL_TYPE);
- result.setExtra(text.substring(SCHEME_MAILTO.length()));
- } else if (text.startsWith(SCHEME_GEO)) {
- result.setType(HitTestResult.GEO_TYPE);
- result.setExtra(URLDecoder.decode(text
- .substring(SCHEME_GEO.length())));
- } else if (node.mIsAnchor) {
- result.setType(HitTestResult.SRC_ANCHOR_TYPE);
- result.setExtra(text);
+ } else {
+ String text = nativeCursorText();
+ if (text != null) {
+ if (text.startsWith(SCHEME_TEL)) {
+ result.setType(HitTestResult.PHONE_TYPE);
+ result.setExtra(text.substring(SCHEME_TEL.length()));
+ } else if (text.startsWith(SCHEME_MAILTO)) {
+ result.setType(HitTestResult.EMAIL_TYPE);
+ result.setExtra(text.substring(SCHEME_MAILTO.length()));
+ } else if (text.startsWith(SCHEME_GEO)) {
+ result.setType(HitTestResult.GEO_TYPE);
+ result.setExtra(URLDecoder.decode(text
+ .substring(SCHEME_GEO.length())));
+ } else if (nativeCursorIsAnchor()) {
+ result.setType(HitTestResult.SRC_ANCHOR_TYPE);
+ result.setExtra(text);
+ }
}
}
}
@@ -1525,8 +1642,8 @@
int contentY = viewToContent((int) mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
- result.setType(type == HitTestResult.UNKNOWN_TYPE ?
- HitTestResult.IMAGE_TYPE :
+ result.setType(type == HitTestResult.UNKNOWN_TYPE ?
+ HitTestResult.IMAGE_TYPE :
HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
result.setExtra(text);
}
@@ -1538,31 +1655,29 @@
* Request the href of an anchor element due to getFocusNodePath returning
* "href." If hrefMsg is null, this method returns immediately and does not
* dispatch hrefMsg to its target.
- *
+ *
* @param hrefMsg This message will be dispatched with the result of the
* request as the data member with "url" as key. The result can
* be null.
*/
+ // FIXME: API change required to change the name of this function. We now
+ // look at the cursor node, and not the focus node. Also, what is
+ // getFocusNodePath?
public void requestFocusNodeHref(Message hrefMsg) {
if (hrefMsg == null || mNativeClass == 0) {
return;
}
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsAnchor) {
- // NOTE: We may already have the url of the anchor stored in
- // node.mText but it may be out of date or the caller may want
- // to know about javascript urls.
- mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
- node.mFramePointer, node.mNodePointer, hrefMsg);
- }
+ if (nativeCursorIsAnchor()) {
+ mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
+ nativeCursorFramePointer(), nativeCursorNodePointer(),
+ hrefMsg);
}
}
-
+
/**
* Request the url of the image last touched by the user. msg will be sent
* to its target with a String representing the url as its object.
- *
+ *
* @param msg This message will be dispatched with the result of the request
* as the data member with "url" as key. The result can be null.
*/
@@ -1606,7 +1721,7 @@
return Math.round(x * mInvActualScale);
}
- private int contentToView(int x) {
+ /*package*/ int contentToView(int x) {
return Math.round(x * mActualScale);
}
@@ -1637,7 +1752,7 @@
if ((w | h) == 0) {
return;
}
-
+
// don't abort a scroll animation if we didn't change anything
if (mContentWidth != w || mContentHeight != h) {
// record new dimensions
@@ -1697,7 +1812,10 @@
mActualScale = scale;
mInvActualScale = 1 / scale;
- // as we don't have animation for scaling, don't do animation
+ // Scale all the child views
+ mViewManager.scaleAll();
+
+ // as we don't have animation for scaling, don't do animation
// for scrolling, as it causes weird intermediate state
// pinScrollTo(Math.round(sx), Math.round(sy));
mScrollX = pinLocX(Math.round(sx));
@@ -1718,18 +1836,21 @@
private Rect sendOurVisibleRect() {
Rect rect = new Rect();
calcOurContentVisibleRect(rect);
- if (mFindIsUp) {
- rect.bottom -= viewToContent(FIND_HEIGHT);
- }
// Rect.equals() checks for null input.
if (!rect.equals(mLastVisibleRectSent)) {
+ Point pos = new Point(rect.left, rect.top);
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
- rect.left, rect.top);
+ nativeMoveGeneration(), 0, pos);
mLastVisibleRectSent = rect;
}
Rect globalRect = new Rect();
if (getGlobalVisibleRect(globalRect)
&& !globalRect.equals(mLastGlobalRect)) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "sendOurVisibleRect=(" + globalRect.left + ","
+ + globalRect.top + ",r=" + globalRect.right + ",b="
+ + globalRect.bottom);
+ }
// TODO: the global offset is only used by windowRect()
// in ChromeClientAndroid ; other clients such as touch
// and mouse events could return view + screen relative points.
@@ -1744,6 +1865,9 @@
Point p = new Point();
getGlobalVisibleRect(r, p);
r.offset(-p.x, -p.y);
+ if (mFindIsUp) {
+ r.bottom -= FIND_HEIGHT;
+ }
}
// Sets r to be our visible rectangle in content coordinates
@@ -1755,6 +1879,13 @@
r.bottom = viewToContent(r.bottom);
}
+ static class ViewSizeData {
+ int mWidth;
+ int mHeight;
+ int mTextWrapWidth;
+ float mScale;
+ }
+
/**
* Compute unzoomed width and height, and if they differ from the last
* values we sent, send them to webkit (to be used has new viewport)
@@ -1762,7 +1893,8 @@
* @return true if new values were sent
*/
private boolean sendViewSizeZoom() {
- int newWidth = Math.round(getViewWidth() * mInvActualScale);
+ int viewWidth = getViewWidth();
+ int newWidth = Math.round(viewWidth * mInvActualScale);
int newHeight = Math.round(getViewHeight() * mInvActualScale);
/*
* Because the native side may have already done a layout before the
@@ -1777,8 +1909,16 @@
}
// Avoid sending another message if the dimensions have not changed.
if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
- mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
- newWidth, newHeight, new Float(mActualScale));
+ ViewSizeData data = new ViewSizeData();
+ data.mWidth = newWidth;
+ data.mHeight = newHeight;
+ // while in zoom overview mode, the text are wrapped to the screen
+ // width matching mLastScale. So that we don't trigger re-flow while
+ // toggling between overview mode and normal mode.
+ data.mTextWrapWidth = mInZoomOverview ? Math.round(viewWidth
+ / mLastScale) : newWidth;
+ data.mScale = mActualScale;
+ mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
mLastWidthSent = newWidth;
mLastHeightSent = newHeight;
return true;
@@ -1821,10 +1961,10 @@
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getUrl() : null;
}
-
+
/**
- * Get the original url for the current page. This is not always the same
- * as the url passed to WebViewClient.onPageStarted because although the
+ * Get the original url for the current page. This is not always the same
+ * as the url passed to WebViewClient.onPageStarted because although the
* load for that url has begun, the current page may not have changed.
* Also, there may have been redirects resulting in a different url to that
* originally requested.
@@ -1856,13 +1996,22 @@
}
/**
+ * Get the touch icon url for the apple-touch-icon <link> element.
+ * @hide
+ */
+ public String getTouchIconUrl() {
+ WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
+ return h != null ? h.getTouchIconUrl() : null;
+ }
+
+ /**
* Get the progress for the current page.
* @return The progress for the current page between 0 and 100.
*/
public int getProgress() {
return mCallbackProxy.getProgress();
}
-
+
/**
* @return the height of the HTML content.
*/
@@ -1871,30 +2020,77 @@
}
/**
- * Pause all layout, parsing, and javascript timers. This can be useful if
- * the WebView is not visible or the application has been paused.
+ * Pause all layout, parsing, and javascript timers for all webviews. This
+ * is a global requests, not restricted to just this webview. This can be
+ * useful if the application has been paused.
*/
public void pauseTimers() {
mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
}
/**
- * Resume all layout, parsing, and javascript timers. This will resume
- * dispatching all timers.
+ * Resume all layout, parsing, and javascript timers for all webviews.
+ * This will resume dispatching all timers.
*/
public void resumeTimers() {
mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
}
/**
- * Clear the resource cache. This will cause resources to be re-downloaded
- * if accessed again.
- * <p>
- * Note: this really needs to be a static method as it clears cache for all
- * WebView. But we need mWebViewCore to send message to WebCore thread, so
- * we can't make this static.
+ * Call this to pause any extra processing associated with this view and
+ * its associated DOM/plugins/javascript/etc. For example, if the view is
+ * taken offscreen, this could be called to reduce unnecessary CPU and/or
+ * network traffic. When the view is again "active", call onResume().
+ *
+ * Note that this differs from pauseTimers(), which affects all views/DOMs
+ * @hide
+ */
+ public void onPause() {
+ if (!mIsPaused) {
+ mIsPaused = true;
+ mWebViewCore.sendMessage(EventHub.ON_PAUSE);
+ }
+ }
+
+ /**
+ * Call this to balanace a previous call to onPause()
+ * @hide
+ */
+ public void onResume() {
+ if (mIsPaused) {
+ mIsPaused = false;
+ mWebViewCore.sendMessage(EventHub.ON_RESUME);
+ }
+ }
+
+ /**
+ * Returns true if the view is paused, meaning onPause() was called. Calling
+ * onResume() sets the paused state back to false.
+ * @hide
+ */
+ public boolean isPaused() {
+ return mIsPaused;
+ }
+
+ /**
+ * Call this to inform the view that memory is low so that it can
+ * free any available memory.
+ * @hide
+ */
+ public void freeMemory() {
+ mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
+ }
+
+ /**
+ * Clear the resource cache. Note that the cache is per-application, so
+ * this will clear the cache for all WebViews used.
+ *
+ * @param includeDiskFiles If false, only the RAM cache is cleared.
*/
public void clearCache(boolean includeDiskFiles) {
+ // Note: this really needs to be a static method as it clears cache for all
+ // WebView. But we need mWebViewCore to send message to WebCore thread, so
+ // we can't make this static.
mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
includeDiskFiles ? 1 : 0, 0);
}
@@ -1906,7 +2102,7 @@
public void clearFormData() {
if (inEditingMode()) {
AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
+ mWebTextView.setAdapterCustom(adapter);
}
}
@@ -1940,7 +2136,7 @@
/*
* Highlight and scroll to the next occurance of String in findAll.
- * Wraps the page infinitely, and scrolls. Must be called after
+ * Wraps the page infinitely, and scrolls. Must be called after
* calling findAll.
*
* @param forward Direction to search.
@@ -1966,11 +2162,8 @@
// or not we draw the highlights for matches.
private boolean mFindIsUp;
- private native int nativeFindAll(String findLower, String findUpper);
- private native void nativeFindNext(boolean forward);
-
/**
- * Return the first substring consisting of the address of a physical
+ * Return the first substring consisting of the address of a physical
* location. Currently, only addresses in the United States are detected,
* and consist of:
* - a house number
@@ -1983,14 +2176,40 @@
* All names must be correctly capitalized, and the zip code, if present,
* must be valid for the state. The street type must be a standard USPS
* spelling or abbreviation. The state or territory must also be spelled
- * or abbreviated using USPS standards. The house number may not exceed
+ * or abbreviated using USPS standards. The house number may not exceed
* five digits.
* @param addr The string to search for addresses.
*
* @return the address, or if no address is found, return null.
*/
public static String findAddress(String addr) {
- return WebViewCore.nativeFindAddress(addr);
+ return findAddress(addr, false);
+ }
+
+ /**
+ * @hide
+ * Return the first substring consisting of the address of a physical
+ * location. Currently, only addresses in the United States are detected,
+ * and consist of:
+ * - a house number
+ * - a street name
+ * - a street type (Road, Circle, etc), either spelled out or abbreviated
+ * - a city name
+ * - a state or territory, either spelled out or two-letter abbr.
+ * - an optional 5 digit or 9 digit zip code.
+ *
+ * Names are optionally capitalized, and the zip code, if present,
+ * must be valid for the state. The street type must be a standard USPS
+ * spelling or abbreviation. The state or territory must also be spelled
+ * or abbreviated using USPS standards. The house number may not exceed
+ * five digits.
+ * @param addr The string to search for addresses.
+ * @param caseInsensitive addr Set to true to make search ignore case.
+ *
+ * @return the address, or if no address is found, return null.
+ */
+ public static String findAddress(String addr, boolean caseInsensitive) {
+ return WebViewCore.nativeFindAddress(addr, caseInsensitive);
}
/*
@@ -2075,13 +2294,13 @@
// Scale from content to view coordinates, and pin.
// Also called by jni webview.cpp
- private void setContentScrollBy(int cx, int cy, boolean animate) {
+ private boolean setContentScrollBy(int cx, int cy, boolean animate) {
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
// TODO: as we switchOutDrawHistory when trackball or navigation
// keys are hit, this should be safe. Right?
- return;
+ return false;
}
cx = contentToView(cx);
cy = contentToView(cy);
@@ -2098,11 +2317,9 @@
// FIXME: Why do we only scroll horizontally if there is no
// vertical scroll?
// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
- if (cy == 0 && cx != 0) {
- pinScrollBy(cx, 0, animate, 0);
- }
+ return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
} else {
- pinScrollBy(cx, cy, animate, 0);
+ return pinScrollBy(cx, cy, animate, 0);
}
}
@@ -2201,6 +2418,16 @@
}
/**
+ * Gets the chrome handler.
+ * @return the current WebChromeClient instance.
+ *
+ * @hide API council approval.
+ */
+ public WebChromeClient getWebChromeClient() {
+ return mCallbackProxy.getWebChromeClient();
+ }
+
+ /**
* Set the Picture listener. This is an interface used to receive
* notifications of a new Picture.
* @param listener An implementation of WebView.PictureListener.
@@ -2245,10 +2472,9 @@
* @param interfaceName The name to used to expose the class in Javascript
*/
public void addJavascriptInterface(Object obj, String interfaceName) {
- // Use Hashmap rather than Bundle as Bundles can't cope with Objects
- HashMap arg = new HashMap();
- arg.put("object", obj);
- arg.put("interfaceName", interfaceName);
+ WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
+ arg.mObject = obj;
+ arg.mInterfaceName = interfaceName;
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
}
@@ -2265,26 +2491,19 @@
/**
* Return the list of currently loaded plugins.
* @return The list of currently loaded plugins.
+ *
+ * @deprecated This was used for Gears, which has been deprecated.
*/
+ @Deprecated
public static synchronized PluginList getPluginList() {
- if (sPluginList == null) {
- sPluginList = new PluginList();
- }
- return sPluginList;
+ return null;
}
/**
- * Signal the WebCore thread to refresh its list of plugins. Use
- * this if the directory contents of one of the plugin directories
- * has been modified and needs its changes reflecting. May cause
- * plugin load and/or unload.
- * @param reloadOpenPages Set to true to reload all open pages.
+ * @deprecated This was used for Gears, which has been deprecated.
*/
- public void refreshPlugins(boolean reloadOpenPages) {
- if (mWebViewCore != null) {
- mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
- }
- }
+ @Deprecated
+ public void refreshPlugins(boolean reloadOpenPages) { }
//-------------------------------------------------------------------------
// Override View methods
@@ -2292,9 +2511,13 @@
@Override
protected void finalize() throws Throwable {
- destroy();
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
}
-
+
@Override
protected void onDraw(Canvas canvas) {
// if mNativeClass is 0, the WebView has been destroyed. Do nothing.
@@ -2303,7 +2526,7 @@
}
if (mWebViewCore.mEndScaleZoom) {
mWebViewCore.mEndScaleZoom = false;
- if (mTouchMode >= FIRST_SCROLL_ZOOM
+ if (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
@@ -2314,22 +2537,21 @@
if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
scrollZoomDraw(canvas);
} else {
- nativeRecomputeFocus();
// Update the buttons in the picture, so when we draw the picture
// to the screen, they are in the correct state.
// Tell the native side if user is a) touching the screen,
// b) pressing the trackball down, or c) pressing the enter key
- // If the focus is a button, we need to draw it in the pressed
+ // If the cursor is on a button, we need to draw it in the pressed
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
nativeRecordButtons(hasFocus() && hasWindowFocus(),
mTouchMode == TOUCH_SHORTPRESS_START_MODE
- || mTrackballDown || mGotEnterDown, false);
- drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
+ || mTrackballDown || mGotCenterDown, false);
+ drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
}
canvas.restoreToCount(sc);
-
+
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
@@ -2345,15 +2567,23 @@
@Override
public boolean performLongClick() {
+ if (mNativeClass != 0 && nativeCursorIsTextInput()) {
+ // Send the click so that the textfield is in focus
+ // FIXME: When we start respecting changes to the native textfield's
+ // selection, need to make sure that this does not change it.
+ mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
+ nativeCursorNodePointer());
+ rebuildWebTextView();
+ }
if (inEditingMode()) {
- return mTextEntry.performLongClick();
+ return mWebTextView.performLongClick();
} else {
return super.performLongClick();
}
}
- private void drawCoreAndFocusRing(Canvas canvas, int color,
- boolean drawFocus) {
+ private void drawCoreAndCursorRing(Canvas canvas, int color,
+ boolean drawCursorRing) {
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
@@ -2361,14 +2591,14 @@
}
boolean animateZoom = mZoomScale != 0;
- boolean animateScroll = !mScroller.isFinished()
+ boolean animateScroll = !mScroller.isFinished()
|| mVelocityTracker != null;
if (animateZoom) {
float zoomScale;
int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
if (interval < ZOOM_ANIMATION_LENGTH) {
float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
- zoomScale = 1.0f / (mInvInitialZoomScale
+ zoomScale = 1.0f / (mInvInitialZoomScale
+ (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
invalidate();
} else {
@@ -2376,24 +2606,15 @@
// set mZoomScale to be 0 as we have done animation
mZoomScale = 0;
}
- float scale = (mActualScale - zoomScale) * mInvActualScale;
- float tx = scale * (mZoomCenterX + mScrollX);
- float ty = scale * (mZoomCenterY + mScrollY);
-
- // this block pins the translate to "legal" bounds. This makes the
- // animation a bit non-obvious, but it means we won't pop when the
- // "real" zoom takes effect
- if (true) {
- // canvas.translate(mScrollX, mScrollY);
- tx -= mScrollX;
- ty -= mScrollY;
- tx = -pinLoc(-Math.round(tx), getViewWidth(), Math
- .round(mContentWidth * zoomScale));
- ty = -pinLoc(-Math.round(ty), getViewHeight(), Math
- .round(mContentHeight * zoomScale));
- tx += mScrollX;
- ty += mScrollY;
- }
+ float scale = zoomScale * mInvInitialZoomScale;
+ int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX)
+ - mZoomCenterX);
+ tx = -pinLoc(tx, getViewWidth(), Math.round(mContentWidth
+ * zoomScale)) + mScrollX;
+ int ty = Math.round(scale * (mInitialScrollY + mZoomCenterY)
+ - mZoomCenterY);
+ ty = -pinLoc(ty, getViewHeight(), Math.round(mContentHeight
+ * zoomScale)) + mScrollY;
canvas.translate(tx, ty);
canvas.scale(zoomScale, zoomScale);
} else {
@@ -2408,10 +2629,10 @@
if (mTouchSelection) {
nativeDrawSelectionRegion(canvas);
} else {
- nativeDrawSelection(canvas, mSelectX, mSelectY,
+ nativeDrawSelection(canvas, mSelectX, mSelectY,
mExtendSelection);
}
- } else if (drawFocus) {
+ } else if (drawCursorRing) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mTouchMode = TOUCH_SHORTPRESS_MODE;
HitTestResult hitTest = getHitTestResult();
@@ -2422,7 +2643,7 @@
LONG_PRESS_TIMEOUT);
}
}
- nativeDrawFocusRing(canvas);
+ nativeDrawCursorRing(canvas);
}
// When the FindDialog is up, only draw the matches if we are not in
// the process of scrolling them into view.
@@ -2431,14 +2652,12 @@
}
}
- private native void nativeDrawMatches(Canvas canvas);
-
private float scrollZoomGridScale(float invScale) {
- float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
+ float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
/ (float) SCROLL_ZOOM_GRID;
return 1.0f / griddedInvScale;
}
-
+
private float scrollZoomX(float scale) {
int width = getViewWidth();
float maxScrollZoomX = mContentWidth * scale - width;
@@ -2454,7 +2673,7 @@
return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
: maxScrollZoomY / 2);
}
-
+
private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) {
final float ADORNMENT_LEN = 16.0f;
float width = frame.width();
@@ -2475,13 +2694,13 @@
path.offset(frame.left, frame.top);
canvas.drawPath(path, paint);
}
-
- // Returns frame surrounding magified portion of screen while
+
+ // Returns frame surrounding magified portion of screen while
// scroll-zoom is enabled. The frame is also used to center the
// zoom-in zoom-out points at the start and end of the animation.
private Rect scrollZoomFrame(int width, int height, float halfScale) {
Rect scrollFrame = new Rect();
- scrollFrame.set(mZoomScrollX, mZoomScrollY,
+ scrollFrame.set(mZoomScrollX, mZoomScrollY,
mZoomScrollX + width, mZoomScrollY + height);
if (mContentWidth * mZoomScrollLimit < width) {
float scale = zoomFrameScaleX(width, halfScale, 1.0f);
@@ -2497,37 +2716,37 @@
}
return scrollFrame;
}
-
+
private float zoomFrameScaleX(int width, float halfScale, float noScale) {
// mContentWidth > width > mContentWidth * mZoomScrollLimit
if (mContentWidth <= width) {
return halfScale;
}
- float part = (width - mContentWidth * mZoomScrollLimit)
+ float part = (width - mContentWidth * mZoomScrollLimit)
/ (width * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
}
-
+
private float zoomFrameScaleY(int height, float halfScale, float noScale) {
if (mContentHeight <= height) {
return halfScale;
}
- float part = (height - mContentHeight * mZoomScrollLimit)
+ float part = (height - mContentHeight * mZoomScrollLimit)
/ (height * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
}
-
+
private float scrollZoomMagScale(float invScale) {
return (invScale * 2 + mInvActualScale) / 3;
}
-
+
private void scrollZoomDraw(Canvas canvas) {
- float invScale = mZoomScrollInvLimit;
+ float invScale = mZoomScrollInvLimit;
int elapsed = 0;
if (mTouchMode != SCROLL_ZOOM_OUT) {
- elapsed = (int) Math.min(System.currentTimeMillis()
+ elapsed = (int) Math.min(System.currentTimeMillis()
- mZoomScrollStart, SCROLL_ZOOM_DURATION);
- float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
+ float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
* elapsed / SCROLL_ZOOM_DURATION;
if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
invScale = mInvActualScale + transitionScale;
@@ -2545,21 +2764,23 @@
if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
- updateTextEntry();
- scrollTo((int) (scrollFrame.centerX() * mActualScale)
- - (width >> 1), (int) (scrollFrame.centerY()
+ rebuildWebTextView();
+ scrollTo((int) (scrollFrame.centerX() * mActualScale)
+ - (width >> 1), (int) (scrollFrame.centerY()
* mActualScale) - (height >> 1));
mTouchMode = TOUCH_DONE_MODE;
+ // Show all the child views once we are done.
+ mViewManager.showAll();
} else {
mTouchMode = SCROLL_ZOOM_OUT;
}
}
float newX = scrollZoomX(scale);
float newY = scrollZoomY(scale);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
+ ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
- + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
+ + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
+ scale);
}
canvas.translate(newX, newY);
@@ -2603,8 +2824,8 @@
}
canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
, mZoomScrollY + height * halfY);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
+ width + ", " + height + ") half=(" + halfX + ", "
+ halfY + ")");
}
@@ -2632,14 +2853,17 @@
, Math.max(0, (int) ((x - left) / scale)));
mZoomScrollY = Math.min(mContentHeight - height
, Math.max(0, (int) ((y - top) / scale)));
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left
+ ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", "
+ mZoomScrollY + ")" + " x=" + x + " y=" + y);
}
}
- private boolean canZoomScrollOut() {
+ /**
+ * @hide
+ */
+ public boolean canZoomScrollOut() {
if (mContentWidth == 0 || mContentHeight == 0) {
return false;
}
@@ -2649,7 +2873,7 @@
float y = (float) height / (float) mContentHeight;
mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y));
mZoomScrollInvLimit = 1.0f / mZoomScrollLimit;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "canZoomScrollOut"
+ " mInvActualScale=" + mInvActualScale
+ " mZoomScrollLimit=" + mZoomScrollLimit
@@ -2664,7 +2888,7 @@
return mContentWidth >= width * limit
|| mContentHeight >= height * limit;
}
-
+
private void startZoomScrollOut() {
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
@@ -2690,30 +2914,35 @@
mZoomScrollStart = System.currentTimeMillis();
Rect zoomFrame = scrollZoomFrame(width, height
, scrollZoomMagScale(mZoomScrollInvLimit));
- mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
+ mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
- (zoomFrame.width() >> 1));
- mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
+ mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
- (zoomFrame.height() >> 1));
scrollTo(0, 0); // triggers inval, starts animation
clearTextEntry();
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
+ mZoomScrollX + ", " + mZoomScrollY +")");
}
}
-
- private void zoomScrollOut() {
+
+ /**
+ * @hide
+ */
+ public void zoomScrollOut() {
if (canZoomScrollOut() == false) {
mTouchMode = TOUCH_DONE_MODE;
return;
}
+ // Hide the child views while in this mode.
+ mViewManager.hideAll();
startZoomScrollOut();
mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
invalidate();
}
private void moveZoomScrollWindow(float x, float y) {
- if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
+ if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
&& Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
return;
}
@@ -2725,12 +2954,12 @@
int height = getViewHeight();
int maxZoomX = mContentWidth - width;
if (maxZoomX > 0) {
- int maxScreenX = width - (int) Math.ceil(width
+ int maxScreenX = width - (int) Math.ceil(width
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-X"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow-X"
+ " maxScreenX=" + maxScreenX + " width=" + width
- + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
+ + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
}
x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
@@ -2738,12 +2967,12 @@
}
int maxZoomY = mContentHeight - height;
if (maxZoomY > 0) {
- int maxScreenY = height - (int) Math.ceil(height
+ int maxScreenY = height - (int) Math.ceil(height
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-Y"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow-Y"
+ " maxScreenY=" + maxScreenY + " height=" + height
- + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
+ + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
}
y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
@@ -2752,12 +2981,12 @@
if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
invalidate();
}
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow"
- + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
- + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
- + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
- + " last=("+mLastScrollX+", "+mLastScrollY+")"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow"
+ + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
+ + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
+ + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
+ + " last=("+mLastScrollX+", "+mLastScrollY+")"
+ " x=" + x + " y=" + y);
}
}
@@ -2802,7 +3031,7 @@
// Should only be called in UI thread
void switchOutDrawHistory() {
if (null == mWebViewCore) return; // CallbackProxy may trigger this
- if (mDrawHistory) {
+ if (mDrawHistory && mWebViewCore.pictureReady()) {
mDrawHistory = false;
invalidate();
int oldScrollX = mScrollX;
@@ -2818,72 +3047,29 @@
}
}
- /**
- * Class representing the node which is focused.
- */
- private class FocusNode {
- public FocusNode() {
- mBounds = new Rect();
- }
- // Only to be called by JNI
- private void setAll(boolean isTextField, boolean isTextArea, boolean
- isPassword, boolean isAnchor, boolean isRtlText, int maxLength,
- int textSize, int boundsX, int boundsY, int boundsRight, int
- boundsBottom, int nodePointer, int framePointer, String text,
- String name, int rootTextGeneration) {
- mIsTextField = isTextField;
- mIsTextArea = isTextArea;
- mIsPassword = isPassword;
- mIsAnchor = isAnchor;
- mIsRtlText = isRtlText;
-
- mMaxLength = maxLength;
- mTextSize = textSize;
-
- mBounds.set(boundsX, boundsY, boundsRight, boundsBottom);
-
-
- mNodePointer = nodePointer;
- mFramePointer = framePointer;
- mText = text;
- mName = name;
- mRootTextGeneration = rootTextGeneration;
- }
- public boolean mIsTextField;
- public boolean mIsTextArea;
- public boolean mIsPassword;
- public boolean mIsAnchor;
- public boolean mIsRtlText;
-
- public int mSelectionStart;
- public int mSelectionEnd;
- public int mMaxLength;
- public int mTextSize;
-
- public Rect mBounds;
-
- public int mNodePointer;
- public int mFramePointer;
- public String mText;
- public String mName;
- public int mRootTextGeneration;
+ WebViewCore.CursorData cursorData() {
+ WebViewCore.CursorData result = new WebViewCore.CursorData();
+ result.mMoveGeneration = nativeMoveGeneration();
+ result.mFrame = nativeCursorFramePointer();
+ Point position = nativeCursorPosition();
+ result.mX = position.x;
+ result.mY = position.y;
+ return result;
}
-
- // Warning: ONLY use mFocusNode AFTER calling nativeUpdateFocusNode(),
- // and ONLY if it returns true;
- private FocusNode mFocusNode = new FocusNode();
-
+
/**
* Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
+ * focus, or if start == end, silently fail. If start and end are out of
* order, swap them.
* @param start Beginning of selection to delete.
* @param end End of selection to delete.
*/
/* package */ void deleteSelection(int start, int end) {
mTextGeneration++;
- mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
+ WebViewCore.TextSelectionData data
+ = new WebViewCore.TextSelectionData(start, end);
+ mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
+ data);
}
/**
@@ -2893,119 +3079,138 @@
* @param end End of selection.
*/
/* package */ void setSelection(int start, int end) {
- mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
+ mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
}
// Called by JNI when a touch event puts a textfield into focus.
- private void displaySoftKeyboard() {
+ private void displaySoftKeyboard(boolean isTextView) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mTextEntry, 0);
- mTextEntry.enableScrollOnScreen(true);
- // Now we need to fake a touch event to place the cursor where the
- // user touched.
- AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
- mTextEntry.getLayoutParams();
- if (lp != null) {
- // Take the last touch and adjust for the location of the
- // TextDialog.
- float x = mLastTouchX + (float) (mScrollX - lp.x);
- float y = mLastTouchY + (float) (mScrollY - lp.y);
- mTextEntry.fakeTouchEvent(x, y);
+
+ if (isTextView) {
+ imm.showSoftInput(mWebTextView, 0);
+ // Now we need to fake a touch event to place the cursor where the
+ // user touched.
+ AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
+ mWebTextView.getLayoutParams();
+ if (lp != null) {
+ // Take the last touch and adjust for the location of the
+ // WebTextView.
+ float x = mLastTouchX + (float) (mScrollX - lp.x);
+ float y = mLastTouchY + (float) (mScrollY - lp.y);
+ mWebTextView.fakeTouchEvent(x, y);
+ }
+ if (mInZoomOverview) {
+ // if in zoom overview mode, call doDoubleTap() to bring it back
+ // to normal mode so that user can enter text.
+ doDoubleTap();
+ }
+ }
+ else { // used by plugins
+ imm.showSoftInput(this, 0);
}
}
- private void updateTextEntry() {
- if (mTextEntry == null) {
- mTextEntry = new TextDialog(mContext, WebView.this);
- // Initialize our generation number.
- mTextGeneration = 0;
- }
- // If we do not have focus, do nothing until we gain focus.
- if (!hasFocus() && !mTextEntry.hasFocus()
- || (mTouchMode >= FIRST_SCROLL_ZOOM
+ // Called by WebKit to instruct the UI to hide the keyboard
+ private void hideSoftKeyboard() {
+ InputMethodManager imm = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
+ }
+
+ /*
+ * This method checks the current focus and cursor and potentially rebuilds
+ * mWebTextView to have the appropriate properties, such as password,
+ * multiline, and what text it contains. It also removes it if necessary.
+ */
+ /* package */ void rebuildWebTextView() {
+ // If the WebView does not have focus, do nothing until it gains focus.
+ if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())
+ || (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM)) {
- mNeedsUpdateTextEntry = true;
return;
}
boolean alreadyThere = inEditingMode();
- if (0 == mNativeClass || !nativeUpdateFocusNode()) {
+ // inEditingMode can only return true if mWebTextView is non-null,
+ // so we can safely call remove() if (alreadyThere)
+ if (0 == mNativeClass || !nativeFocusCandidateIsTextInput()) {
if (alreadyThere) {
- mTextEntry.remove();
+ mWebTextView.remove();
}
return;
}
- FocusNode node = mFocusNode;
- if (!node.mIsTextField && !node.mIsTextArea) {
- if (alreadyThere) {
- mTextEntry.remove();
- }
- return;
+ // At this point, we know we have found an input field, so go ahead
+ // and create the WebTextView if necessary.
+ if (mWebTextView == null) {
+ mWebTextView = new WebTextView(mContext, WebView.this);
+ // Initialize our generation number.
+ mTextGeneration = 0;
}
- mTextEntry.setTextSize(contentToView(node.mTextSize));
- Rect visibleRect = sendOurVisibleRect();
+ mWebTextView.setTextSize(contentToView(nativeFocusCandidateTextSize()));
+ Rect visibleRect = new Rect();
+ calcOurContentVisibleRect(visibleRect);
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
// should be in content coordinates.
- if (!Rect.intersects(node.mBounds, visibleRect)) {
- // Node is not on screen, so do not bother.
- return;
+ Rect bounds = nativeFocusCandidateNodeBounds();
+ if (!Rect.intersects(bounds, visibleRect)) {
+ mWebTextView.bringIntoView();
}
- int x = node.mBounds.left;
- int y = node.mBounds.top;
- int width = node.mBounds.width();
- int height = node.mBounds.height();
- if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) {
+ String text = nativeFocusCandidateText();
+ int nodePointer = nativeFocusCandidatePointer();
+ if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) {
// It is possible that we have the same textfield, but it has moved,
// i.e. In the case of opening/closing the screen.
// In that case, we need to set the dimensions, but not the other
// aspects.
// We also need to restore the selection, which gets wrecked by
// calling setTextEntryRect.
- Spannable spannable = (Spannable) mTextEntry.getText();
+ Spannable spannable = (Spannable) mWebTextView.getText();
int start = Selection.getSelectionStart(spannable);
int end = Selection.getSelectionEnd(spannable);
- setTextEntryRect(x, y, width, height);
// If the text has been changed by webkit, update it. However, if
// there has been more UI text input, ignore it. We will receive
// another update when that text is recognized.
- if (node.mText != null && !node.mText.equals(spannable.toString())
- && node.mRootTextGeneration == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(node.mText);
+ if (text != null && !text.equals(spannable.toString())
+ && nativeTextGeneration() == mTextGeneration) {
+ mWebTextView.setTextAndKeepSelection(text);
} else {
Selection.setSelection(spannable, start, end);
}
} else {
- String text = node.mText;
- setTextEntryRect(x, y, width, height);
- mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT :
- Gravity.NO_GRAVITY);
+ Rect vBox = contentToView(bounds);
+ mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
+ vBox.height());
+ mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
+ Gravity.RIGHT : Gravity.NO_GRAVITY);
// this needs to be called before update adapter thread starts to
- // ensure the mTextEntry has the same node pointer
- mTextEntry.setNodePointer(node.mNodePointer);
+ // ensure the mWebTextView has the same node pointer
+ mWebTextView.setNodePointer(nodePointer);
int maxLength = -1;
- if (node.mIsTextField) {
- maxLength = node.mMaxLength;
+ boolean isTextField = nativeFocusCandidateIsTextField();
+ if (isTextField) {
+ maxLength = nativeFocusCandidateMaxLength();
+ String name = nativeFocusCandidateName();
if (mWebViewCore.getSettings().getSaveFormData()
- && node.mName != null) {
- HashMap data = new HashMap();
- data.put("text", node.mText);
+ && name != null) {
Message update = mPrivateHandler.obtainMessage(
- UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
- data);
- UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
- node.mName, getUrl(), update);
+ REQUEST_FORM_DATA, nodePointer);
+ RequestFormData updater = new RequestFormData(name,
+ getUrl(), update);
Thread t = new Thread(updater);
t.start();
}
}
- mTextEntry.setMaxLength(maxLength);
+ mWebTextView.setMaxLength(maxLength);
AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
- mTextEntry.setSingleLine(node.mIsTextField);
- mTextEntry.setInPassword(node.mIsPassword);
+ mWebTextView.setAdapterCustom(adapter);
+ mWebTextView.setSingleLine(isTextField);
+ mWebTextView.setInPassword(nativeFocusCandidateIsPassword());
if (null == text) {
- mTextEntry.setText("", 0, 0);
+ mWebTextView.setText("", 0, 0);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView null == text");
+ }
} else {
// Change to true to enable the old style behavior, where
// entering a textfield/textarea always set the selection to the
@@ -3016,24 +3221,35 @@
// textarea. Testing out a new behavior, where textfields set
// selection at the end, and textareas at the beginning.
if (false) {
- mTextEntry.setText(text, 0, text.length());
- } else if (node.mIsTextField) {
+ mWebTextView.setText(text, 0, text.length());
+ } else if (isTextField) {
int length = text.length();
- mTextEntry.setText(text, length, length);
+ mWebTextView.setText(text, length, length);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView length=" + length);
+ }
} else {
- mTextEntry.setText(text, 0, 0);
+ mWebTextView.setText(text, 0, 0);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView !isTextField");
+ }
}
}
- mTextEntry.requestFocus();
+ mWebTextView.requestFocus();
}
}
- private class UpdateTextEntryAdapter implements Runnable {
+ /*
+ * This class requests an Adapter for the WebTextView which shows past
+ * entries stored in the database. It is a Runnable so that it can be done
+ * in its own thread, without slowing down the UI.
+ */
+ private class RequestFormData implements Runnable {
private String mName;
private String mUrl;
private Message mUpdateMessage;
- public UpdateTextEntryAdapter(String name, String url, Message msg) {
+ public RequestFormData(String name, String url, Message msg) {
mName = name;
mUrl = url;
mUpdateMessage = msg;
@@ -3044,29 +3260,21 @@
if (pastEntries.size() > 0) {
AutoCompleteAdapter adapter = new
AutoCompleteAdapter(mContext, pastEntries);
- ((HashMap) mUpdateMessage.obj).put("adapter", adapter);
+ mUpdateMessage.obj = adapter;
mUpdateMessage.sendToTarget();
}
}
}
- private void setTextEntryRect(int x, int y, int width, int height) {
- x = contentToView(x);
- y = contentToView(y);
- width = contentToView(width);
- height = contentToView(height);
- mTextEntry.setRect(x, y, width, height);
- }
-
- // This is used to determine long press with the enter key, or
- // a center key. Does not affect long press with the trackball/touch.
- private boolean mGotEnterDown = false;
+ // This is used to determine long press with the center key. Does not
+ // affect long press with the trackball/touch.
+ private boolean mGotCenterDown = false;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
- + ", " + event);
+ + ", " + event + ", unicode=" + event.getUnicodeChar());
}
if (mNativeClass == 0) {
@@ -3092,29 +3300,27 @@
return false;
}
- if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false
- && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
+ if (mShiftIsPressed == false && nativeCursorWantsKeyEvents() == false
+ && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
mExtendSelection = false;
mShiftIsPressed = true;
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- mSelectX = contentToView(node.mBounds.left);
- mSelectY = contentToView(node.mBounds.top);
+ if (nativeHasCursorNode()) {
+ Rect rect = nativeCursorNodeBounds();
+ mSelectX = contentToView(rect.left);
+ mSelectY = contentToView(rect.top);
} else {
mSelectX = mScrollX + (int) mLastTouchX;
mSelectY = mScrollY + (int) mLastTouchY;
}
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
// always handle the navigation keys in the UI thread
switchOutDrawHistory();
- if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
+ if (navHandledKey(keyCode, 1, false, event.getEventTime(), false)) {
playSoundEffect(keyCodeToSoundsEffect(keyCode));
return true;
}
@@ -3122,13 +3328,12 @@
return false;
}
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
switchOutDrawHistory();
if (event.getRepeatCount() == 0) {
- mGotEnterDown = true;
+ mGotCenterDown = true;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
+ .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
// Already checked mNativeClass, so we do not need to check it
// again.
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
@@ -3138,6 +3343,15 @@
return false;
}
+ if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
+ && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) {
+ // turn off copy select if a shift-key combo is pressed
+ mExtendSelection = mShiftIsPressed = false;
+ if (mTouchMode == TOUCH_SELECT_MODE) {
+ mTouchMode = TOUCH_INIT_MODE;
+ }
+ }
+
if (getSettings().getNavDump()) {
switch (keyCode) {
case KeyEvent.KEYCODE_4:
@@ -3166,8 +3380,30 @@
}
}
+ if (nativeCursorIsPlugin()) {
+ nativeUpdatePluginReceivesEvents();
+ invalidate();
+ } else if (nativeCursorIsTextInput()) {
+ // This message will put the node in focus, for the DOM's notion
+ // of focus, and make the focuscontroller active
+ mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
+ nativeCursorNodePointer());
+ // This will bring up the WebTextView and put it in focus, for
+ // our view system's notion of focus
+ rebuildWebTextView();
+ // Now we need to pass the event to it
+ return mWebTextView.onKeyDown(keyCode, event);
+ } else if (nativeHasFocusNode()) {
+ // In this case, the cursor is not on a text input, but the focus
+ // might be. Check it, and if so, hand over to the WebTextView.
+ rebuildWebTextView();
+ if (inEditingMode()) {
+ return mWebTextView.onKeyDown(keyCode, event);
+ }
+ }
+
// TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
+ if (nativeCursorWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
// return true as DOM handles the key
@@ -3180,20 +3416,19 @@
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
- + ", " + event);
+ + ", " + event + ", unicode=" + event.getUnicodeChar());
}
if (mNativeClass == 0) {
return false;
}
- // special CALL handling when focus node's href is "tel:XXX"
- if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- String text = node.mText;
- if (!node.mIsTextField && !node.mIsTextArea && text != null
+ // special CALL handling when cursor node's href is "tel:XXX"
+ if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
+ String text = nativeCursorText();
+ if (!nativeCursorIsTextInput() && text != null
&& text.startsWith(SCHEME_TEL)) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
getContext().startActivity(intent);
@@ -3220,7 +3455,7 @@
return false;
}
- if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
+ if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
if (commitCopy()) {
return true;
@@ -3234,55 +3469,30 @@
return false;
}
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// remove the long press message first
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
- mGotEnterDown = false;
+ mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
+ mGotCenterDown = false;
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- if (mShiftIsPressed) {
- return false;
- }
- if (getSettings().supportZoom()) {
- if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- zoomScrollOut();
- } else {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
- }
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
- mTouchMode = TOUCH_DOUBLECLICK_MODE;
- }
- return true;
- }
+ if (mShiftIsPressed) {
+ return false;
}
-
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the
- // coordinates should be in content coordinates.
- if (nativeUpdateFocusNode()) {
- if (Rect.intersects(mFocusNode.mBounds, visibleRect)) {
- nativeSetFollowedLink(true);
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
- new WebViewCore.FocusData(mFocusData));
- playSoundEffect(SoundEffectConstants.CLICK);
- if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) {
- // use CLICK instead of KEY_DOWN/KEY_UP so that we can
- // trigger mouse click events
- mWebViewCore.sendMessage(EventHub.CLICK);
- }
+ if (getSettings().supportZoom()
+ && mTouchMode == TOUCH_DOUBLECLICK_MODE) {
+ zoomScrollOut();
+ } else {
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(SWITCH_TO_CLICK), TAP_TIMEOUT);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
}
- return true;
+ mTouchMode = TOUCH_DOUBLECLICK_MODE;
}
- // Bubble up the key event as WebView doesn't handle it
- return false;
+ return true;
}
// TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
+ if (nativeCursorWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_UP, event);
// return true as DOM handles the key
@@ -3292,16 +3502,14 @@
// Bubble up the key event as WebView doesn't handle it
return false;
}
-
+
/**
* @hide
*/
public void emulateShiftHeld() {
mExtendSelection = false;
mShiftIsPressed = true;
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
}
private boolean commitCopy() {
@@ -3349,16 +3557,13 @@
// Clean up the zoom controller
mZoomButtonsController.setVisible(false);
}
-
+
// Implementation for OnHierarchyChangeListener
public void onChildViewAdded(View parent, View child) {}
-
+
public void onChildViewRemoved(View p, View child) {
if (child == this) {
- if (inEditingMode()) {
- clearTextEntry();
- mNeedsUpdateTextEntry = true;
- }
+ clearTextEntry();
}
}
@@ -3371,26 +3576,25 @@
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
}
- // To avoid drawing the focus ring, and remove the TextView when our window
+ // To avoid drawing the cursor ring, and remove the TextView when our window
// loses focus.
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if (hasWindowFocus) {
if (hasFocus()) {
// If our window regained focus, and we have focus, then begin
- // drawing the focus ring, and restore the TextView if
- // necessary.
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- }
+ // drawing the cursor ring
+ mDrawCursorRing = true;
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
+ if (inEditingMode()) {
+ mWebViewCore.sendMessage(EventHub.SET_ACTIVE, 1, 0);
+ }
}
} else {
// If our window gained focus, but we do not have it, do not
- // draw the focus ring.
- mDrawFocusRing = false;
+ // draw the cursor ring.
+ mDrawCursorRing = false;
// We do not call nativeRecordButtons here because we assume
// that when we lost focus, or window focus, it got called with
// false for the first parameter
@@ -3399,39 +3603,49 @@
if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) {
/*
* The zoom controls come in their own window, so our window
- * loses focus. Our policy is to not draw the focus ring if
+ * loses focus. Our policy is to not draw the cursor ring if
* our window is not focused, but this is an exception since
* the user can still navigate the web page with the zoom
* controls showing.
*/
- // If our window has lost focus, stop drawing the focus ring
- mDrawFocusRing = false;
+ // If our window has lost focus, stop drawing the cursor ring
+ mDrawCursorRing = false;
}
mGotKeyDown = false;
mShiftIsPressed = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
+ setFocusControllerInactive();
}
invalidate();
super.onWindowFocusChanged(hasWindowFocus);
}
+ /*
+ * Pass a message to WebCore Thread, telling the WebCore::Page's
+ * FocusController to be "inactive" so that it will
+ * not draw the blinking cursor. It gets set to "active" to draw the cursor
+ * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
+ */
+ /* package */ void setFocusControllerInactive() {
+ // Do not need to also check whether mWebViewCore is null, because
+ // mNativeClass is only set if mWebViewCore is non null
+ if (mNativeClass == 0) return;
+ mWebViewCore.sendMessage(EventHub.SET_ACTIVE, 0, 0);
+ }
+
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
}
if (focused) {
// When we regain focus, if we have window focus, resume drawing
- // the focus ring, and add the TextView if necessary.
+ // the cursor ring
if (hasWindowFocus()) {
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- mNeedsUpdateTextEntry = false;
- }
+ mDrawCursorRing = true;
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
@@ -3442,12 +3656,13 @@
}
} else {
// When we lost focus, unless focus went to the TextView (which is
- // true if we are in editing mode), stop drawing the focus ring.
+ // true if we are in editing mode), stop drawing the cursor ring.
if (!inEditingMode()) {
- mDrawFocusRing = false;
+ mDrawCursorRing = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
+ setFocusControllerInactive();
}
mGotKeyDown = false;
}
@@ -3465,7 +3680,8 @@
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+ / (mDrawHistory ? mHistoryPicture.getWidth()
+ : mZoomOverviewWidth);
}
// we always force, in case our height changed, in which case we still
@@ -3476,10 +3692,11 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
+
sendOurVisibleRect();
}
-
-
+
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean dispatch = true;
@@ -3523,7 +3740,7 @@
return false;
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
+ mTouchMode);
}
@@ -3548,7 +3765,7 @@
if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
&& mTouchMode != SCROLL_ZOOM_ANIMATION_IN
&& mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
- && (action != MotionEvent.ACTION_MOVE ||
+ && (action != MotionEvent.ACTION_MOVE ||
eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
@@ -3579,22 +3796,34 @@
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
mTouchMode = TOUCH_SELECT_MODE;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
+ } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
+ mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+ if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
+ mTouchMode = TOUCH_DOUBLE_TAP_MODE;
+ } else {
+ // commit the short press action for the previous tap
+ doShortPress();
+ // continue, mTouchMode should be still TOUCH_INIT_MODE
+ }
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
+ mWebViewCore.sendMessage(
+ EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
}
// Trigger the link
- if (mTouchMode == TOUCH_INIT_MODE) {
+ if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3607,7 +3836,7 @@
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mTouchMode == TOUCH_DONE_MODE
+ if (mTouchMode == TOUCH_DONE_MODE
|| mTouchMode == SCROLL_ZOOM_ANIMATION_IN
|| mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
// no dragging during scroll zoom animation
@@ -3624,7 +3853,7 @@
if (mTouchMode == TOUCH_SELECT_MODE) {
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
@@ -3640,7 +3869,8 @@
if (mTouchMode == TOUCH_SHORTPRESS_MODE
|| mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- } else if (mTouchMode == TOUCH_INIT_MODE) {
+ } else if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
@@ -3657,22 +3887,14 @@
mTouchMode = TOUCH_DRAG_MODE;
WebViewCore.pauseUpdate(mWebViewCore);
- int contentX = viewToContent((int) x + mScrollX);
- int contentY = viewToContent((int) y + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
- // remove the zoom anchor if there is any
- if (mZoomScale != 0) {
- mWebViewCore
- .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
+ if (!mDragFromTextInput) {
+ nativeHideCursor();
}
WebSettings settings = getSettings();
if (settings.supportZoom()
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
- && (canZoomScrollOut() ||
+ && (canZoomScrollOut() ||
mMinZoomScale < mMaxZoomScale)) {
mZoomButtonsController.setVisible(true);
}
@@ -3698,7 +3920,7 @@
}
// reverse direction means lock in the snap mode
if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
- ((mSnapPositive &&
+ ((mSnapPositive &&
deltaX < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
deltaX > mMinLockSnapReverseDistance))) {
@@ -3712,9 +3934,9 @@
}
// reverse direction means lock in the snap mode
if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
- ((mSnapPositive &&
+ ((mSnapPositive &&
deltaY < -mMinLockSnapReverseDistance)
- || (!mSnapPositive &&
+ || (!mSnapPositive &&
deltaY > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_Y_LOCK;
}
@@ -3762,7 +3984,23 @@
case MotionEvent.ACTION_UP: {
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
+ case TOUCH_DOUBLE_TAP_MODE: // double tap
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ mTouchMode = TOUCH_DONE_MODE;
+ doDoubleTap();
+ break;
case TOUCH_INIT_MODE: // tap
+ if (ENABLE_DOUBLETAP_ZOOM) {
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ if (!mPreventDrag) {
+ mPrivateHandler.sendMessageDelayed(
+ mPrivateHandler.obtainMessage(
+ RELEASE_SINGLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+ break;
+ }
+ // fall through
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -3779,7 +4017,7 @@
// no action during scroll animation
break;
case SCROLL_ZOOM_OUT:
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT"
+ " eventTime - mLastTouchTime="
+ (eventTime - mLastTouchTime));
@@ -3837,18 +4075,13 @@
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mTouchMode = TOUCH_DONE_MODE;
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
break;
}
}
return true;
}
-
+
private long mTrackballFirstTime = 0;
private long mTrackballLastTime = 0;
private float mTrackballRemainsX = 0.0f;
@@ -3870,14 +4103,14 @@
private boolean mShiftIsPressed = false;
private boolean mTrackballDown = false;
private long mTrackballUpTime = 0;
- private long mLastFocusTime = 0;
- private Rect mLastFocusBounds;
+ private long mLastCursorTime = 0;
+ private Rect mLastCursorBounds;
// Set by default; BrowserActivity clears to interpret trackball data
- // directly for movement. Currently, the framework only passes
+ // directly for movement. Currently, the framework only passes
// arrow key events, not trackball events, from one child to the next
private boolean mMapTrackballToArrowKeys = true;
-
+
public void setMapTrackballToArrowKeys(boolean setMap) {
mMapTrackballToArrowKeys = setMap;
}
@@ -3895,26 +4128,27 @@
return true;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
+ mPrivateHandler.removeMessages(SWITCH_TO_CLICK);
mTrackballDown = true;
- if (mNativeClass != 0) {
- nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+ if (mNativeClass == 0) {
+ return false;
}
- if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
- && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
- nativeSelectBestAt(mLastFocusBounds);
+ nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+ if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
+ && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
+ nativeSelectBestAt(mLastCursorBounds);
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
- + " time=" + time
- + " mLastFocusTime=" + mLastFocusTime);
+ + " time=" + time
+ + " mLastCursorTime=" + mLastCursorTime);
}
if (isInTouchMode()) requestFocusFromTouch();
return false; // let common code in onKeyDown at it
- }
+ }
if (ev.getAction() == MotionEvent.ACTION_UP) {
- // LONG_PRESS_ENTER is set in common onKeyDown
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
+ // LONG_PRESS_CENTER is set in common onKeyDown
+ mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
mTrackballDown = false;
mTrackballUpTime = time;
if (mShiftIsPressed) {
@@ -3924,42 +4158,42 @@
mExtendSelection = true;
}
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
- + " time=" + time
+ + " time=" + time
);
}
return false; // let common code in onKeyUp at it
}
if (mMapTrackballToArrowKeys && mShiftIsPressed == false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
return false;
}
- // no move if we're still waiting on SWITCH_TO_ENTER timeout
+ // no move if we're still waiting on SWITCH_TO_CLICK timeout
if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
return true;
}
if (mTrackballDown) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent down quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
return true; // discard move if trackball is down
}
if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
return true;
}
// TODO: alternatively we can do panning as touch does
switchOutDrawHistory();
if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent time="
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "onTrackballEvent time="
+ time + " last=" + mTrackballLastTime);
}
mTrackballFirstTime = time;
mTrackballXMove = mTrackballYMove = 0;
}
mTrackballLastTime = time;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
}
mTrackballRemainsX += ev.getX();
@@ -3967,7 +4201,7 @@
doTrackball(time);
return true;
}
-
+
void moveSelection(float xRate, float yRate) {
if (mNativeClass == 0)
return;
@@ -3981,8 +4215,8 @@
, mSelectX));
mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
, mSelectY));
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveSelection"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveSelection"
+ " mSelectX=" + mSelectX
+ " mSelectY=" + mSelectY
+ " mScrollX=" + mScrollX
@@ -3994,10 +4228,10 @@
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), mExtendSelection);
int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
- : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
+ : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
- : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
+ : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
pinScrollBy(scrollX, scrollY, true, 0);
Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
@@ -4054,7 +4288,7 @@
if (elapsed == 0) {
elapsed = TRACKBALL_TIMEOUT;
}
- float xRate = mTrackballRemainsX * 1000 / elapsed;
+ float xRate = mTrackballRemainsX * 1000 / elapsed;
float yRate = mTrackballRemainsY * 1000 / elapsed;
if (mShiftIsPressed) {
moveSelection(xRate, yRate);
@@ -4064,7 +4298,7 @@
float ax = Math.abs(xRate);
float ay = Math.abs(yRate);
float maxA = Math.max(ax, ay);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
+ " xRate=" + xRate
+ " yRate=" + yRate
@@ -4081,9 +4315,9 @@
int maxWH = Math.max(width, height);
mZoomScrollX += scaleTrackballX(xRate, maxWH);
mZoomScrollY += scaleTrackballY(yRate, maxWH);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
- + " mZoomScrollX=" + mZoomScrollX
+ + " mZoomScrollX=" + mZoomScrollX
+ " mZoomScrollY=" + mZoomScrollY);
}
mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
@@ -4101,18 +4335,18 @@
int oldScrollX = mScrollX;
int oldScrollY = mScrollY;
if (count > 0) {
- int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
- KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
+ int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
+ KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
KeyEvent.KEYCODE_DPAD_RIGHT;
count = Math.min(count, TRACKBALL_MOVE_COUNT);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ " count=" + count
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
}
- if (navHandledKey(selectKeyCode, count, false, time)) {
+ if (navHandledKey(selectKeyCode, count, false, time, false)) {
playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
}
mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -4120,12 +4354,12 @@
if (count >= TRACKBALL_SCROLL_COUNT) {
int xMove = scaleTrackballX(xRate, width);
int yMove = scaleTrackballY(yRate, height);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball pinScrollBy"
+ " count=" + count
+ " xMove=" + xMove + " yMove=" + yMove
- + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
- + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
+ + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
+ + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
);
}
if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
@@ -4138,18 +4372,17 @@
pinScrollBy(xMove, yMove, true, 0);
}
mUserScroll = true;
- }
- mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
+ }
}
public void flingScroll(int vx, int vy) {
int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
-
+
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY);
invalidate();
}
-
+
private void doFling() {
if (mVelocityTracker == null) {
return;
@@ -4168,7 +4401,7 @@
vx = 0;
}
}
-
+
if (true /* EMG release: make our fling more like Maps' */) {
// maps cuts their velocity in half
vx = vx * 3 / 4;
@@ -4187,6 +4420,8 @@
private boolean zoomWithPreview(float scale) {
float oldScale = mActualScale;
+ mInitialScrollX = mScrollX;
+ mInitialScrollY = mScrollY;
// snap to DEFAULT_SCALE if it is close
if (scale > (mDefaultScale - 0.05) && scale < (mDefaultScale + 0.05)) {
@@ -4201,6 +4436,9 @@
mInvInitialZoomScale = 1.0f / oldScale;
mInvFinalZoomScale = 1.0f / mActualScale;
mZoomScale = mActualScale;
+ if (!mInZoomOverview) {
+ mLastScale = scale;
+ }
invalidate();
return true;
} else {
@@ -4229,7 +4467,7 @@
}
if (mZoomControls == null) {
mZoomControls = createZoomControls();
-
+
/*
* need to be set to VISIBLE first so that getMeasuredHeight() in
* {@link #onSizeChanged()} can return the measured value for proper
@@ -4238,7 +4476,7 @@
mZoomControls.setVisibility(View.VISIBLE);
mZoomControlRunnable = new Runnable() {
public void run() {
-
+
/* Don't dismiss the controls if the user has
* focus on them. Wait and check again later.
*/
@@ -4290,7 +4528,7 @@
/**
* Gets the {@link ZoomButtonsController} which can be used to add
* additional buttons to the zoom controls window.
- *
+ *
* @return The instance of {@link ZoomButtonsController} used by this class,
* or null if it is unavailable.
* @hide
@@ -4306,7 +4544,18 @@
public boolean zoomIn() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 1.25f);
+ // Center zooming to the center of the screen.
+ if (mInZoomOverview) {
+ // if in overview mode, bring it back to normal mode
+ mLastTouchX = getViewWidth() * .5f;
+ mLastTouchY = getViewHeight() * .5f;
+ doDoubleTap();
+ return true;
+ } else {
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ return zoomWithPreview(mActualScale * 1.25f);
+ }
}
/**
@@ -4316,7 +4565,18 @@
public boolean zoomOut() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 0.8f);
+ float scale = mActualScale * 0.8f;
+ if (scale < (mMinZoomScale + 0.1f) && WebView.ENABLE_DOUBLETAP_ZOOM
+ && mWebViewCore.getSettings().getUseWideViewPort()) {
+ // when zoom out to min scale, switch to overview mode
+ doDoubleTap();
+ return true;
+ } else {
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ return zoomWithPreview(scale);
+ }
}
private void updateSelection() {
@@ -4328,19 +4588,77 @@
int contentY = viewToContent((int) mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
- // If we were already focused on a textfield, update its cache.
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
nativeSelectBestAt(rect);
}
+ /**
+ * Scroll the focused text field/area to match the WebTextView
+ * @param x New x position of the WebTextView in view coordinates
+ * @param y New y position of the WebTextView in view coordinates
+ */
+ /*package*/ void scrollFocusedTextInput(int x, int y) {
+ if (!inEditingMode() || mWebViewCore == null) {
+ return;
+ }
+ mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContent(x),
+ viewToContent(y));
+ }
+
+ /**
+ * Set our starting point and time for a drag from the WebTextView.
+ */
+ /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) {
+ if (!inEditingMode()) {
+ return;
+ }
+ mLastTouchX = x + (float) (mWebTextView.getLeft() - mScrollX);
+ mLastTouchY = y + (float) (mWebTextView.getTop() - mScrollY);
+ mLastTouchTime = eventTime;
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE);
+ }
+ mSnapScrollMode = SNAP_NONE;
+ mVelocityTracker = VelocityTracker.obtain();
+ mTouchMode = TOUCH_DRAG_START_MODE;
+ }
+
+ /**
+ * Given a motion event from the WebTextView, set its location to our
+ * coordinates, and handle the event.
+ */
+ /*package*/ boolean textFieldDrag(MotionEvent event) {
+ if (!inEditingMode()) {
+ return false;
+ }
+ mDragFromTextInput = true;
+ event.offsetLocation((float) (mWebTextView.getLeft() - mScrollX),
+ (float) (mWebTextView.getTop() - mScrollY));
+ boolean result = onTouchEvent(event);
+ mDragFromTextInput = false;
+ return result;
+ }
+
+ /**
+ * Do a touch up from a WebTextView. This will be handled by webkit to
+ * change the selection.
+ * @param event MotionEvent in the WebTextView's coordinates.
+ */
+ /*package*/ void touchUpOnTextField(MotionEvent event) {
+ if (!inEditingMode()) {
+ return;
+ }
+ int x = viewToContent((int) event.getX() + mWebTextView.getLeft());
+ int y = viewToContent((int) event.getY() + mWebTextView.getTop());
+ nativeTextInputMotionUp(x, y);
+ }
+
/*package*/ void shortPressOnTextField() {
if (inEditingMode()) {
- View v = mTextEntry;
+ View v = mWebTextView;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- nativeMotionUp(x, y, mNavSlop, true);
+ nativeTextInputMotionUp(x, y);
}
}
@@ -4352,29 +4670,76 @@
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (nativeMotionUp(contentX, contentY, mNavSlop, true)) {
+ if (nativeMotionUp(contentX, contentY, mNavSlop)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
}
}
- if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
- && !mFocusNode.mIsTextArea) {
+ if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
playSoundEffect(SoundEffectConstants.CLICK);
}
}
+ private void doDoubleTap() {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
+ return;
+ }
+ mZoomCenterX = mLastTouchX;
+ mZoomCenterY = mLastTouchY;
+ mInZoomOverview = !mInZoomOverview;
+ mCallbackProxy.uiOnChangeViewingMode(mInZoomOverview);
+ // 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
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int left = nativeGetBlockLeftEdge(contentX, contentY, mActualScale);
+ if (left != NO_LEFTEDGE) {
+ // add a 5pt padding to the left edge. Re-calculate the zoom
+ // center so that the new scroll x will be on the left edge.
+ mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale
+ * mActualScale / (mLastScale - mActualScale);
+ }
+ zoomWithPreview(mLastScale);
+ }
+ }
+
// Called by JNI to handle a touch on a node representing an email address,
// address, or phone number
private void overrideLoading(String url) {
mCallbackProxy.uiOverrideUrlLoading(url);
}
+ // called by JNI
+ private void sendPluginState(int state) {
+ WebViewCore.PluginStateData psd = new WebViewCore.PluginStateData();
+ psd.mFrame = nativeCursorFramePointer();
+ psd.mNode = nativeCursorNodePointer();
+ psd.mState = state;
+ mWebViewCore.sendMessage(EventHub.PLUGIN_STATE, psd);
+ }
+
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
boolean result = false;
if (inEditingMode()) {
- result = mTextEntry.requestFocus(direction, previouslyFocusedRect);
+ result = mWebTextView.requestFocus(direction,
+ previouslyFocusedRect);
} else {
result = super.requestFocus(direction, previouslyFocusedRect);
if (mWebViewCore.getSettings().getNeedInitialFocus()) {
@@ -4398,8 +4763,8 @@
default:
return result;
}
- if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
- navHandledKey(fakeKeyDirection, 1, true, 0);
+ if (mNativeClass != 0 && !nativeHasCursorNode()) {
+ navHandledKey(fakeKeyDirection, 1, true, 0, true);
}
}
}
@@ -4467,14 +4832,19 @@
int scrollYDelta = 0;
- if (rect.bottom > screenBottom && rect.top > screenTop) {
- if (rect.height() > height) {
- scrollYDelta += (rect.top - screenTop);
+ if (rect.bottom > screenBottom) {
+ int oneThirdOfScreenHeight = height / 3;
+ if (rect.height() > 2 * oneThirdOfScreenHeight) {
+ // If the rectangle is too tall to fit in the bottom two thirds
+ // of the screen, place it at the top.
+ scrollYDelta = rect.top - screenTop;
} else {
- scrollYDelta += (rect.bottom - screenBottom);
+ // If the rectangle will still fit on screen, we want its
+ // top to be in the top third of the screen.
+ scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
}
} else if (rect.top < screenTop) {
- scrollYDelta -= (screenTop - rect.top);
+ scrollYDelta = rect.top - screenTop;
}
int width = getWidth() - getVerticalScrollbarWidth();
@@ -4499,33 +4869,35 @@
return false;
}
-
+
/* package */ void replaceTextfieldText(int oldStart, int oldEnd,
String replace, int newStart, int newEnd) {
- HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
- arg.put("replace", replace);
- arg.put("start", new Integer(newStart));
- arg.put("end", new Integer(newEnd));
+ WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData();
+ arg.mReplace = replace;
+ arg.mNewStart = newStart;
+ arg.mNewEnd = newEnd;
mTextGeneration++;
+ arg.mTextGeneration = mTextGeneration;
mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
}
/* package */ void passToJavaScript(String currentText, KeyEvent event) {
- HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
- arg.put("event", event);
- arg.put("currentText", currentText);
+ if (nativeCursorWantsKeyEvents() && !nativeCursorMatchesFocus()) {
+ mWebViewCore.sendMessage(EventHub.CLICK);
+ }
+ WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
+ arg.mEvent = event;
+ arg.mCurrentText = currentText;
// Increase our text generation number, and pass it to webcore thread
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
// WebKit's document state is not saved until about to leave the page.
- // To make sure the host application, like Browser, has the up to date
- // document state when it goes to background, we force to save the
+ // To make sure the host application, like Browser, has the up to date
+ // document state when it goes to background, we force to save the
// document state.
mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
- new WebViewCore.FocusData(mFocusData), 1000);
+ cursorData(), 1000);
}
/* package */ WebViewCore getWebViewCore() {
@@ -4543,9 +4915,9 @@
class PrivateHandler extends Handler {
@Override
public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
- > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
+ > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
: HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
}
switch (msg.what) {
@@ -4567,6 +4939,8 @@
if (mTouchMode == TOUCH_INIT_MODE) {
mTouchMode = TOUCH_SHORTPRESS_START_MODE;
updateSelection();
+ } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
+ mTouchMode = TOUCH_DONE_MODE;
}
break;
}
@@ -4574,23 +4948,49 @@
if (!mPreventDrag) {
mTouchMode = TOUCH_DONE_MODE;
performLongClick();
- updateTextEntry();
+ rebuildWebTextView();
}
break;
}
- case SWITCH_TO_ENTER:
- if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
+ case RELEASE_SINGLE_TAP: {
+ if (!mPreventDrag) {
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
+ }
+ break;
+ }
+ case SWITCH_TO_CLICK:
+ // The user clicked with the trackball, and did not click a
+ // second time, so perform the action of a trackball single
+ // click
mTouchMode = TOUCH_DONE_MODE;
- onKeyUp(KeyEvent.KEYCODE_ENTER
- , new KeyEvent(KeyEvent.ACTION_UP
- , KeyEvent.KEYCODE_ENTER));
+ Rect visibleRect = sendOurVisibleRect();
+ // Note that sendOurVisibleRect calls viewToContent, so the
+ // coordinates should be in content coordinates.
+ if (!nativeCursorIntersects(visibleRect)) {
+ break;
+ }
+ nativeSetFollowedLink(true);
+ nativeUpdatePluginReceivesEvents();
+ WebViewCore.CursorData data = cursorData();
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
+ playSoundEffect(SoundEffectConstants.CLICK);
+ boolean isTextInput = nativeCursorIsTextInput();
+ if (isTextInput || !mCallbackProxy.uiOverrideUrlLoading(
+ nativeCursorText())) {
+ mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
+ nativeCursorNodePointer());
+ }
+ if (isTextInput) {
+ rebuildWebTextView();
+ }
break;
case SCROLL_BY_MSG_ID:
setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
break;
case SYNC_SCROLL_TO_MSG_ID:
if (mUserScroll) {
- // if user has scrolled explicitly, don't sync the
+ // if user has scrolled explicitly, don't sync the
// scroll position any more
mUserScroll = false;
break;
@@ -4599,7 +4999,7 @@
case SCROLL_TO_MSG_ID:
if (setContentScrollTo(msg.arg1, msg.arg2)) {
// if we can't scroll to the exact position due to pin,
- // send a message to WebCore to re-scroll when we get a
+ // send a message to WebCore to re-scroll when we get a
// new picture
mUserScroll = false;
mWebViewCore.sendMessage(EventHub.SYNC_SCROLL,
@@ -4609,24 +5009,50 @@
case SPAWN_SCROLL_TO_MSG_ID:
spawnContentScrollTo(msg.arg1, msg.arg2);
break;
- case NEW_PICTURE_MSG_ID:
+ case NEW_PICTURE_MSG_ID: {
+ WebSettings settings = mWebViewCore.getSettings();
// called for new content
- final WebViewCore.DrawData draw =
+ final int viewWidth = getViewWidth();
+ final WebViewCore.DrawData draw =
(WebViewCore.DrawData) msg.obj;
final Point viewSize = draw.mViewPoint;
- if (mZoomScale > 0) {
- // use the same logic in sendViewSizeZoom() to make sure
- // the mZoomScale has matched the viewSize so that we
- // can clear mZoomScale
- if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
- mZoomScale = 0;
- mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
- 0, 0);
+ boolean useWideViewport = settings.getUseWideViewPort();
+ WebViewCore.RestoreState restoreState = draw.mRestoreState;
+ if (restoreState != null) {
+ mInZoomOverview = false;
+ mLastScale = restoreState.mTextWrapScale;
+ if (restoreState.mMinScale == 0) {
+ mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mMinZoomScaleFixed = false;
+ } else {
+ mMinZoomScale = restoreState.mMinScale;
+ mMinZoomScaleFixed = true;
}
- }
- if (!mMinZoomScaleFixed) {
- mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
+ if (restoreState.mMaxScale == 0) {
+ mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+ } else {
+ mMaxZoomScale = restoreState.mMaxScale;
+ }
+ if (useWideViewport && restoreState.mViewScale == 0) {
+ mInZoomOverview = ENABLE_DOUBLETAP_ZOOM
+ && settings.getLoadWithOverviewMode();
+ }
+ mCallbackProxy.uiOnChangeViewingMode(true);
+ if (!mInZoomOverview) {
+ // We are going to start zoomed in. However, we
+ // truly want to show the title bar, and then hide
+ // it once the page has loaded
+ mCallbackProxy.uiChangeViewingModeOnFinishedLoad(
+ false, getOriginalUrl());
+ }
+ setNewZoomScale(mLastScale, false);
+ setContentScrollTo(restoreState.mScrollX,
+ restoreState.mScrollY);
+ // 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
+ // the WebTextView was visible.
+ clearTextEntry();
}
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
@@ -4634,9 +5060,9 @@
// received in the fixed dimension.
final boolean updateLayout = viewSize.x == mLastWidthSent
&& viewSize.y == mLastHeightSent;
- recordNewContentSize(draw.mWidthHeight.x,
+ recordNewContentSize(draw.mWidthHeight.x,
draw.mWidthHeight.y, updateLayout);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Rect b = draw.mInvalRegion.getBounds();
Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
b.left+","+b.top+","+b.right+","+b.bottom+"}");
@@ -4645,114 +5071,76 @@
if (mPictureListener != null) {
mPictureListener.onNewPicture(WebView.this, capturePicture());
}
+ if (useWideViewport) {
+ mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
+ draw.mViewPoint.x);
+ }
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
+ }
+ if (!mDrawHistory && mInZoomOverview) {
+ // fit the content width to the current view. Ignore
+ // the rounding error case.
+ if (Math.abs((viewWidth * mInvActualScale)
+ - mZoomOverviewWidth) > 1) {
+ setNewZoomScale((float) viewWidth
+ / mZoomOverviewWidth, false);
+ }
+ }
break;
+ }
case WEBCORE_INITIALIZED_MSG_ID:
// nativeCreate sets mNativeClass to a non-zero value
nativeCreate(msg.arg1);
break;
case UPDATE_TEXTFIELD_TEXT_MSG_ID:
// Make sure that the textfield is currently focused
- // and representing the same node as the pointer.
- if (inEditingMode() &&
- mTextEntry.isSameTextField(msg.arg1)) {
+ // and representing the same node as the pointer.
+ if (inEditingMode() &&
+ mWebTextView.isSameTextField(msg.arg1)) {
if (msg.getData().getBoolean("password")) {
- Spannable text = (Spannable) mTextEntry.getText();
+ Spannable text = (Spannable) mWebTextView.getText();
int start = Selection.getSelectionStart(text);
int end = Selection.getSelectionEnd(text);
- mTextEntry.setInPassword(true);
+ mWebTextView.setInPassword(true);
// Restore the selection, which may have been
// ruined by setInPassword.
- Spannable pword = (Spannable) mTextEntry.getText();
+ Spannable pword =
+ (Spannable) mWebTextView.getText();
Selection.setSelection(pword, start, end);
// If the text entry has created more events, ignore
// this one.
} else if (msg.arg2 == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(
+ mWebTextView.setTextAndKeepSelection(
(String) msg.obj);
}
}
break;
- case DID_FIRST_LAYOUT_MSG_ID:
- if (mNativeClass == 0) {
- break;
+ case UPDATE_TEXT_SELECTION_MSG_ID:
+ if (inEditingMode()
+ && mWebTextView.isSameTextField(msg.arg1)
+ && msg.arg2 == mTextGeneration) {
+ WebViewCore.TextSelectionData tData
+ = (WebViewCore.TextSelectionData) msg.obj;
+ mWebTextView.setSelectionFromWebKit(tData.mStart,
+ tData.mEnd);
}
-// Do not reset the focus or clear the text; the user may have already
-// navigated or entered text at this point. The focus should have gotten
-// reset, if need be, when the focus cache was built. Similarly, the text
-// view should already be torn down and rebuilt if needed.
-// nativeResetFocus();
-// clearTextEntry();
- HashMap scaleLimit = (HashMap) msg.obj;
- int minScale = (Integer) scaleLimit.get("minScale");
- if (minScale == 0) {
- mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
- mMinZoomScaleFixed = false;
- } else {
- mMinZoomScale = (float) (minScale / 100.0);
- mMinZoomScaleFixed = true;
- }
- int maxScale = (Integer) scaleLimit.get("maxScale");
- if (maxScale == 0) {
- mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- } else {
- mMaxZoomScale = (float) (maxScale / 100.0);
- }
- // If history Picture is drawn, don't update zoomWidth
- if (mDrawHistory) {
- break;
- }
- int width = getViewWidth();
- if (width == 0) {
- break;
- }
- int initialScale = msg.arg1;
- int viewportWidth = msg.arg2;
- // start a new page with DEFAULT_SCALE zoom scale.
- float scale = mDefaultScale;
- if (mInitialScale > 0) {
- scale = mInitialScale / 100.0f;
- } else {
- if (mWebViewCore.getSettings().getUseWideViewPort()) {
- // force viewSizeChanged by setting mLastWidthSent
- // to 0
- mLastWidthSent = 0;
- }
- if (initialScale == 0) {
- // if viewportWidth is defined and it is smaller
- // than the view width, zoom in to fill the view
- if (viewportWidth > 0 && viewportWidth < width) {
- scale = (float) width / viewportWidth;
- }
- } else {
- scale = initialScale / 100.0f;
- }
- }
- setNewZoomScale(scale, false);
break;
- case MARK_NODE_INVALID_ID:
- nativeMarkNodeInvalid(msg.arg1);
- break;
- case NOTIFY_FOCUS_SET_MSG_ID:
- if (mNativeClass != 0) {
- nativeNotifyFocusSet(inEditingMode());
+ case MOVE_OUT_OF_PLUGIN:
+ if (nativePluginEatsNavKey()) {
+ navHandledKey(msg.arg1, 1, false, 0, true);
}
break;
case UPDATE_TEXT_ENTRY_MSG_ID:
- // this is sent after finishing resize in WebViewCore. Make
+ // this is sent after finishing resize in WebViewCore. Make
// sure the text edit box is still on the screen.
- boolean alreadyThere = inEditingMode();
- if (alreadyThere && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
- mTextEntry.bringIntoView();
- }
+ if (inEditingMode() && nativeCursorIsTextInput()) {
+ mWebTextView.bringIntoView();
+ rebuildWebTextView();
}
- updateTextEntry();
break;
- case RECOMPUTE_FOCUS_MSG_ID:
- if (mNativeClass != 0) {
- nativeRecomputeFocus();
- }
+ case CLEAR_TEXT_ENTRY:
+ clearTextEntry();
break;
case INVAL_RECT_MSG_ID: {
Rect r = (Rect)msg.obj;
@@ -4765,17 +5153,15 @@
}
break;
}
- case UPDATE_TEXT_ENTRY_ADAPTER:
- HashMap data = (HashMap) msg.obj;
- if (mTextEntry.isSameTextField(msg.arg1)) {
- AutoCompleteAdapter adapter =
- (AutoCompleteAdapter) data.get("adapter");
- mTextEntry.setAdapterCustom(adapter);
+ case REQUEST_FORM_DATA:
+ AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
+ if (mWebTextView.isSameTextField(msg.arg1)) {
+ mWebTextView.setAdapterCustom(adapter);
}
break;
case UPDATE_CLIPBOARD:
String str = (String) msg.obj;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "UPDATE_CLIPBOARD " + str);
}
try {
@@ -4790,12 +5176,12 @@
WebViewCore.resumeUpdate(mWebViewCore);
break;
- case LONG_PRESS_ENTER:
+ case LONG_PRESS_CENTER:
// as this is shared by keydown and trackballdown, reset all
// the states
- mGotEnterDown = false;
+ mGotCenterDown = false;
mTrackballDown = false;
- // LONG_PRESS_ENTER is sent as a delayed message. If we
+ // LONG_PRESS_CENTER is sent as a delayed message. If we
// switch to windows overview, the WebView will be
// temporarily removed from the view system. In that case,
// do nothing.
@@ -4817,6 +5203,14 @@
}
break;
+ case REQUEST_KEYBOARD:
+ if (msg.arg1 == 0) {
+ hideSoftKeyboard();
+ } else {
+ displaySoftKeyboard(false);
+ }
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -4826,16 +5220,12 @@
// Class used to use a dropdown for a <select> element
private class InvokeListBox implements Runnable {
- // Strings for the labels in the listbox.
- private String[] mArray;
- // Array representing whether each item is enabled.
- private boolean[] mEnableArray;
// Whether the listbox allows multiple selection.
private boolean mMultiple;
// Passed in to a list with multiple selection to tell
// which items are selected.
private int[] mSelectedArray;
- // Passed in to a list with single selection to tell
+ // Passed in to a list with single selection to tell
// where the initial selection is.
private int mSelection;
@@ -4854,14 +5244,14 @@
}
/**
- * Subclass ArrayAdapter so we can disable OptionGroupLabels,
+ * Subclass ArrayAdapter so we can disable OptionGroupLabels,
* and allow filtering.
*/
private class MyArrayListAdapter extends ArrayAdapter<Container> {
public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) {
- super(context,
+ super(context,
multiple ? com.android.internal.R.layout.select_dialog_multichoice :
- com.android.internal.R.layout.select_dialog_singlechoice,
+ com.android.internal.R.layout.select_dialog_singlechoice,
objects);
}
@@ -4919,7 +5309,7 @@
}
}
- private InvokeListBox(String[] array, boolean[] enabled, int
+ private InvokeListBox(String[] array, boolean[] enabled, int
selection) {
mSelection = selection;
mMultiple = false;
@@ -4982,31 +5372,36 @@
public void run() {
final ListView listView = (ListView) LayoutInflater.from(mContext)
.inflate(com.android.internal.R.layout.select_dialog, null);
- final MyArrayListAdapter adapter = new
+ final MyArrayListAdapter adapter = new
MyArrayListAdapter(mContext, mContainers, mMultiple);
AlertDialog.Builder b = new AlertDialog.Builder(mContext)
.setView(listView).setCancelable(true)
.setInverseBackgroundForced(true);
-
+
if (mMultiple) {
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mWebViewCore.sendMessage(
- EventHub.LISTBOX_CHOICES,
+ EventHub.LISTBOX_CHOICES,
adapter.getCount(), 0,
listView.getCheckedItemPositions());
}});
- b.setNegativeButton(android.R.string.cancel, null);
+ b.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mWebViewCore.sendMessage(
+ EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
+ }});
}
final AlertDialog dialog = b.create();
listView.setAdapter(adapter);
listView.setFocusableInTouchMode(true);
// There is a bug (1250103) where the checks in a ListView with
// multiple items selected are associated with the positions, not
- // the ids, so the items do not properly retain their checks when
+ // the ids, so the items do not properly retain their checks when
// filtered. Do not allow filtering on multiple lists until
// that bug is fixed.
-
+
listView.setTextFilterEnabled(!mMultiple);
if (mMultiple) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
@@ -5069,48 +5464,39 @@
}
// called by JNI
- private void sendFinalFocus(int frame, int node, int x, int y) {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData();
- focusData.mFrame = frame;
- focusData.mNode = node;
- focusData.mX = x;
- focusData.mY = y;
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData);
+ private void sendMoveMouse(int frame, int node, int x, int y) {
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+ new WebViewCore.CursorData(frame, node, x, y));
+ }
+
+ /*
+ * Send a mouse move event to the webcore thread.
+ *
+ * @param removeFocus Pass true if the "mouse" cursor is now over a node
+ * which wants key events, but it is not the focus. This
+ * will make the visual appear as though nothing is in
+ * focus. Remove the WebTextView, if present, and stop
+ * drawing the blinking caret.
+ * called by JNI
+ */
+ private void sendMoveMouseIfLatest(boolean removeFocus) {
+ if (removeFocus) {
+ clearTextEntry();
+ setFocusControllerInactive();
+ }
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
+ cursorData());
}
// called by JNI
- private void setFocusData(int moveGeneration, int buildGeneration,
- int frame, int node, int x, int y, boolean ignoreNullFocus) {
- mFocusData.mMoveGeneration = moveGeneration;
- mFocusData.mBuildGeneration = buildGeneration;
- mFocusData.mFrame = frame;
- mFocusData.mNode = node;
- mFocusData.mX = x;
- mFocusData.mY = y;
- mFocusData.mIgnoreNullFocus = ignoreNullFocus;
- }
-
- // called by JNI
- private void sendKitFocus() {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData);
- mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData);
- }
-
- // called by JNI
- private void sendMotionUp(int touchGeneration, int buildGeneration,
- int frame, int node, int x, int y, int size, boolean isClick,
- boolean retry) {
+ private void sendMotionUp(int touchGeneration,
+ int frame, int node, int x, int y) {
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
touchUpData.mMoveGeneration = touchGeneration;
- touchUpData.mBuildGeneration = buildGeneration;
- touchUpData.mSize = size;
- touchUpData.mIsClick = isClick;
- touchUpData.mRetry = retry;
- mFocusData.mFrame = touchUpData.mFrame = frame;
- mFocusData.mNode = touchUpData.mNode = node;
- mFocusData.mX = touchUpData.mX = x;
- mFocusData.mY = touchUpData.mY = y;
+ touchUpData.mFrame = frame;
+ touchUpData.mNode = node;
+ touchUpData.mX = x;
+ touchUpData.mY = y;
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
}
@@ -5149,56 +5535,72 @@
private void viewInvalidate() {
invalidate();
}
-
+
// return true if the key was handled
- private boolean navHandledKey(int keyCode, int count, boolean noScroll
- , long time) {
+ private boolean navHandledKey(int keyCode, int count, boolean noScroll,
+ long time, boolean ignorePlugin) {
if (mNativeClass == 0) {
return false;
}
- mLastFocusTime = time;
- mLastFocusBounds = nativeGetFocusRingBounds();
- boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
- + " mLastFocusTime=" + mLastFocusTime
+ if (ignorePlugin == false && nativePluginEatsNavKey()) {
+ KeyEvent event = new KeyEvent(time, time, KeyEvent.ACTION_DOWN
+ , keyCode, count, (mShiftIsPressed ? KeyEvent.META_SHIFT_ON : 0)
+ | (false ? KeyEvent.META_ALT_ON : 0) // FIXME
+ | (false ? KeyEvent.META_SYM_ON : 0) // FIXME
+ , 0, 0, 0);
+ mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
+ mWebViewCore.sendMessage(EventHub.KEY_UP, event);
+ return true;
+ }
+ mLastCursorTime = time;
+ mLastCursorBounds = nativeGetCursorRingBounds();
+ boolean keyHandled
+ = nativeMoveCursor(keyCode, count, noScroll) == false;
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds
+ + " mLastCursorTime=" + mLastCursorTime
+ " handled=" + keyHandled);
}
if (keyHandled == false || mHeightCanMeasure == false) {
return keyHandled;
}
- Rect contentFocus = nativeGetFocusRingBounds();
- if (contentFocus.isEmpty()) return keyHandled;
- Rect viewFocus = contentToView(contentFocus);
+ Rect contentCursorRingBounds = nativeGetCursorRingBounds();
+ if (contentCursorRingBounds.isEmpty()) return keyHandled;
+ Rect viewCursorRingBounds = contentToView(contentCursorRingBounds);
Rect visRect = new Rect();
calcOurVisibleRect(visRect);
Rect outset = new Rect(visRect);
int maxXScroll = visRect.width() / 2;
int maxYScroll = visRect.height() / 2;
outset.inset(-maxXScroll, -maxYScroll);
- if (Rect.intersects(outset, viewFocus) == false) {
+ if (Rect.intersects(outset, viewCursorRingBounds) == false) {
return keyHandled;
}
// FIXME: Necessary because ScrollView/ListView do not scroll left/right
- int maxH = Math.min(viewFocus.right - visRect.right, maxXScroll);
+ int maxH = Math.min(viewCursorRingBounds.right - visRect.right,
+ maxXScroll);
if (maxH > 0) {
pinScrollBy(maxH, 0, true, 0);
} else {
- maxH = Math.max(viewFocus.left - visRect.left, -maxXScroll);
+ maxH = Math.max(viewCursorRingBounds.left - visRect.left,
+ -maxXScroll);
if (maxH < 0) {
pinScrollBy(maxH, 0, true, 0);
}
}
- if (mLastFocusBounds.isEmpty()) return keyHandled;
- if (mLastFocusBounds.equals(contentFocus)) return keyHandled;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus);
+ if (mLastCursorBounds.isEmpty()) return keyHandled;
+ if (mLastCursorBounds.equals(contentCursorRingBounds)) {
+ return keyHandled;
}
- requestRectangleOnScreen(viewFocus);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "navHandledKey contentCursorRingBounds="
+ + contentCursorRingBounds);
+ }
+ requestRectangleOnScreen(viewCursorRingBounds);
mUserScroll = true;
return keyHandled;
}
-
+
/**
* Set the background color. It's white by default. Pass
* zero to make the view transparent.
@@ -5213,7 +5615,7 @@
nativeDebugDump();
mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
}
-
+
/**
* Update our cache with updatedText.
* @param updatedText The new text to put in our cache.
@@ -5223,52 +5625,85 @@
// we recognize that it is up to date.
nativeUpdateCachedTextfield(updatedText, mTextGeneration);
}
-
- // Never call this version except by updateCachedTextfield(String) -
- // we always want to pass in our generation number.
- private native void nativeUpdateCachedTextfield(String updatedText,
- int generation);
- private native void nativeClearFocus(int x, int y);
+
+ /* package */ native void nativeClearCursor();
private native void nativeCreate(int ptr);
+ private native int nativeCursorFramePointer();
+ private native Rect nativeCursorNodeBounds();
+ /* package */ native int nativeCursorNodePointer();
+ /* package */ native boolean nativeCursorMatchesFocus();
+ private native boolean nativeCursorIntersects(Rect visibleRect);
+ private native boolean nativeCursorIsAnchor();
+ private native boolean nativeCursorIsPlugin();
+ private native boolean nativeCursorIsTextInput();
+ private native Point nativeCursorPosition();
+ private native String nativeCursorText();
+ /**
+ * Returns true if the native cursor node says it wants to handle key events
+ * (ala plugins). This can only be called if mNativeClass is non-zero!
+ */
+ private native boolean nativeCursorWantsKeyEvents();
private native void nativeDebugDump();
private native void nativeDestroy();
- private native void nativeDrawFocusRing(Canvas content);
+ private native void nativeDrawCursorRing(Canvas content);
+ private native void nativeDrawMatches(Canvas canvas);
private native void nativeDrawSelection(Canvas content
, int x, int y, boolean extendSelection);
private native void nativeDrawSelectionRegion(Canvas content);
- private native boolean nativeUpdateFocusNode();
- private native Rect nativeGetFocusRingBounds();
- private native Rect nativeGetNavBounds();
+ private native void nativeDumpDisplayTree(String urlOrNull);
+ private native int nativeFindAll(String findLower, String findUpper);
+ private native void nativeFindNext(boolean forward);
+ private native boolean nativeFocusCandidateIsPassword();
+ private native boolean nativeFocusCandidateIsRtlText();
+ private native boolean nativeFocusCandidateIsTextField();
+ private native boolean nativeFocusCandidateIsTextInput();
+ private native int nativeFocusCandidateMaxLength();
+ /* package */ native String nativeFocusCandidateName();
+ private native Rect nativeFocusCandidateNodeBounds();
+ /* package */ native int nativeFocusCandidatePointer();
+ private native String nativeFocusCandidateText();
+ private native int nativeFocusCandidateTextSize();
+ /* package */ native int nativeFocusNodePointer();
+ private native Rect nativeGetCursorRingBounds();
+ private native Region nativeGetSelection();
+ private native boolean nativeHasCursorNode();
+ private native boolean nativeHasFocusNode();
+ private native void nativeHideCursor();
+ private native String nativeImageURI(int x, int y);
private native void nativeInstrumentReport();
- private native void nativeMarkNodeInvalid(int node);
+ /* package */ native void nativeMoveCursorToNextTextInput();
// return true if the page has been scrolled
- private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
+ private native boolean nativeMotionUp(int x, int y, int slop);
// returns false if it handled the key
- private native boolean nativeMoveFocus(int keyCode, int count,
+ private native boolean nativeMoveCursor(int keyCode, int count,
boolean noScroll);
- private native void nativeNotifyFocusSet(boolean inEditingMode);
- private native void nativeRecomputeFocus();
+ private native int nativeMoveGeneration();
+ private native void nativeMoveSelection(int x, int y,
+ boolean extendSelection);
+ private native boolean nativePluginEatsNavKey();
// Like many other of our native methods, you must make sure that
// mNativeClass is not null before calling this method.
private native void nativeRecordButtons(boolean focused,
boolean pressed, boolean invalidate);
- private native void nativeResetFocus();
- private native void nativeResetNavClipBounds();
private native void nativeSelectBestAt(Rect rect);
private native void nativeSetFindIsDown();
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
- private native void nativeSetNavBounds(Rect rect);
- private native void nativeSetNavClipBounds(Rect rect);
- private native String nativeImageURI(int x, int y);
+ // Returns a value corresponding to CachedFrame::ImeAction
+ /* package */ native int nativeTextFieldAction();
/**
- * Returns true if the native focus nodes says it wants to handle key events
- * (ala plugins). This can only be called if mNativeClass is non-zero!
+ * Perform a click on a currently focused text input. Since it is already
+ * focused, there is no need to go through the nativeMotionUp code, which
+ * may change the Cursor.
*/
- private native boolean nativeFocusNodeWantsKeyEvents();
- private native void nativeMoveSelection(int x, int y
- , boolean extendSelection);
- private native Region nativeGetSelection();
-
- private native void nativeDumpDisplayTree(String urlOrNull);
+ private native void nativeTextInputMotionUp(int x, int y);
+ private native int nativeTextGeneration();
+ // Never call this version except by updateCachedTextfield(String) -
+ // we always want to pass in our generation number.
+ private native void nativeUpdateCachedTextfield(String updatedText,
+ int generation);
+ private native void nativeUpdatePluginReceivesEvents();
+ // return NO_LEFTEDGE means failure.
+ private static final int NO_LEFTEDGE = -1;
+ private native int nativeGetBlockLeftEdge(int x, int y, float scale);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index a5fa41e..0720beb 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -32,17 +32,17 @@
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Set;
import junit.framework.Assert;
final class WebViewCore {
private static final String LOGTAG = "webcore";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
static {
// Load libwebcore during static initialization. This happens in the
@@ -96,14 +96,19 @@
private int mViewportMaximumScale = 0;
private boolean mViewportUserScalable = true;
-
- private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
+
+ private int mRestoredScale = 0;
+ private int mRestoredScreenWidthScale = 0;
private int mRestoredX = 0;
private int mRestoredY = 0;
private int mWebkitScrollX = 0;
private int mWebkitScrollY = 0;
+ // If the site doesn't use viewport meta tag to specify the viewport, use
+ // DEFAULT_VIEWPORT_WIDTH as default viewport width
+ static final int DEFAULT_VIEWPORT_WIDTH = 800;
+
// The thread name used to identify the WebCore thread and for use in
// debugging other classes that require operation within the WebCore thread.
/* package */ static final String THREAD_NAME = "WebViewCoreThread";
@@ -143,6 +148,8 @@
// The WebIconDatabase needs to be initialized within the UI thread so
// just request the instance here.
WebIconDatabase.getInstance();
+ // Create the WebStorage singleton
+ WebStorage.getInstance();
// Send a message to initialize the WebViewCore.
Message init = sWebCoreHandler.obtainMessage(
WebCoreThread.INITIALIZE, this);
@@ -162,6 +169,10 @@
mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
// Create the handler and transfer messages for the IconDatabase
WebIconDatabase.getInstance().createHandler();
+ // Create the handler for WebStorage
+ WebStorage.getInstance().createHandler();
+ // Create the handler for GeolocationPermissions.
+ GeolocationPermissions.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -225,6 +236,16 @@
}
/**
+ * Add an error message to the client's console.
+ * @param message The message to add
+ * @param lineNumber the line on which the error occurred
+ * @param sourceID the filename of the source that caused the error.
+ */
+ protected void addMessageToConsole(String message, int lineNumber, String sourceID) {
+ mCallbackProxy.addMessageToConsole(message, lineNumber, sourceID);
+ }
+
+ /**
* Invoke a javascript alert.
* @param message The message displayed in the alert.
*/
@@ -233,6 +254,68 @@
}
/**
+ * Notify the browser that the origin has exceeded it's database quota.
+ * @param url The URL that caused the overflow.
+ * @param databaseIdentifier The identifier of the database.
+ * @param currentQuota The current quota for the origin.
+ */
+ protected void exceededDatabaseQuota(String url,
+ String databaseIdentifier,
+ long currentQuota) {
+ // 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);
+ }
+ });
+ }
+
+ /**
+ * Notify the browser that the appcache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ */
+ protected void reachedMaxAppCacheSize(long spaceNeeded) {
+ mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
+ new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetNewStorageLimit(quota);
+ }
+ });
+ }
+
+ /**
+ * Shows a prompt to ask the user to set the Geolocation permission state
+ * for the given origin.
+ * @param origin The origin for which Geolocation permissions are
+ * requested.
+ */
+ protected void geolocationPermissionsShowPrompt(String origin) {
+ mCallbackProxy.onGeolocationPermissionsShowPrompt(origin,
+ new GeolocationPermissions.Callback() {
+ public void invoke(String origin, boolean allow, boolean remember) {
+ GeolocationPermissionsData data = new GeolocationPermissionsData();
+ data.mOrigin = origin;
+ data.mAllow = allow;
+ data.mRemember = remember;
+ // Marshall to WebCore thread.
+ sendMessage(EventHub.GEOLOCATION_PERMISSIONS_PROVIDE, data);
+ }
+ });
+ }
+
+ /**
+ * Hides the Geolocation permissions prompt.
+ */
+ protected void geolocationPermissionsHidePrompt() {
+ mCallbackProxy.onGeolocationPermissionsHidePrompt();
+ }
+
+ /**
* Invoke a javascript confirm dialog.
* @param message The message displayed in the dialog.
* @return True if the user confirmed or false if the user cancelled.
@@ -277,31 +360,36 @@
// JNI methods
//-------------------------------------------------------------------------
- static native String nativeFindAddress(String addr);
+ static native String nativeFindAddress(String addr, boolean caseInsensitive);
/**
* Empty the picture set.
*/
private native void nativeClearContent();
-
+
/**
* Create a flat picture from the set of pictures.
*/
private native void nativeCopyContentToPicture(Picture picture);
-
+
/**
* Draw the picture set with a background color. Returns true
- * if some individual picture took too long to draw and can be
+ * if some individual picture took too long to draw and can be
* split into parts. Called from the UI thread.
*/
private native boolean nativeDrawContent(Canvas canvas, int color);
-
+
+ /**
+ * check to see if picture is blank and in progress
+ */
+ private native boolean nativePictureReady();
+
/**
* Redraw a portion of the picture set. The Point wh returns the
* width and height of the overall picture.
*/
private native boolean nativeRecordContent(Region invalRegion, Point wh);
-
+
/**
* Splits slow parts of the picture set. Called from the webkit
* thread after nativeDrawContent returns true.
@@ -309,9 +397,10 @@
private native void nativeSplitContent();
private native boolean nativeKey(int keyCode, int unichar,
- int repeatCount, boolean isShift, boolean isAlt, boolean isDown);
+ int repeatCount, boolean isShift, boolean isAlt, boolean isSym,
+ boolean isDown);
- private native boolean nativeClick();
+ private native void nativeClick(int framePtr, int nodePtr);
private native void nativeSendListBoxChoices(boolean[] choices, int size);
@@ -329,60 +418,54 @@
float scale, int realScreenWidth, int screenHeight);
private native int nativeGetContentMinPrefWidth();
-
- // Start: functions that deal with text editing
- private native void nativeReplaceTextfieldText(int frame, int node, int x,
- int y, int oldStart, int oldEnd, String replace, int newStart,
- int newEnd);
- private native void passToJs(int frame, int node, int x, int y, int gen,
+ // Start: functions that deal with text editing
+ private native void nativeReplaceTextfieldText(
+ int oldStart, int oldEnd, String replace, int newStart, int newEnd,
+ int textGeneration);
+
+ private native void passToJs(int gen,
String currentText, int keyCode, int keyValue, boolean down,
boolean cap, boolean fn, boolean sym);
+ private native void nativeSetFocusControllerActive(boolean active);
+
private native void nativeSaveDocumentState(int frame);
- private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
- int y, boolean block);
+ private native void nativeMoveMouse(int framePtr, int x, int y);
- private native void nativeSetKitFocus(int moveGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- boolean ignoreNullFocus);
+ private native void nativeMoveMouseIfLatest(int moveGeneration,
+ int framePtr, int x, int y);
private native String nativeRetrieveHref(int framePtr, int nodePtr);
-
- private native void nativeTouchUp(int touchGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- int size, boolean isClick, boolean retry);
+
+ private native void nativeTouchUp(int touchGeneration,
+ int framePtr, int nodePtr, int x, int y);
private native boolean nativeHandleTouchEvent(int action, int x, int y);
- private native void nativeUnblockFocus();
-
private native void nativeUpdateFrameCache();
-
- private native void nativeSetSnapAnchor(int x, int y);
-
- private native void nativeSnapToAnchor();
-
+
private native void nativeSetBackgroundColor(int color);
-
+
private native void nativeDumpDomTree(boolean useFile);
private native void nativeDumpRenderTree(boolean useFile);
private native void nativeDumpNavTree();
- private native void nativeRefreshPlugins(boolean reloadOpenPages);
-
+ private native void nativeSetJsFlags(String flags);
+
/**
* Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
+ * focus, or if start == end, silently fail. If start and end are out of
* order, swap them.
* @param start Beginning of selection to delete.
* @param end End of selection to delete.
+ * @param textGeneration Text generation number when delete was pressed.
*/
- private native void nativeDeleteSelection(int frame, int node, int x, int y,
- int start, int end);
+ private native void nativeDeleteSelection(int start, int end,
+ int textGeneration);
/**
* Set the selection to (start, end) in the focused textfield. If start and
@@ -390,15 +473,34 @@
* @param start Beginning of selection.
* @param end End of selection.
*/
- private native void nativeSetSelection(int frame, int node, int x, int y,
- int start, int end);
+ private native void nativeSetSelection(int start, int end);
private native String nativeGetSelection(Region sel);
-
+
// Register a scheme to be treated as local scheme so that it can access
// local asset files for resources
private native void nativeRegisterURLSchemeAsLocal(String scheme);
+ /*
+ * Inform webcore that the user has decided whether to allow or deny new
+ * quota for the current origin or more space for the app cache, and that
+ * the main thread should wake up now.
+ * @param limit Is the new quota for an origin or new app cache max size.
+ */
+ private native void nativeSetNewStorageLimit(long limit);
+
+ private native void nativeUpdatePluginState(int framePtr, int nodePtr, int state);
+
+ /**
+ * Provide WebCore with a Geolocation permission state for the specified
+ * origin.
+ * @param origin The origin for which Geolocation permissions are provided.
+ * @param allow Whether Geolocation permissions are allowed.
+ * @param remember Whether this decision should be remembered beyond the
+ * life of the current page.
+ */
+ private native void nativeGeolocationPermissionsProvide(String origin, boolean allow, boolean remember);
+
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
@@ -447,7 +549,7 @@
CacheManager.endCacheTransaction();
CacheManager.startCacheTransaction();
sendMessageDelayed(
- obtainMessage(CACHE_TICKER),
+ obtainMessage(CACHE_TICKER),
CACHE_TICKER_INTERVAL);
}
break;
@@ -472,36 +574,64 @@
}
}
- static class FocusData {
- FocusData() {}
- FocusData(FocusData d) {
- mMoveGeneration = d.mMoveGeneration;
- mBuildGeneration = d.mBuildGeneration;
- mFrame = d.mFrame;
- mNode = d.mNode;
- mX = d.mX;
- mY = d.mY;
- mIgnoreNullFocus = d.mIgnoreNullFocus;
+ static class BaseUrlData {
+ String mBaseUrl;
+ String mData;
+ String mMimeType;
+ String mEncoding;
+ String mFailUrl;
+ }
+
+ static class CursorData {
+ CursorData() {}
+ CursorData(int frame, int node, int x, int y) {
+ mFrame = frame;
+ mX = x;
+ mY = y;
}
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
- int mNode;
int mX;
int mY;
- boolean mIgnoreNullFocus;
+ }
+
+ static class JSInterfaceData {
+ Object mObject;
+ String mInterfaceName;
+ }
+
+ static class JSKeyData {
+ String mCurrentText;
+ KeyEvent mEvent;
+ }
+
+ static class PostUrlData {
+ String mUrl;
+ byte[] mPostData;
+ }
+
+ static class ReplaceTextData {
+ String mReplace;
+ int mNewStart;
+ int mNewEnd;
+ int mTextGeneration;
+ }
+
+ static class TextSelectionData {
+ public TextSelectionData(int start, int end) {
+ mStart = start;
+ mEnd = end;
+ }
+ int mStart;
+ int mEnd;
}
static class TouchUpData {
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
int mNode;
int mX;
int mY;
- int mSize;
- boolean mIsClick;
- boolean mRetry;
}
static class TouchEventData {
@@ -510,7 +640,21 @@
int mY;
}
+ static class PluginStateData {
+ int mFrame;
+ int mNode;
+ int mState;
+ }
+
+ static class GeolocationPermissionsData {
+ String mOrigin;
+ boolean mAllow;
+ boolean mRemember;
+ }
+
static final String[] HandlerDebugString = {
+ "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
+ "SCROLL_TEXT_INPUT", // = 99
"LOAD_URL", // = 100;
"STOP_LOADING", // = 101;
"RELOAD", // = 102;
@@ -532,33 +676,37 @@
"CLICK", // = 118;
"SET_NETWORK_STATE", // = 119;
"DOC_HAS_IMAGES", // = 120;
- "SET_SNAP_ANCHOR", // = 121;
+ "121", // = 121;
"DELETE_SELECTION", // = 122;
"LISTBOX_CHOICES", // = 123;
"SINGLE_LISTBOX_CHOICE", // = 124;
- "125",
+ "MESSAGE_RELAY", // = 125;
"SET_BACKGROUND_COLOR", // = 126;
- "UNBLOCK_FOCUS", // = 127;
+ "PLUGIN_STATE", // = 127;
"SAVE_DOCUMENT_STATE", // = 128;
"GET_SELECTION", // = 129;
"WEBKIT_DRAW", // = 130;
"SYNC_SCROLL", // = 131;
- "REFRESH_PLUGINS", // = 132;
- // this will replace REFRESH_PLUGINS in the next release
- "POST_URL", // = 142;
+ "POST_URL", // = 132;
"SPLIT_PICTURE_SET", // = 133;
"CLEAR_CONTENT", // = 134;
- "SET_FINAL_FOCUS", // = 135;
- "SET_KIT_FOCUS", // = 136;
- "REQUEST_FOCUS_HREF", // = 137;
+ "SET_MOVE_MOUSE", // = 135;
+ "SET_MOVE_MOUSE_IF_LATEST", // = 136;
+ "REQUEST_CURSOR_HREF", // = 137;
"ADD_JS_INTERFACE", // = 138;
"LOAD_DATA", // = 139;
"TOUCH_UP", // = 140;
"TOUCH_EVENT", // = 141;
+ "SET_ACTIVE", // = 142;
+ "ON_PAUSE", // = 143
+ "ON_RESUME", // = 144
+ "FREE_MEMORY", // = 145
};
class EventHub {
// Message Ids
+ static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
+ static final int SCROLL_TEXT_INPUT = 99;
static final int LOAD_URL = 100;
static final int STOP_LOADING = 101;
static final int RELOAD = 102;
@@ -580,26 +728,24 @@
static final int CLICK = 118;
static final int SET_NETWORK_STATE = 119;
static final int DOC_HAS_IMAGES = 120;
- static final int SET_SNAP_ANCHOR = 121;
static final int DELETE_SELECTION = 122;
static final int LISTBOX_CHOICES = 123;
static final int SINGLE_LISTBOX_CHOICE = 124;
+ static final int MESSAGE_RELAY = 125;
static final int SET_BACKGROUND_COLOR = 126;
- static final int UNBLOCK_FOCUS = 127;
+ static final int PLUGIN_STATE = 127; // plugin notifications
static final int SAVE_DOCUMENT_STATE = 128;
static final int GET_SELECTION = 129;
static final int WEBKIT_DRAW = 130;
static final int SYNC_SCROLL = 131;
- static final int REFRESH_PLUGINS = 132;
- // this will replace REFRESH_PLUGINS in the next release
- static final int POST_URL = 142;
+ static final int POST_URL = 132;
static final int SPLIT_PICTURE_SET = 133;
static final int CLEAR_CONTENT = 134;
-
+
// UI nav messages
- static final int SET_FINAL_FOCUS = 135;
- static final int SET_KIT_FOCUS = 136;
- static final int REQUEST_FOCUS_HREF = 137;
+ static final int SET_MOVE_MOUSE = 135;
+ static final int SET_MOVE_MOUSE_IF_LATEST = 136;
+ static final int REQUEST_CURSOR_HREF = 137;
static final int ADD_JS_INTERFACE = 138;
static final int LOAD_DATA = 139;
@@ -608,6 +754,17 @@
// message used to pass UI touch events to WebCore
static final int TOUCH_EVENT = 141;
+ // Used to tell the focus controller not to draw the blinking cursor,
+ // based on whether the WebView has focus and whether the WebView's
+ // cursor matches the webpage's focus.
+ static final int SET_ACTIVE = 142;
+
+ // lifecycle activities for just this DOM (unlike pauseTimers, which
+ // is global)
+ static final int ON_PAUSE = 143;
+ static final int ON_RESUME = 144;
+ static final int FREE_MEMORY = 145;
+
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
@@ -620,12 +777,12 @@
static final int DUMP_RENDERTREE = 171;
static final int DUMP_NAVTREE = 172;
+ static final int SET_JS_FLAGS = 173;
+ // Geolocation
+ static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
+
// private message ids
private static final int DESTROY = 200;
-
- // flag values passed to message SET_FINAL_FOCUS
- static final int NO_FOCUS_CHANGE_BLOCK = 0;
- static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1;
// Private handler for WebCore messages.
private Handler mHandler;
@@ -654,10 +811,14 @@
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
- > TOUCH_EVENT ? Integer.toString(msg.what)
- : HandlerDebugString[msg.what - LOAD_URL]);
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, (msg.what < UPDATE_FRAME_CACHE_IF_LOADING
+ || msg.what
+ > FREE_MEMORY ? Integer.toString(msg.what)
+ : HandlerDebugString[msg.what
+ - UPDATE_FRAME_CACHE_IF_LOADING])
+ + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
+ + " obj=" + msg.obj);
}
switch (msg.what) {
case WEBKIT_DRAW:
@@ -672,20 +833,26 @@
mNativeClass = 0;
break;
+ case UPDATE_FRAME_CACHE_IF_LOADING:
+ nativeUpdateFrameCacheIfLoading();
+ break;
+
+ case SCROLL_TEXT_INPUT:
+ nativeScrollFocusedTextInput(msg.arg1, msg.arg2);
+ break;
+
case LOAD_URL:
loadUrl((String) msg.obj);
break;
case POST_URL: {
- HashMap param = (HashMap) msg.obj;
- String url = (String) param.get("url");
- byte[] data = (byte[]) param.get("data");
- mBrowserFrame.postUrl(url, data);
+ PostUrlData param = (PostUrlData) msg.obj;
+ mBrowserFrame.postUrl(param.mUrl, param.mPostData);
break;
}
case LOAD_DATA:
- HashMap loadParams = (HashMap) msg.obj;
- String baseUrl = (String) loadParams.get("baseUrl");
+ BaseUrlData loadParams = (BaseUrlData) msg.obj;
+ String baseUrl = loadParams.mBaseUrl;
if (baseUrl != null) {
int i = baseUrl.indexOf(':');
if (i > 0) {
@@ -698,7 +865,7 @@
* we automatically add the scheme of the
* baseUrl for local access as long as it is
* not http(s)/ftp(s)/about/javascript
- */
+ */
String scheme = baseUrl.substring(0, i);
if (!scheme.startsWith("http") &&
!scheme.startsWith("ftp") &&
@@ -709,16 +876,16 @@
}
}
mBrowserFrame.loadData(baseUrl,
- (String) loadParams.get("data"),
- (String) loadParams.get("mimeType"),
- (String) loadParams.get("encoding"),
- (String) loadParams.get("failUrl"));
+ loadParams.mData,
+ loadParams.mMimeType,
+ loadParams.mEncoding,
+ loadParams.mFailUrl);
break;
case STOP_LOADING:
- // If the WebCore has committed the load, but not
- // finished the first layout yet, we need to set
- // first layout done to trigger the interpreted side sync
+ // If the WebCore has committed the load, but not
+ // finished the first layout yet, we need to set
+ // first layout done to trigger the interpreted side sync
// up with native side
if (mBrowserFrame.committed()
&& !mBrowserFrame.firstLayoutDone()) {
@@ -741,20 +908,23 @@
break;
case CLICK:
- nativeClick();
+ nativeClick(msg.arg1, msg.arg2);
break;
- case VIEW_SIZE_CHANGED:
- viewSizeChanged(msg.arg1, msg.arg2,
- ((Float) msg.obj).floatValue());
+ case VIEW_SIZE_CHANGED: {
+ WebView.ViewSizeData data =
+ (WebView.ViewSizeData) msg.obj;
+ viewSizeChanged(data.mWidth, data.mHeight,
+ data.mTextWrapWidth, data.mScale);
break;
-
+ }
case SET_SCROLL_OFFSET:
// note: these are in document coordinates
// (inv-zoom)
- nativeSetScrollOffset(msg.arg1, msg.arg2);
+ Point pt = (Point) msg.obj;
+ nativeSetScrollOffset(msg.arg1, pt.x, pt.y);
break;
-
+
case SET_GLOBAL_BOUNDS:
Rect r = (Rect) msg.obj;
nativeSetGlobalBounds(r.left, r.top, r.width(),
@@ -765,7 +935,7 @@
// If it is a standard load and the load is not
// committed yet, we interpret BACK as RELOAD
if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
- (mBrowserFrame.loadType() ==
+ (mBrowserFrame.loadType() ==
BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
mBrowserFrame.reload(true);
} else {
@@ -802,6 +972,24 @@
}
break;
+ case ON_PAUSE:
+ nativePause();
+ break;
+
+ case ON_RESUME:
+ nativeResume();
+ break;
+
+ case FREE_MEMORY:
+ clearCache(false);
+ nativeFreeMemory();
+ break;
+
+ case PLUGIN_STATE:
+ PluginStateData psd = (PluginStateData) msg.obj;
+ nativeUpdatePluginState(psd.mFrame, psd.mNode, psd.mState);
+ break;
+
case SET_NETWORK_STATE:
if (BrowserFrame.sJavaBridge == null) {
throw new IllegalStateException("No WebView " +
@@ -812,10 +1000,7 @@
break;
case CLEAR_CACHE:
- mBrowserFrame.clearCache();
- if (msg.arg1 == 1) {
- CacheManager.removeAllCacheFiles();
- }
+ clearCache(msg.arg1 == 1);
break;
case CLEAR_HISTORY:
@@ -823,29 +1008,21 @@
close(mBrowserFrame.mNativeFrame);
break;
- case REPLACE_TEXT:
- HashMap jMap = (HashMap) msg.obj;
- FocusData fData = (FocusData) jMap.get("focusData");
- String replace = (String) jMap.get("replace");
- int newStart =
- ((Integer) jMap.get("start")).intValue();
- int newEnd =
- ((Integer) jMap.get("end")).intValue();
- nativeReplaceTextfieldText(fData.mFrame,
- fData.mNode, fData.mX, fData.mY, msg.arg1,
- msg.arg2, replace, newStart, newEnd);
+ case REPLACE_TEXT:
+ ReplaceTextData rep = (ReplaceTextData) msg.obj;
+ nativeReplaceTextfieldText(msg.arg1, msg.arg2,
+ rep.mReplace, rep.mNewStart, rep.mNewEnd,
+ rep.mTextGeneration);
break;
case PASS_TO_JS: {
- HashMap jsMap = (HashMap) msg.obj;
- FocusData fDat = (FocusData) jsMap.get("focusData");
- KeyEvent evt = (KeyEvent) jsMap.get("event");
+ JSKeyData jsData = (JSKeyData) msg.obj;
+ KeyEvent evt = jsData.mEvent;
int keyCode = evt.getKeyCode();
int keyValue = evt.getUnicodeChar();
int generation = msg.arg1;
- passToJs(fDat.mFrame, fDat.mNode, fDat.mX, fDat.mY,
- generation,
- (String) jsMap.get("currentText"),
+ passToJs(generation,
+ jsData.mCurrentText,
keyCode,
keyValue,
evt.isDown(),
@@ -855,8 +1032,8 @@
}
case SAVE_DOCUMENT_STATE: {
- FocusData fDat = (FocusData) msg.obj;
- nativeSaveDocumentState(fDat.mFrame);
+ CursorData cDat = (CursorData) msg.obj;
+ nativeSaveDocumentState(cDat.mFrame);
break;
}
@@ -868,11 +1045,8 @@
case TOUCH_UP:
TouchUpData touchUpData = (TouchUpData) msg.obj;
nativeTouchUp(touchUpData.mMoveGeneration,
- touchUpData.mBuildGeneration,
touchUpData.mFrame, touchUpData.mNode,
- touchUpData.mX, touchUpData.mY,
- touchUpData.mSize, touchUpData.mIsClick,
- touchUpData.mRetry);
+ touchUpData.mX, touchUpData.mY);
break;
case TOUCH_EVENT: {
@@ -885,13 +1059,14 @@
break;
}
+ case SET_ACTIVE:
+ nativeSetFocusControllerActive(msg.arg1 == 1);
+ break;
+
case ADD_JS_INTERFACE:
- HashMap map = (HashMap) msg.obj;
- Object obj = map.get("object");
- String interfaceName = (String)
- map.get("interfaceName");
- mBrowserFrame.addJavascriptInterface(obj,
- interfaceName);
+ JSInterfaceData jsData = (JSInterfaceData) msg.obj;
+ mBrowserFrame.addJavascriptInterface(jsData.mObject,
+ jsData.mInterfaceName);
break;
case REQUEST_EXT_REPRESENTATION:
@@ -903,35 +1078,27 @@
mBrowserFrame.documentAsText((Message) msg.obj);
break;
- case SET_FINAL_FOCUS:
- FocusData finalData = (FocusData) msg.obj;
- nativeSetFinalFocus(finalData.mFrame,
- finalData.mNode, finalData.mX,
- finalData.mY, msg.arg1
- != EventHub.NO_FOCUS_CHANGE_BLOCK);
+ case SET_MOVE_MOUSE:
+ CursorData cursorData = (CursorData) msg.obj;
+ nativeMoveMouse(cursorData.mFrame,
+ cursorData.mX, cursorData.mY);
break;
- case UNBLOCK_FOCUS:
- nativeUnblockFocus();
+ case SET_MOVE_MOUSE_IF_LATEST:
+ CursorData cData = (CursorData) msg.obj;
+ nativeMoveMouseIfLatest(cData.mMoveGeneration,
+ cData.mFrame,
+ cData.mX, cData.mY);
break;
- case SET_KIT_FOCUS:
- FocusData focusData = (FocusData) msg.obj;
- nativeSetKitFocus(focusData.mMoveGeneration,
- focusData.mBuildGeneration,
- focusData.mFrame, focusData.mNode,
- focusData.mX, focusData.mY,
- focusData.mIgnoreNullFocus);
- break;
-
- case REQUEST_FOCUS_HREF: {
+ case REQUEST_CURSOR_HREF: {
Message hrefMsg = (Message) msg.obj;
String res = nativeRetrieveHref(msg.arg1, msg.arg2);
hrefMsg.getData().putString("url", res);
hrefMsg.sendToTarget();
break;
}
-
+
case UPDATE_CACHE_AND_TEXT_ENTRY:
nativeUpdateFrameCache();
// FIXME: this should provide a minimal rectangle
@@ -948,24 +1115,17 @@
imageResult.sendToTarget();
break;
- case SET_SNAP_ANCHOR:
- nativeSetSnapAnchor(msg.arg1, msg.arg2);
- break;
-
case DELETE_SELECTION:
- FocusData delData = (FocusData) msg.obj;
- nativeDeleteSelection(delData.mFrame,
- delData.mNode, delData.mX,
- delData.mY, msg.arg1, msg.arg2);
+ TextSelectionData deleteSelectionData
+ = (TextSelectionData) msg.obj;
+ nativeDeleteSelection(deleteSelectionData.mStart,
+ deleteSelectionData.mEnd, msg.arg1);
break;
case SET_SELECTION:
- FocusData selData = (FocusData) msg.obj;
- nativeSetSelection(selData.mFrame,
- selData.mNode, selData.mX,
- selData.mY, msg.arg1, msg.arg2);
+ nativeSetSelection(msg.arg1, msg.arg2);
break;
-
+
case LISTBOX_CHOICES:
SparseBooleanArray choices = (SparseBooleanArray)
msg.obj;
@@ -974,18 +1134,18 @@
for (int c = 0; c < choicesSize; c++) {
choicesArray[c] = choices.get(c);
}
- nativeSendListBoxChoices(choicesArray,
+ nativeSendListBoxChoices(choicesArray,
choicesSize);
break;
case SINGLE_LISTBOX_CHOICE:
nativeSendListBoxChoice(msg.arg1);
break;
-
+
case SET_BACKGROUND_COLOR:
nativeSetBackgroundColor(msg.arg1);
break;
-
+
case GET_SELECTION:
String str = nativeGetSelection((Region) msg.obj);
Message.obtain(mWebView.mPrivateHandler
@@ -1005,26 +1165,39 @@
nativeDumpNavTree();
break;
+ case SET_JS_FLAGS:
+ nativeSetJsFlags((String)msg.obj);
+ break;
+
+ case GEOLOCATION_PERMISSIONS_PROVIDE:
+ GeolocationPermissionsData data =
+ (GeolocationPermissionsData) msg.obj;
+ nativeGeolocationPermissionsProvide(data.mOrigin,
+ data.mAllow, data.mRemember);
+ break;
+
case SYNC_SCROLL:
mWebkitScrollX = msg.arg1;
mWebkitScrollY = msg.arg2;
break;
- case REFRESH_PLUGINS:
- nativeRefreshPlugins(msg.arg1 != 0);
- break;
-
case SPLIT_PICTURE_SET:
nativeSplitContent();
mSplitPictureIsScheduled = false;
break;
-
+
case CLEAR_CONTENT:
// Clear the view so that onDraw() will draw nothing
// but white background
// (See public method WebView.clearView)
nativeClearContent();
break;
+
+ case MESSAGE_RELAY:
+ if (msg.obj instanceof Message) {
+ ((Message) msg.obj).sendToTarget();
+ }
+ break;
}
}
};
@@ -1114,7 +1287,7 @@
//-------------------------------------------------------------------------
void stopLoading() {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE stopLoading");
if (mBrowserFrame != null) {
mBrowserFrame.stopLoading();
}
@@ -1189,20 +1362,42 @@
// WebViewCore private methods
//-------------------------------------------------------------------------
+ private void clearCache(boolean includeDiskFiles) {
+ mBrowserFrame.clearCache();
+ if (includeDiskFiles) {
+ CacheManager.removeAllCacheFiles();
+ }
+ }
+
private void loadUrl(String url) {
- if (LOGV_ENABLED) Log.v(LOGTAG, " CORE loadUrl " + url);
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
mBrowserFrame.loadUrl(url);
}
private void key(KeyEvent evt, boolean isDown) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
+ evt);
}
- if (!nativeKey(evt.getKeyCode(), evt.getUnicodeChar(),
+ int keyCode = evt.getKeyCode();
+ if (!nativeKey(keyCode, evt.getUnicodeChar(),
evt.getRepeatCount(), evt.isShiftPressed(), evt.isAltPressed(),
- isDown)) {
+ evt.isSymPressed(),
+ isDown) && keyCode != KeyEvent.KEYCODE_ENTER) {
+ if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
+ && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "key: arrow unused by plugin: " + keyCode);
+ }
+ if (mWebView != null && evt.isDown()) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.MOVE_OUT_OF_PLUGIN, keyCode).sendToTarget();
+ }
+ return;
+ }
// bubble up the event handling
+ // but do not bubble up the ENTER key, which would open the search
+ // bar without any text.
mCallbackProxy.onUnhandledKeyEvent(evt);
}
}
@@ -1210,21 +1405,24 @@
// These values are used to avoid requesting a layout based on old values
private int mCurrentViewWidth = 0;
private int mCurrentViewHeight = 0;
+ private float mCurrentViewScale = 1.0f;
// notify webkit that our virtual view size changed size (after inv-zoom)
- private void viewSizeChanged(int w, int h, float scale) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
+ private void viewSizeChanged(int w, int h, int textwrapWidth, float scale) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "viewSizeChanged w=" + w + "; h=" + h
+ + "; textwrapWidth=" + textwrapWidth + "; scale=" + scale);
+ }
if (w == 0) {
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
- if (mSettings.getUseWideViewPort()
- && (w < mViewportWidth || mViewportWidth == -1)) {
- int width = mViewportWidth;
+ int width = w;
+ if (mSettings.getUseWideViewPort()) {
if (mViewportWidth == -1) {
- if (mSettings.getLayoutAlgorithm() ==
+ if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
- width = WebView.ZOOM_OUT_WIDTH;
+ width = DEFAULT_VIEWPORT_WIDTH;
} else {
/*
* if a page's minimum preferred width is wider than the
@@ -1238,22 +1436,24 @@
* In the worse case, the native width will be adjusted when
* next zoom or screen orientation change happens.
*/
- width = Math.max(w, nativeGetContentMinPrefWidth());
+ width = Math.max(w, Math.max(DEFAULT_VIEWPORT_WIDTH,
+ nativeGetContentMinPrefWidth()));
}
+ } else {
+ width = Math.max(w, mViewportWidth);
}
- nativeSetSize(width, Math.round((float) width * h / w), w, scale,
- w, h);
- } else {
- nativeSetSize(w, h, w, scale, w, h);
}
+ nativeSetSize(width, width == w ? h : Math.round((float) width * h / w),
+ textwrapWidth, scale, w, h);
// Remember the current width and height
boolean needInvalidate = (mCurrentViewWidth == 0);
mCurrentViewWidth = w;
mCurrentViewHeight = h;
+ mCurrentViewScale = scale;
if (needInvalidate) {
// ensure {@link #webkitDraw} is called as we were blocking in
// {@link #contentDraw} when mCurrentViewWidth is 0
- if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "viewSizeChanged");
contentDraw();
}
mEventHub.sendMessage(Message.obtain(null,
@@ -1267,9 +1467,24 @@
}
}
+ // Utility method for exceededDatabaseQuota and reachedMaxAppCacheSize
+ // callbacks. Computes the sum of database quota for all origins.
+ private long getUsedQuota() {
+ WebStorage webStorage = WebStorage.getInstance();
+ Set<String> origins = webStorage.getOrigins();
+ if (origins == null) {
+ return 0;
+ }
+ long usedQuota = 0;
+ for (String origin : origins) {
+ usedQuota += webStorage.getQuotaForOrigin(origin);
+ }
+ return usedQuota;
+ }
+
// Used to avoid posting more than one draw message.
private boolean mDrawIsScheduled;
-
+
// Used to avoid posting more than one split picture message.
private boolean mSplitPictureIsScheduled;
@@ -1278,31 +1493,55 @@
// Used to end scale+scroll mode, accessed by both threads
boolean mEndScaleZoom = false;
-
- public class DrawData {
- public DrawData() {
+
+ // mRestoreState is set in didFirstLayout(), and reset in the next
+ // webkitDraw after passing it to the UI thread.
+ private RestoreState mRestoreState = null;
+
+ static class RestoreState {
+ float mMinScale;
+ float mMaxScale;
+ float mViewScale;
+ float mTextWrapScale;
+ int mScrollX;
+ int mScrollY;
+ }
+
+ static class DrawData {
+ DrawData() {
mInvalRegion = new Region();
mWidthHeight = new Point();
}
- public Region mInvalRegion;
- public Point mViewPoint;
- public Point mWidthHeight;
+ Region mInvalRegion;
+ Point mViewPoint;
+ Point mWidthHeight;
+ int mMinPrefWidth;
+ RestoreState mRestoreState; // only non-null if it is for the first
+ // picture set after the first layout
}
-
+
private void webkitDraw() {
mDrawIsScheduled = false;
DrawData draw = new DrawData();
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
- if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw start");
+ if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
== false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
return;
}
if (mWebView != null) {
// Send the native view size that was used during the most recent
// layout.
draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
+ if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+ draw.mMinPrefWidth = Math.max(DEFAULT_VIEWPORT_WIDTH,
+ nativeGetContentMinPrefWidth());
+ }
+ if (mRestoreState != null) {
+ draw.mRestoreState = mRestoreState;
+ mRestoreState = null;
+ }
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
@@ -1312,9 +1551,6 @@
mWebkitScrollY).sendToTarget();
mWebkitScrollX = mWebkitScrollY = 0;
}
- // nativeSnapToAnchor() needs to be called after NEW_PICTURE_MSG_ID
- // is sent, so that scroll will be based on the new content size.
- nativeSnapToAnchor();
}
}
@@ -1350,6 +1586,10 @@
}
}
+ /* package */ boolean pictureReady() {
+ return nativePictureReady();
+ }
+
/*package*/ Picture copyContentPicture() {
Picture result = new Picture();
nativeCopyContentToPicture(result);
@@ -1363,9 +1603,9 @@
sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
.obtainMessage(WebCoreThread.REDUCE_PRIORITY));
// Note: there is one possible failure mode. If pauseUpdate() is called
- // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
- // of the queue and about to be executed. mDrawIsScheduled may be set to
- // false in webkitDraw(). So update won't be blocked. But at least the
+ // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
+ // of the queue and about to be executed. mDrawIsScheduled may be set to
+ // false in webkitDraw(). So update won't be blocked. But at least the
// webcore thread priority is still lowered.
if (core != null) {
synchronized (core) {
@@ -1385,7 +1625,7 @@
synchronized (core) {
core.mDrawIsScheduled = false;
core.mDrawIsPaused = false;
- if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "resumeUpdate");
core.contentDraw();
}
}
@@ -1434,7 +1674,7 @@
mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
}
}
-
+
// called by JNI
private void contentScrollBy(int dx, int dy, boolean animate) {
if (!mBrowserFrame.firstLayoutDone()) {
@@ -1442,9 +1682,14 @@
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_BY_MSG_ID, dx, dy,
- new Boolean(animate)).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SCROLL_BY_MSG_ID, dx, dy, new Boolean(animate));
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1461,8 +1706,14 @@
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_TO_MSG_ID, x, y).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SCROLL_TO_MSG_ID, x, y);
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1479,24 +1730,14 @@
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendMarkNodeInvalid(int node) {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.MARK_NODE_INVALID_ID, node, 0).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendNotifyFocusSet() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SPAWN_SCROLL_TO_MSG_ID, x, y);
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1511,14 +1752,6 @@
contentDraw();
}
- // called by JNI
- private void sendRecomputeFocus() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.RECOMPUTE_FOCUS_MSG_ID).sendToTarget();
- }
- }
-
/* Called by JNI. The coordinates are in doc coordinates, so they need to
be scaled before they can be used by the view system, which happens
in WebView since it (and its thread) know the current scale factor.
@@ -1536,20 +1769,11 @@
}
private native void setViewportSettingsFromNative();
-
+
// called by JNI
- private void didFirstLayout() {
- // Trick to ensure that the Picture has the exact height for the content
- // by forcing to layout with 0 height after the page is ready, which is
- // indicated by didFirstLayout. This is essential to get rid of the
- // white space in the GMail which uses WebView for message view.
- if (mWebView != null && mWebView.mHeightCanMeasure) {
- mWebView.mLastHeightSent = 0;
- // Send a negative scale to indicate that WebCore should reuse the
- // current scale
- mEventHub.sendMessage(Message.obtain(null,
- EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
- mWebView.mLastHeightSent, -1.0f));
+ private void didFirstLayout(boolean standardLoad) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "didFirstLayout standardLoad =" + standardLoad);
}
mBrowserFrame.didFirstLayout();
@@ -1557,6 +1781,9 @@
// reset the scroll position as it is a new page now
mWebkitScrollX = mWebkitScrollY = 0;
+ // for non-standard load, we only adjust scale if mRestoredScale > 0
+ if (mWebView == null || (mRestoredScale == 0 && !standardLoad)) return;
+
// set the viewport settings from WebKit
setViewportSettingsFromNative();
@@ -1608,39 +1835,74 @@
}
// now notify webview
- if (mWebView != null) {
- HashMap scaleLimit = new HashMap();
- scaleLimit.put("minScale", mViewportMinimumScale);
- scaleLimit.put("maxScale", mViewportMaximumScale);
-
- if (mRestoredScale > 0) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
- scaleLimit).sendToTarget();
- mRestoredScale = 0;
+ int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale);
+ mRestoreState = new RestoreState();
+ mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
+ mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
+ mRestoreState.mScrollX = mRestoredX;
+ mRestoreState.mScrollY = mRestoredY;
+ if (mRestoredScale > 0) {
+ if (mRestoredScreenWidthScale > 0) {
+ mRestoreState.mTextWrapScale =
+ mRestoredScreenWidthScale / 100.0f;
+ // 0 will trigger WebView to turn on zoom overview mode
+ mRestoreState.mViewScale = 0;
} else {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
- mViewportWidth, scaleLimit).sendToTarget();
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ mRestoredScale / 100.0f;
}
-
- // if no restored offset, move the new page to (0, 0)
- Message.obtain(mWebView.mPrivateHandler, WebView.SCROLL_TO_MSG_ID,
- mRestoredX, mRestoredY).sendToTarget();
- mRestoredX = mRestoredY = 0;
-
- // force an early draw for quick feedback after the first layout
- if (mCurrentViewWidth != 0) {
- synchronized (this) {
- if (mDrawIsScheduled) {
- mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
- }
- mDrawIsScheduled = true;
- mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
- EventHub.WEBKIT_DRAW));
- }
+ } else {
+ if (mViewportInitialScale > 0) {
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ mViewportInitialScale / 100.0f;
+ } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth) {
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ (float) webViewWidth / mViewportWidth;
+ } else {
+ mRestoreState.mTextWrapScale =
+ WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+ // 0 will trigger WebView to turn on zoom overview mode
+ mRestoreState.mViewScale = 0;
}
}
+
+ if (mWebView.mHeightCanMeasure) {
+ // Trick to ensure that the Picture has the exact height for the
+ // content by forcing to layout with 0 height after the page is
+ // ready, which is indicated by didFirstLayout. This is essential to
+ // get rid of the white space in the GMail which uses WebView for
+ // message view.
+ mWebView.mLastHeightSent = 0;
+ // Send a negative scale to indicate that WebCore should reuse
+ // the current scale
+ WebView.ViewSizeData data = new WebView.ViewSizeData();
+ data.mWidth = mWebView.mLastWidthSent;
+ data.mHeight = 0;
+ // if mHeightCanMeasure is true, getUseWideViewPort() can't be
+ // true. It is safe to use mWidth for mTextWrapWidth.
+ data.mTextWrapWidth = data.mWidth;
+ 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));
+ }
+ // reset restored offset, scale
+ mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
}
// called by JNI
@@ -1651,6 +1913,17 @@
}
// called by JNI
+ private void restoreScreenWidthScale(int scale) {
+ if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+ return;
+ }
+
+ if (mBrowserFrame.firstLayoutDone() == false) {
+ mRestoredScreenWidthScale = scale;
+ }
+ }
+
+ // called by JNI
private void needTouchEvents(boolean need) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
@@ -1664,15 +1937,39 @@
String text, int textGeneration) {
if (mWebView != null) {
Message msg = Message.obtain(mWebView.mPrivateHandler,
- WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
+ WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
textGeneration, text);
msg.getData().putBoolean("password", changeToPassword);
msg.sendToTarget();
}
}
+ // called by JNI
+ private void updateTextSelection(int pointer, int start, int end,
+ int textGeneration) {
+ if (mWebView != null) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
+ new TextSelectionData(start, end)).sendToTarget();
+ }
+ }
+
+ // called by JNI
+ private void clearTextEntry() {
+ if (mWebView == null) return;
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.CLEAR_TEXT_ENTRY).sendToTarget();
+ }
+
+ private native void nativeUpdateFrameCacheIfLoading();
+
+ /**
+ * Scroll the focused textfield to (x, y) in document space
+ */
+ private native void nativeScrollFocusedTextInput(int x, int y);
+
// these must be in document space (i.e. not scaled/zoomed).
- private native void nativeSetScrollOffset(int dx, int dy);
+ private native void nativeSetScrollOffset(int gen, int dx, int dy);
private native void nativeSetGlobalBounds(int x, int y, int w, int h);
@@ -1690,6 +1987,97 @@
if (mWebView != null) {
mWebView.requestListBox(array, enabledArray, selection);
}
-
+
}
+
+ // called by JNI
+ private void requestKeyboard(boolean showKeyboard) {
+ if (mWebView != null) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0)
+ .sendToTarget();
+ }
+ }
+
+ // This class looks like a SurfaceView to native code. In java, we can
+ // assume the passed in SurfaceView is this class so we can talk to the
+ // ViewManager through the ChildView.
+ private class SurfaceViewProxy extends SurfaceView
+ implements SurfaceHolder.Callback {
+ private final ViewManager.ChildView mChildView;
+ private int mPointer;
+ private final boolean mIsFixedSize;
+ SurfaceViewProxy(Context context, ViewManager.ChildView childView,
+ int pointer, int pixelFormat, boolean isFixedSize) {
+ super(context);
+ setWillNotDraw(false); // this prevents the black box artifact
+ getHolder().addCallback(this);
+ getHolder().setFormat(pixelFormat);
+ mChildView = childView;
+ mChildView.mView = this;
+ mPointer = pointer;
+ mIsFixedSize = isFixedSize;
+ }
+ void destroy() {
+ mPointer = 0;
+ mChildView.removeView();
+ }
+ void attach(int x, int y, int width, int height) {
+ mChildView.attachView(x, y, width, height);
+
+ if (mIsFixedSize) {
+ getHolder().setFixedSize(width, height);
+ }
+ }
+
+ // SurfaceHolder.Callback methods
+ public void surfaceCreated(SurfaceHolder holder) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 0, 0, 0, 0);
+ }
+ }
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 1, format, width, height);
+ }
+ }
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 2, 0, 0, 0);
+ }
+ }
+ }
+
+ // PluginWidget functions for mainting SurfaceViews for the Surface drawing
+ // model.
+ private SurfaceView createSurface(int nativePointer, int pixelFormat,
+ boolean isFixedSize) {
+ if (mWebView == null) {
+ return null;
+ }
+ return new SurfaceViewProxy(mContext, mWebView.mViewManager.createView(),
+ nativePointer, pixelFormat, isFixedSize);
+ }
+
+ private void destroySurface(SurfaceView surface) {
+ SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
+ proxy.destroy();
+ }
+
+ private void attachSurface(SurfaceView surface, int x, int y,
+ int width, int height) {
+ SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
+ proxy.attach(x, y, width, height);
+ }
+
+ // Callback for the SurfaceHolder.Callback. Called for all the surface
+ // callbacks. The state parameter is one of Created(0), Changed(1),
+ // Destroyed(2).
+ private native void nativeSurfaceChanged(int pointer, int state, int format,
+ int width, int height);
+
+ private native void nativePause();
+ private native void nativeResume();
+ private native void nativeFreeMemory();
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 1004e30..4e76254 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -48,7 +48,9 @@
// 6 -> 7 Change cache localPath from int to String
// 7 -> 8 Move cache to its own db
// 8 -> 9 Store both scheme and host when storing passwords
- private static final int CACHE_DATABASE_VERSION = 1;
+ private static final int CACHE_DATABASE_VERSION = 3;
+ // 1 -> 2 Add expires String
+ // 2 -> 3 Add content-disposition
private static WebViewDatabase mInstance = null;
@@ -107,6 +109,8 @@
private static final String CACHE_EXPIRES_COL = "expires";
+ private static final String CACHE_EXPIRES_STRING_COL = "expiresstring";
+
private static final String CACHE_MIMETYPE_COL = "mimetype";
private static final String CACHE_ENCODING_COL = "encoding";
@@ -117,6 +121,8 @@
private static final String CACHE_CONTENTLENGTH_COL = "contentlength";
+ private static final String CACHE_CONTENTDISPOSITION_COL = "contentdisposition";
+
// column id strings for "password" table
private static final String PASSWORD_HOST_COL = "host";
@@ -150,11 +156,13 @@
private static int mCacheLastModifyColIndex;
private static int mCacheETagColIndex;
private static int mCacheExpiresColIndex;
+ private static int mCacheExpiresStringColIndex;
private static int mCacheMimeTypeColIndex;
private static int mCacheEncodingColIndex;
private static int mCacheHttpStatusColIndex;
private static int mCacheLocationColIndex;
private static int mCacheContentLengthColIndex;
+ private static int mCacheContentDispositionColIndex;
private static int mCacheTransactionRefcount;
@@ -220,6 +228,8 @@
.getColumnIndex(CACHE_ETAG_COL);
mCacheExpiresColIndex = mCacheInserter
.getColumnIndex(CACHE_EXPIRES_COL);
+ mCacheExpiresStringColIndex = mCacheInserter
+ .getColumnIndex(CACHE_EXPIRES_STRING_COL);
mCacheMimeTypeColIndex = mCacheInserter
.getColumnIndex(CACHE_MIMETYPE_COL);
mCacheEncodingColIndex = mCacheInserter
@@ -230,6 +240,8 @@
.getColumnIndex(CACHE_LOCATION_COL);
mCacheContentLengthColIndex = mCacheInserter
.getColumnIndex(CACHE_CONTENTLENGTH_COL);
+ mCacheContentDispositionColIndex = mCacheInserter
+ .getColumnIndex(CACHE_CONTENTDISPOSITION_COL);
}
}
@@ -320,11 +332,12 @@
+ " TEXT, " + CACHE_FILE_PATH_COL + " TEXT, "
+ CACHE_LAST_MODIFY_COL + " TEXT, " + CACHE_ETAG_COL
+ " TEXT, " + CACHE_EXPIRES_COL + " INTEGER, "
+ + CACHE_EXPIRES_STRING_COL + " TEXT, "
+ CACHE_MIMETYPE_COL + " TEXT, " + CACHE_ENCODING_COL
+ " TEXT," + CACHE_HTTP_STATUS_COL + " INTEGER, "
+ CACHE_LOCATION_COL + " TEXT, " + CACHE_CONTENTLENGTH_COL
- + " INTEGER, " + " UNIQUE (" + CACHE_URL_COL
- + ") ON CONFLICT REPLACE);");
+ + " INTEGER, " + CACHE_CONTENTDISPOSITION_COL + " TEXT, "
+ + " UNIQUE (" + CACHE_URL_COL + ") ON CONFLICT REPLACE);");
mCacheDatabase.execSQL("CREATE INDEX cacheUrlIndex ON cache ("
+ CACHE_URL_COL + ")");
}
@@ -537,8 +550,8 @@
}
Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
- + "mimetype, encoding, httpstatus, location, contentlength "
- + "FROM cache WHERE url = ?",
+ + "expiresstring, mimetype, encoding, httpstatus, location, contentlength, "
+ + "contentdisposition FROM cache WHERE url = ?",
new String[] { url });
try {
@@ -548,11 +561,13 @@
ret.lastModified = cursor.getString(1);
ret.etag = cursor.getString(2);
ret.expires = cursor.getLong(3);
- ret.mimeType = cursor.getString(4);
- ret.encoding = cursor.getString(5);
- ret.httpStatusCode = cursor.getInt(6);
- ret.location = cursor.getString(7);
- ret.contentLength = cursor.getLong(8);
+ ret.expiresString = cursor.getString(4);
+ ret.mimeType = cursor.getString(5);
+ ret.encoding = cursor.getString(6);
+ ret.httpStatusCode = cursor.getInt(7);
+ ret.location = cursor.getString(8);
+ ret.contentLength = cursor.getLong(9);
+ ret.contentdisposition = cursor.getString(10);
return ret;
}
} finally {
@@ -591,11 +606,14 @@
mCacheInserter.bind(mCacheLastModifyColIndex, c.lastModified);
mCacheInserter.bind(mCacheETagColIndex, c.etag);
mCacheInserter.bind(mCacheExpiresColIndex, c.expires);
+ mCacheInserter.bind(mCacheExpiresStringColIndex, c.expiresString);
mCacheInserter.bind(mCacheMimeTypeColIndex, c.mimeType);
mCacheInserter.bind(mCacheEncodingColIndex, c.encoding);
mCacheInserter.bind(mCacheHttpStatusColIndex, c.httpStatusCode);
mCacheInserter.bind(mCacheLocationColIndex, c.location);
mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength);
+ mCacheInserter.bind(mCacheContentDispositionColIndex,
+ c.contentdisposition);
mCacheInserter.execute();
}
diff --git a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java b/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
deleted file mode 100644
index 3646042..0000000
--- a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * GPS provider implementation for Android.
- */
-public final class AndroidGpsLocationProvider implements LocationListener {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-GpsProvider";
- /**
- * Our location manager instance.
- */
- private LocationManager locationManager;
- /**
- * The native object ID.
- */
- private long nativeObject;
-
- public AndroidGpsLocationProvider(WebView webview, long object) {
- nativeObject = object;
- locationManager = (LocationManager) webview.getContext().getSystemService(
- Context.LOCATION_SERVICE);
- if (locationManager == null) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidGpsLocationProvider: locationManager is null.");
- }
- // Register for location updates.
- try {
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
- this);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG,
- "AndroidLocationGpsProvider: could not register for updates: " + ex);
- throw ex;
- } catch (SecurityException ex) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: not allowed to register for update: "
- + ex);
- throw ex;
- }
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- locationManager.removeUpdates(this);
- Log.i(TAG, "GPS provider closed.");
- }
-
- /**
- * Called when the location has changed.
- * @param location The new location, as a Location object.
- */
- public void onLocationChanged(Location location) {
- Log.i(TAG, "Location changed: " + location);
- nativeLocationChanged(location, nativeObject);
- }
-
- /**
- * Called when the provider status changes.
- *
- * @param provider the name of the location provider associated with this
- * update.
- * @param status {@link LocationProvider#OUT_OF_SERVICE} if the
- * provider is out of service, and this is not expected to change in the
- * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if
- * the provider is temporarily unavailable but is expected to be available
- * shortly; and {@link LocationProvider#AVAILABLE} if the
- * provider is currently available.
- * @param extras an optional Bundle which will contain provider specific
- * status variables (such as number of satellites).
- */
- public void onStatusChanged(String provider, int status, Bundle extras) {
- Log.i(TAG, "Provider " + provider + " status changed to " + status);
- if (status == LocationProvider.OUT_OF_SERVICE ||
- status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
- nativeProviderError(false, nativeObject);
- }
- }
-
- /**
- * Called when the provider is enabled.
- *
- * @param provider the name of the location provider that is now enabled.
- */
- public void onProviderEnabled(String provider) {
- Log.i(TAG, "Provider " + provider + " enabled.");
- // No need to notify the native side. It's enough to start sending
- // valid position fixes again.
- }
-
- /**
- * Called when the provider is disabled.
- *
- * @param provider the name of the location provider that is now disabled.
- */
- public void onProviderDisabled(String provider) {
- Log.i(TAG, "Provider " + provider + " disabled.");
- nativeProviderError(true, nativeObject);
- }
-
- /**
- * The native method called when a new location is available.
- * @param location is the new Location instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeLocationChanged(Location location, long object);
-
- /**
- * The native method called when there is a GPS provder error.
- * @param isDisabled is true when the error signifies the fact that the GPS
- * HW is disabled. For other errors, this param is always false.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeProviderError(boolean isDisabled, long object);
-}
diff --git a/core/java/android/webkit/gears/AndroidRadioDataProvider.java b/core/java/android/webkit/gears/AndroidRadioDataProvider.java
deleted file mode 100644
index 1384042..0000000
--- a/core/java/android/webkit/gears/AndroidRadioDataProvider.java
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.telephony.CellLocation;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.gsm.GsmCellLocation;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Radio data provider implementation for Android.
- */
-public final class AndroidRadioDataProvider extends PhoneStateListener {
-
- /** Logging tag */
- private static final String TAG = "Gears-J-RadioProvider";
-
- /** Network types */
- private static final int RADIO_TYPE_UNKNOWN = 0;
- private static final int RADIO_TYPE_GSM = 1;
- private static final int RADIO_TYPE_WCDMA = 2;
- private static final int RADIO_TYPE_CDMA = 3;
- private static final int RADIO_TYPE_EVDO = 4;
- private static final int RADIO_TYPE_1xRTT = 5;
-
- /** Simple container for radio data */
- public static final class RadioData {
- public int cellId = -1;
- public int locationAreaCode = -1;
- // TODO: use new SignalStrength instead of asu
- public int signalStrength = -1;
- public int mobileCountryCode = -1;
- public int mobileNetworkCode = -1;
- public int homeMobileCountryCode = -1;
- public int homeMobileNetworkCode = -1;
- public int radioType = RADIO_TYPE_UNKNOWN;
- public String carrierName;
-
- /**
- * Constructs radioData object from the given telephony data.
- * @param telephonyManager contains the TelephonyManager instance.
- * @param cellLocation contains information about the current GSM cell.
- * @param signalStrength is the strength of the network signal.
- * @param serviceState contains information about the network service.
- * @return a new RadioData object populated with the currently
- * available network information or null if there isn't
- * enough information.
- */
- public static RadioData getInstance(TelephonyManager telephonyManager,
- CellLocation cellLocation, int signalStrength,
- ServiceState serviceState) {
-
- if (!(cellLocation instanceof GsmCellLocation)) {
- // This also covers the case when cellLocation is null.
- // When that happens, we do not bother creating a
- // RadioData instance.
- return null;
- }
-
- RadioData radioData = new RadioData();
- GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
-
- // Extract the cell id, LAC, and signal strength.
- radioData.cellId = gsmCellLocation.getCid();
- radioData.locationAreaCode = gsmCellLocation.getLac();
- radioData.signalStrength = signalStrength;
-
- // Extract the home MCC and home MNC.
- String operator = telephonyManager.getSimOperator();
- radioData.setMobileCodes(operator, true);
-
- if (serviceState != null) {
- // Extract the carrier name.
- radioData.carrierName = serviceState.getOperatorAlphaLong();
-
- // Extract the MCC and MNC.
- operator = serviceState.getOperatorNumeric();
- radioData.setMobileCodes(operator, false);
- }
-
- // Finally get the radio type.
- //TODO We have to edit the parameter for getNetworkType regarding CDMA
- int type = telephonyManager.getNetworkType();
- if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
- radioData.radioType = RADIO_TYPE_WCDMA;
- } else if (type == TelephonyManager.NETWORK_TYPE_GPRS
- || type == TelephonyManager.NETWORK_TYPE_EDGE) {
- radioData.radioType = RADIO_TYPE_GSM;
- } else if (type == TelephonyManager.NETWORK_TYPE_CDMA) {
- radioData.radioType = RADIO_TYPE_CDMA;
- } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_0) {
- radioData.radioType = RADIO_TYPE_EVDO;
- } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_A) {
- radioData.radioType = RADIO_TYPE_EVDO;
- } else if (type == TelephonyManager.NETWORK_TYPE_1xRTT) {
- radioData.radioType = RADIO_TYPE_1xRTT;
- }
-
- // Print out what we got.
- Log.i(TAG, "Got the following data:");
- Log.i(TAG, "CellId: " + radioData.cellId);
- Log.i(TAG, "LAC: " + radioData.locationAreaCode);
- Log.i(TAG, "MNC: " + radioData.mobileNetworkCode);
- Log.i(TAG, "MCC: " + radioData.mobileCountryCode);
- Log.i(TAG, "home MNC: " + radioData.homeMobileNetworkCode);
- Log.i(TAG, "home MCC: " + radioData.homeMobileCountryCode);
- Log.i(TAG, "Signal strength: " + radioData.signalStrength);
- Log.i(TAG, "Carrier: " + radioData.carrierName);
- Log.i(TAG, "Network type: " + radioData.radioType);
-
- return radioData;
- }
-
- private RadioData() {}
-
- /**
- * Parses a string containing a mobile country code and a mobile
- * network code and sets the corresponding member variables.
- * @param codes is the string to parse.
- * @param homeValues flags whether the codes are for the home operator.
- */
- private void setMobileCodes(String codes, boolean homeValues) {
- if (codes != null) {
- try {
- // The operator numeric format is 3 digit country code plus 2 or
- // 3 digit network code.
- int mcc = Integer.parseInt(codes.substring(0, 3));
- int mnc = Integer.parseInt(codes.substring(3));
- if (homeValues) {
- homeMobileCountryCode = mcc;
- homeMobileNetworkCode = mnc;
- } else {
- mobileCountryCode = mcc;
- mobileNetworkCode = mnc;
- }
- } catch (IndexOutOfBoundsException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Invalid operator numeric data: " + ex);
- } catch (NumberFormatException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Operator numeric format error: " + ex);
- }
- }
- }
- };
-
- /** The native object ID */
- private long nativeObject;
-
- /** The last known cellLocation */
- private CellLocation cellLocation = null;
-
- /** The last known signal strength */
- // TODO: use new SignalStrength instead of asu
- private int signalStrength = -1;
-
- /** The last known serviceState */
- private ServiceState serviceState = null;
-
- /**
- * Our TelephonyManager instance.
- */
- private TelephonyManager telephonyManager;
-
- /**
- * Public constructor. Uses the webview to get the Context object.
- */
- public AndroidRadioDataProvider(WebView webview, long object) {
- super();
- nativeObject = object;
- telephonyManager = (TelephonyManager) webview.getContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyManager == null) {
- Log.e(TAG,
- "AndroidRadioDataProvider: could not get tepephony manager.");
- throw new NullPointerException(
- "AndroidRadioDataProvider: telephonyManager is null.");
- }
-
- // Register for cell id, signal strength and service state changed
- // notifications.
- telephonyManager.listen(this, PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_SERVICE_STATE);
- }
-
- /**
- * Should be called when the provider is no longer needed.
- */
- public void shutdown() {
- telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
- Log.i(TAG, "AndroidRadioDataProvider shutdown.");
- }
-
- @Override
- public void onServiceStateChanged(ServiceState state) {
- serviceState = state;
- notifyListeners();
- }
-
- @Override
- public void onSignalStrengthsChanged(SignalStrength ss) {
- int gsmSignalStrength = ss.getGsmSignalStrength();
- signalStrength = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
- notifyListeners();
- }
-
- @Override
- public void onCellLocationChanged(CellLocation location) {
- cellLocation = location;
- notifyListeners();
- }
-
- private void notifyListeners() {
- RadioData radioData = RadioData.getInstance(telephonyManager, cellLocation,
- signalStrength, serviceState);
- if (radioData != null) {
- onUpdateAvailable(radioData, nativeObject);
- }
- }
-
- /**
- * The native method called when new radio data is available.
- * @param radioData is the RadioData instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidRadioDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- RadioData radioData, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
deleted file mode 100644
index d2850b06..0000000
--- a/core/java/android/webkit/gears/AndroidWifiDataProvider.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2008, Google Inc.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.webkit.WebView;
-import java.util.List;
-
-/**
- * WiFi data provider implementation for Android.
- * {@hide}
- */
-public final class AndroidWifiDataProvider extends BroadcastReceiver {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-WifiProvider";
- /**
- * Flag for guarding Log.v() calls.
- * Set to true to enable extra debug logging.
- */
- private static final boolean LOGV_ENABLED = false;
- /**
- * Our Wifi manager instance.
- */
- private WifiManager mWifiManager;
- /**
- * The native object ID.
- */
- private long mNativeObject;
- /**
- * The Context instance.
- */
- private Context mContext;
-
- /**
- * Constructs a instance of this class and registers for wifi scan
- * updates. Note that this constructor must be called on a Looper
- * thread. Suitable threads can be created on the native side using
- * the AndroidLooperThread C++ class.
- */
- public AndroidWifiDataProvider(WebView webview, long object) {
- mNativeObject = object;
- mContext = webview.getContext();
- mWifiManager =
- (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (mWifiManager == null) {
- Log.e(TAG,
- "AndroidWifiDataProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidWifiDataProvider: locationManager is null.");
- }
-
- // Create a Handler that identifies the message loop associated
- // with the current thread. Note that it is not necessary to
- // override handleMessage() at all since the Intent
- // ReceiverDispatcher (see the ActivityThread class) only uses
- // this handler to post a Runnable to this thread's loop.
- Handler handler = new Handler(Looper.myLooper());
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- mContext.registerReceiver(this, filter, null, handler);
-
- // Get the last scan results and pass them to the native side.
- // We can't just invoke the callback here, so we queue a message
- // to this thread's loop.
- handler.post(new Runnable() {
- public void run() {
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- });
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- mContext.unregisterReceiver(this);
- if (LOGV_ENABLED) {
- Log.v(TAG, "Wifi provider closed.");
- }
- }
-
- /**
- * This method is called when the AndroidWifiDataProvider is receiving an
- * Intent broadcast.
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(
- mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- if (LOGV_ENABLED) {
- Log.v(TAG, "Wifi scan resulst available");
- }
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- }
-
- /**
- * The native method called when new wifi data is available.
- * @param scanResults is a list of ScanResults to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidWifiDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- List<ScanResult> scanResults, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java b/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
deleted file mode 100644
index 74d27ed..0000000
--- a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
+++ /dev/null
@@ -1,1134 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.net.http.Headers;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.webkit.CacheManager;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.CookieManager;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.IOException;
-import java.lang.StringBuilder;
-import java.util.Date;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.HttpResponse;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.client.*;
-import org.apache.http.client.methods.*;
-import org.apache.http.impl.client.AbstractHttpClient;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
-import org.apache.http.impl.cookie.DateUtils;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Performs the underlying HTTP/HTTPS GET, POST, HEAD, PUT, DELETE requests.
- * <p> These are performed synchronously (blocking). The caller should
- * ensure that it is in a background thread if asynchronous behavior
- * is required. All data is pushed, so there is no need for JNI native
- * callbacks.
- * <p> This uses Apache's HttpClient framework to perform most
- * of the underlying network activity. The Android brower's cache,
- * android.webkit.CacheManager, is also used when caching is enabled,
- * and updated with new data. The android.webkit.CookieManager is also
- * queried and updated as necessary.
- * <p> The public interface is designed to be called by native code
- * through JNI, and to simplify coding none of the public methods will
- * surface a checked exception. Unchecked exceptions may still be
- * raised but only if the system is in an ill state, such as out of
- * memory.
- * <p> TODO: This isn't plumbed into LocalServer yet. Mutually
- * dependent on LocalServer - will attach the two together once both
- * are submitted.
- */
-public final class ApacheHttpRequestAndroid {
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** Flag for guarding Log.v() calls. */
- private static final boolean LOGV_ENABLED = false;
- /** HTTP response header line endings are CR-LF style. */
- private static final String HTTP_LINE_ENDING = "\r\n";
- /** Safe MIME type to use whenever it isn't specified. */
- private static final String DEFAULT_MIME_TYPE = "text/plain";
- /** Case-sensitive header keys */
- public static final String KEY_CONTENT_LENGTH = "Content-Length";
- public static final String KEY_EXPIRES = "Expires";
- public static final String KEY_LAST_MODIFIED = "Last-Modified";
- public static final String KEY_ETAG = "ETag";
- public static final String KEY_LOCATION = "Location";
- public static final String KEY_CONTENT_TYPE = "Content-Type";
- /** Number of bytes to send and receive on the HTTP connection in
- * one go. */
- private static final int BUFFER_SIZE = 4096;
-
- /** The first element of the String[] value in a headers map is the
- * unmodified (case-sensitive) key. */
- public static final int HEADERS_MAP_INDEX_KEY = 0;
- /** The second element of the String[] value in a headers map is the
- * associated value. */
- public static final int HEADERS_MAP_INDEX_VALUE = 1;
-
- /** Request headers, as key -> value map. */
- // TODO: replace this design by a simpler one (the C++ side has to
- // be modified too), where we do not store both the original header
- // and the lowercase one.
- private Map<String, String[]> mRequestHeaders =
- new HashMap<String, String[]>();
- /** Response headers, as a lowercase key -> value map. */
- private Map<String, String[]> mResponseHeaders =
- new HashMap<String, String[]>();
- /** The URL used for createCacheResult() */
- private String mCacheResultUrl;
- /** CacheResult being saved into, if inserting a new cache entry. */
- private CacheResult mCacheResult;
- /** Initialized by initChildThread(). Used to target abort(). */
- private Thread mBridgeThread;
-
- /** Our HttpClient */
- private AbstractHttpClient mClient;
- /** The HttpMethod associated with this request */
- private HttpRequestBase mMethod;
- /** The complete response line e.g "HTTP/1.0 200 OK" */
- private String mResponseLine;
- /** HTTP body stream, setup after connection. */
- private InputStream mBodyInputStream;
-
- /** HTTP Response Entity */
- private HttpResponse mResponse;
-
- /** Post Entity, used to stream the request to the server */
- private StreamEntity mPostEntity = null;
- /** Content lenght, mandatory when using POST */
- private long mContentLength;
-
- /** The request executes in a parallel thread */
- private Thread mHttpThread = null;
- /** protect mHttpThread, if interrupt() is called concurrently */
- private Lock mHttpThreadLock = new ReentrantLock();
- /** Flag set to true when the request thread is joined */
- private boolean mConnectionFinished = false;
- /** Flag set to true by interrupt() and/or connection errors */
- private boolean mConnectionFailed = false;
- /** Lock protecting the access to mConnectionFailed */
- private Lock mConnectionFailedLock = new ReentrantLock();
-
- /** Lock on the loop in StreamEntity */
- private Lock mStreamingReadyLock = new ReentrantLock();
- /** Condition variable used to signal the loop is ready... */
- private Condition mStreamingReady = mStreamingReadyLock.newCondition();
-
- /** Used to pass around the block of data POSTed */
- private Buffer mBuffer = new Buffer();
- /** Used to signal that the block of data has been written */
- private SignalConsumed mSignal = new SignalConsumed();
-
- // inner classes
-
- /**
- * Implements the http request
- */
- class Connection implements Runnable {
- public void run() {
- boolean problem = false;
- try {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "REQUEST : " + mMethod.getRequestLine());
- }
- mResponse = mClient.execute(mMethod);
- if (mResponse != null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "response (status line): "
- + mResponse.getStatusLine());
- }
- mResponseLine = "" + mResponse.getStatusLine();
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "problem, response == null");
- }
- problem = true;
- }
- } catch (IOException e) {
- Log.e(LOG_TAG, "Connection IO exception ", e);
- problem = true;
- } catch (RuntimeException e) {
- Log.e(LOG_TAG, "Connection runtime exception ", e);
- problem = true;
- }
-
- if (!problem) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Request complete ("
- + mMethod.getRequestLine() + ")");
- }
- } else {
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Request FAILED ("
- + mMethod.getRequestLine() + ")");
- }
- // We abort the execution in order to shutdown and release
- // the underlying connection
- mMethod.abort();
- if (mPostEntity != null) {
- // If there is a post entity, we need to wake it up from
- // a potential deadlock
- mPostEntity.signalOutputStream();
- }
- }
- }
- }
-
- /**
- * simple buffer class implementing a producer/consumer model
- */
- class Buffer {
- private DataPacket mPacket;
- private boolean mEmpty = true;
- public synchronized void put(DataPacket packet) {
- while (!mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while putting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mPacket = packet;
- mEmpty = false;
- notify();
- }
- public synchronized DataPacket get() {
- while (mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while getting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mEmpty = true;
- notify();
- return mPacket;
- }
- }
-
- /**
- * utility class used to block until the packet is signaled as being
- * consumed
- */
- class SignalConsumed {
- private boolean mConsumed = false;
- public synchronized void waitUntilPacketConsumed() {
- while (!mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while waiting " +
- "until a DataPacket is consumed: " + e);
- }
- }
- }
- mConsumed = false;
- notify();
- }
- public synchronized void packetConsumed() {
- while (mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while indicating "
- + "that the DataPacket has been consumed: " + e);
- }
- }
- }
- mConsumed = true;
- notify();
- }
- }
-
- /**
- * Utility class encapsulating a packet of data
- */
- class DataPacket {
- private byte[] mContent;
- private int mLength;
- public DataPacket(byte[] content, int length) {
- mContent = content;
- mLength = length;
- }
- public byte[] getBytes() {
- return mContent;
- }
- public int getLength() {
- return mLength;
- }
- }
-
- /**
- * HttpEntity class to write the bytes received by the C++ thread
- * on the connection outputstream, in a streaming way.
- * This entity is executed in the request thread.
- * The writeTo() method is automatically called by the
- * HttpPost execution; upon reception, we loop while receiving
- * the data packets from the main thread, until completion
- * or error. When done, we flush the outputstream.
- * The main thread (sendPostData()) also blocks until the
- * outputstream is made available (or an error happens)
- */
- class StreamEntity implements HttpEntity {
- private OutputStream mOutputStream;
-
- // HttpEntity interface methods
-
- public boolean isRepeatable() {
- return false;
- }
-
- public boolean isChunked() {
- return false;
- }
-
- public long getContentLength() {
- return mContentLength;
- }
-
- public Header getContentType() {
- return null;
- }
-
- public Header getContentEncoding() {
- return null;
- }
-
- public InputStream getContent() throws IOException {
- return null;
- }
-
- public void writeTo(final OutputStream out) throws IOException {
- // We signal that the outputstream is available
- mStreamingReadyLock.lock();
- mOutputStream = out;
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
-
- // We then loop waiting on messages to process.
- boolean finished = false;
- while (!finished) {
- DataPacket packet = mBuffer.get();
- if (packet == null) {
- finished = true;
- } else {
- write(packet);
- }
- mSignal.packetConsumed();
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "stopping loop on error");
- }
- finished = true;
- }
- mConnectionFailedLock.unlock();
- }
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "flushing the outputstream...");
- }
- mOutputStream.flush();
- }
-
- public boolean isStreaming() {
- return true;
- }
-
- public void consumeContent() throws IOException {
- // Nothing to release
- }
-
- // local methods
-
- private void write(DataPacket packet) {
- try {
- if (mOutputStream == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "NO OUTPUT STREAM !!!");
- }
- return;
- }
- mOutputStream.write(packet.getBytes(), 0, packet.getLength());
- mOutputStream.flush();
- } catch (IOException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "exc: " + e);
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- }
- }
-
- public boolean isReady() {
- mStreamingReadyLock.lock();
- try {
- if (mOutputStream == null) {
- mStreamingReady.await();
- }
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException in "
- + "StreamEntity::isReady() : ", e);
- }
- } finally {
- mStreamingReadyLock.unlock();
- }
- if (mOutputStream == null) {
- return false;
- }
- return true;
- }
-
- public void signalOutputStream() {
- mStreamingReadyLock.lock();
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
- }
- }
-
- /**
- * Initialize mBridgeThread using the TLS value of
- * Thread.currentThread(). Called on start up of the native child
- * thread.
- */
- public synchronized void initChildThread() {
- mBridgeThread = Thread.currentThread();
- }
-
- public void setContentLength(long length) {
- mContentLength = length;
- }
-
- /**
- * Analagous to the native-side HttpRequest::open() function. This
- * initializes an underlying HttpClient method, but does
- * not go to the wire. On success, this enables a call to send() to
- * initiate the transaction.
- *
- * @param method The HTTP method, e.g GET or POST.
- * @param url The URL to open.
- * @return True on success with a complete HTTP response.
- * False on failure.
- */
- public synchronized boolean open(String method, String url) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "open " + method + " " + url);
- }
- // Create the client
- if (mConnectionFailed) {
- // interrupt() could have been called even before open()
- return false;
- }
- mClient = new DefaultHttpClient();
- mClient.setHttpRequestRetryHandler(
- new DefaultHttpRequestRetryHandler(0, false));
- mBodyInputStream = null;
- mResponseLine = null;
- mResponseHeaders = null;
- mPostEntity = null;
- mHttpThread = null;
- mConnectionFailed = false;
- mConnectionFinished = false;
-
- // Create the method. We support everything that
- // Apache HttpClient supports, apart from TRACE.
- if ("GET".equalsIgnoreCase(method)) {
- mMethod = new HttpGet(url);
- } else if ("POST".equalsIgnoreCase(method)) {
- mMethod = new HttpPost(url);
- mPostEntity = new StreamEntity();
- ((HttpPost)mMethod).setEntity(mPostEntity);
- } else if ("HEAD".equalsIgnoreCase(method)) {
- mMethod = new HttpHead(url);
- } else if ("PUT".equalsIgnoreCase(method)) {
- mMethod = new HttpPut(url);
- } else if ("DELETE".equalsIgnoreCase(method)) {
- mMethod = new HttpDelete(url);
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Method " + method + " not supported");
- }
- return false;
- }
- HttpParams params = mClient.getParams();
- // We handle the redirections C++-side
- HttpClientParams.setRedirecting(params, false);
- HttpProtocolParams.setUseExpectContinue(params, false);
- return true;
- }
-
- /**
- * We use this to start the connection thread (doing the method execute).
- * We usually always return true here, as the connection will run its
- * course in the thread.
- * We only return false if interrupted beforehand -- if a connection
- * problem happens, we will thus fail in either sendPostData() or
- * parseHeaders().
- */
- public synchronized boolean connectToRemote() {
- boolean ret = false;
- applyRequestHeaders();
- mConnectionFailedLock.lock();
- if (!mConnectionFailed) {
- mHttpThread = new Thread(new Connection());
- mHttpThread.start();
- }
- ret = mConnectionFailed;
- mConnectionFailedLock.unlock();
- return !ret;
- }
-
- /**
- * Get the complete response line of the HTTP request. Only valid on
- * completion of the transaction.
- * @return The complete HTTP response line, e.g "HTTP/1.0 200 OK".
- */
- public synchronized String getResponseLine() {
- return mResponseLine;
- }
-
- /**
- * Wait for the request thread completion
- * (unless already finished)
- */
- private void waitUntilConnectionFinished() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "waitUntilConnectionFinished("
- + mConnectionFinished + ")");
- }
- if (!mConnectionFinished) {
- if (mHttpThread != null) {
- try {
- mHttpThread.join();
- mConnectionFinished = true;
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "http thread joined");
- }
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "interrupted: " + e);
- }
- }
- } else {
- Log.e(LOG_TAG, ">>> Trying to join on mHttpThread " +
- "when it does not exist!");
- }
- }
- }
-
- // Headers handling
-
- /**
- * Receive all headers from the server and populate
- * mResponseHeaders.
- * @return True if headers are successfully received, False on
- * connection error.
- */
- public synchronized boolean parseHeaders() {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- waitUntilConnectionFinished();
- mResponseHeaders = new HashMap<String, String[]>();
- if (mResponse == null)
- return false;
-
- Header[] headers = mResponse.getAllHeaders();
- for (int i = 0; i < headers.length; i++) {
- Header header = headers[i];
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "header " + header.getName()
- + " -> " + header.getValue());
- }
- setResponseHeader(header.getName(), header.getValue());
- }
-
- return true;
- }
-
- /**
- * Set a header to send with the HTTP request. Will not take effect
- * on a transaction already in progress. The key is associated
- * case-insensitive, but stored case-sensitive.
- * @param name The name of the header, e.g "Set-Cookie".
- * @param value The value for this header, e.g "text/html".
- */
- public synchronized void setRequestHeader(String name, String value) {
- String[] mapValue = { name, value };
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "setRequestHeader: " + name + " => " + value);
- }
- if (name.equalsIgnoreCase(KEY_CONTENT_LENGTH)) {
- setContentLength(Long.parseLong(value));
- } else {
- mRequestHeaders.put(name.toLowerCase(), mapValue);
- }
- }
-
- /**
- * Returns the value associated with the given request header.
- * @param name The name of the request header, non-null, case-insensitive.
- * @return The value associated with the request header, or null if
- * not set, or error.
- */
- public synchronized String getRequestHeader(String name) {
- String[] value = mRequestHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- private void applyRequestHeaders() {
- if (mMethod == null)
- return;
- Iterator<String[]> it = mRequestHeaders.values().iterator();
- while (it.hasNext()) {
- // Set the key case-sensitive.
- String[] entry = it.next();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "apply header " + entry[HEADERS_MAP_INDEX_KEY] +
- " => " + entry[HEADERS_MAP_INDEX_VALUE]);
- }
- mMethod.setHeader(entry[HEADERS_MAP_INDEX_KEY],
- entry[HEADERS_MAP_INDEX_VALUE]);
- }
- }
-
- /**
- * Returns the value associated with the given response header.
- * @param name The name of the response header, non-null, case-insensitive.
- * @return The value associated with the response header, or null if
- * not set or error.
- */
- public synchronized String getResponseHeader(String name) {
- if (mResponseHeaders != null) {
- String[] value = mResponseHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "getResponseHeader() called but "
- + "response not received");
- }
- return null;
- }
- }
-
- /**
- * Return all response headers, separated by CR-LF line endings, and
- * ending with a trailing blank line. This mimics the format of the
- * raw response header up to but not including the body.
- * @return A string containing the entire response header.
- */
- public synchronized String getAllResponseHeaders() {
- if (mResponseHeaders == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "getAllResponseHeaders() called but "
- + "response not received");
- }
- return null;
- }
- StringBuilder result = new StringBuilder();
- Iterator<String[]> it = mResponseHeaders.values().iterator();
- while (it.hasNext()) {
- String[] entry = it.next();
- // Output the "key: value" lines.
- result.append(entry[HEADERS_MAP_INDEX_KEY]);
- result.append(": ");
- result.append(entry[HEADERS_MAP_INDEX_VALUE]);
- result.append(HTTP_LINE_ENDING);
- }
- result.append(HTTP_LINE_ENDING);
- return result.toString();
- }
-
-
- /**
- * Set a response header and associated value. The key is associated
- * case-insensitively, but stored case-sensitively.
- * @param name Case sensitive request header key.
- * @param value The associated value.
- */
- private void setResponseHeader(String name, String value) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Set response header " + name + ": " + value);
- }
- String mapValue[] = { name, value };
- mResponseHeaders.put(name.toLowerCase(), mapValue);
- }
-
- // Cookie handling
-
- /**
- * Get the cookie for the given URL.
- * @param url The fully qualified URL.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static String getCookieForUrl(String url) {
- // Get the cookie for this URL, set as a header
- return CookieManager.getInstance().getCookie(url);
- }
-
- /**
- * Set the cookie for the given URL.
- * @param url The fully qualified URL.
- * @param cookie The new cookie value.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static void setCookieForUrl(String url, String cookie) {
- // Get the cookie for this URL, set as a header
- CookieManager.getInstance().setCookie(url, cookie);
- }
-
- // Cache handling
-
- /**
- * Perform a request using LocalServer if possible. Initializes
- * class members so that receive() will obtain data from the stream
- * provided by the response.
- * @param url The fully qualified URL to try in LocalServer.
- * @return True if the url was found and is now setup to receive.
- * False if not found, with no side-effect.
- */
- public synchronized boolean useLocalServerResult(String url) {
- UrlInterceptHandlerGears handler =
- UrlInterceptHandlerGears.getInstance();
- if (handler == null) {
- return false;
- }
- UrlInterceptHandlerGears.ServiceResponse serviceResponse =
- handler.getServiceResponse(url, mRequestHeaders);
- if (serviceResponse == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No response in LocalServer");
- }
- return false;
- }
- // LocalServer will handle this URL. Initialize stream and
- // response.
- mBodyInputStream = serviceResponse.getInputStream();
- mResponseLine = serviceResponse.getStatusLine();
- mResponseHeaders = serviceResponse.getResponseHeaders();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got response from LocalServer: " + mResponseLine);
- }
- return true;
- }
-
- /**
- * Perform a request using the cache result if present. Initializes
- * class members so that receive() will obtain data from the cache.
- * @param url The fully qualified URL to try in the cache.
- * @return True is the url was found and is now setup to receive
- * from cache. False if not found, with no side-effect.
- */
- public synchronized boolean useCacheResult(String url) {
- // Try the browser's cache. CacheManager wants a Map<String, String>.
- Map<String, String> cacheRequestHeaders = new HashMap<String, String>();
- Iterator<Map.Entry<String, String[]>> it =
- mRequestHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- cacheRequestHeaders.put(
- entry.getKey(),
- entry.getValue()[HEADERS_MAP_INDEX_VALUE]);
- }
- CacheResult mCacheResult =
- CacheManager.getCacheFile(url, cacheRequestHeaders);
- if (mCacheResult == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No CacheResult for " + url);
- }
- return false;
- }
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got CacheResult from browser cache");
- }
- // Check for expiry. -1 is "never", otherwise milliseconds since 1970.
- // Can be compared to System.currentTimeMillis().
- long expires = mCacheResult.getExpires();
- if (expires >= 0 && System.currentTimeMillis() >= expires) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "CacheResult expired "
- + (System.currentTimeMillis() - expires)
- + " milliseconds ago");
- }
- // Cache hit has expired. Do not return it.
- return false;
- }
- // Setup the mBodyInputStream to come from the cache.
- mBodyInputStream = mCacheResult.getInputStream();
- if (mBodyInputStream == null) {
- // Cache result may have gone away.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No mBodyInputStream for CacheResult " + url);
- }
- return false;
- }
- // Cache hit. Parse headers.
- synthesizeHeadersFromCacheResult(mCacheResult);
- return true;
- }
-
- /**
- * Take the limited set of headers in a CacheResult and synthesize
- * response headers.
- * @param cacheResult A CacheResult to populate mResponseHeaders with.
- */
- private void synthesizeHeadersFromCacheResult(CacheResult cacheResult) {
- int statusCode = cacheResult.getHttpStatusCode();
- // The status message is informal, so we can greatly simplify it.
- String statusMessage;
- if (statusCode >= 200 && statusCode < 300) {
- statusMessage = "OK";
- } else if (statusCode >= 300 && statusCode < 400) {
- statusMessage = "MOVED";
- } else {
- statusMessage = "UNAVAILABLE";
- }
- // Synthesize the response line.
- mResponseLine = "HTTP/1.1 " + statusCode + " " + statusMessage;
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Synthesized " + mResponseLine);
- }
- // Synthesize the returned headers from cache.
- mResponseHeaders = new HashMap<String, String[]>();
- String contentLength = Long.toString(cacheResult.getContentLength());
- setResponseHeader(KEY_CONTENT_LENGTH, contentLength);
- long expires = cacheResult.getExpires();
- if (expires >= 0) {
- // "Expires" header is valid and finite. Milliseconds since 1970
- // epoch, formatted as RFC-1123.
- String expiresString = DateUtils.formatDate(new Date(expires));
- setResponseHeader(KEY_EXPIRES, expiresString);
- }
- String lastModified = cacheResult.getLastModified();
- if (lastModified != null) {
- // Last modification time of the page. Passed end-to-end, but
- // not used by us.
- setResponseHeader(KEY_LAST_MODIFIED, lastModified);
- }
- String eTag = cacheResult.getETag();
- if (eTag != null) {
- // Entity tag. A kind of GUID to identify identical resources.
- setResponseHeader(KEY_ETAG, eTag);
- }
- String location = cacheResult.getLocation();
- if (location != null) {
- // If valid, refers to the location of a redirect.
- setResponseHeader(KEY_LOCATION, location);
- }
- String mimeType = cacheResult.getMimeType();
- if (mimeType == null) {
- // Use a safe default MIME type when none is
- // specified. "text/plain" is safe to render in the browser
- // window (even if large) and won't be intepreted as anything
- // that would cause execution.
- mimeType = DEFAULT_MIME_TYPE;
- }
- String encoding = cacheResult.getEncoding();
- // Encoding may not be specified. No default.
- String contentType = mimeType;
- if (encoding != null) {
- if (encoding.length() > 0) {
- contentType += "; charset=" + encoding;
- }
- }
- setResponseHeader(KEY_CONTENT_TYPE, contentType);
- }
-
- /**
- * Create a CacheResult for this URL. This enables the repsonse body
- * to be sent in calls to appendCacheResult().
- * @param url The fully qualified URL to add to the cache.
- * @param responseCode The response code returned for the request, e.g 200.
- * @param mimeType The MIME type of the body, e.g "text/plain".
- * @param encoding The encoding, e.g "utf-8". Use "" for unknown.
- */
- public synchronized boolean createCacheResult(
- String url, int responseCode, String mimeType, String encoding) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Making cache entry for " + url);
- }
- // Take the headers and parse them into a format needed by
- // CacheManager.
- Headers cacheHeaders = new Headers();
- Iterator<Map.Entry<String, String[]>> it =
- mResponseHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- cacheHeaders.parseHeader(buffer);
- }
- mCacheResult = CacheManager.createCacheFile(
- url, responseCode, cacheHeaders, mimeType, true);
- if (mCacheResult != null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Saving into cache");
- }
- mCacheResult.setEncoding(encoding);
- mCacheResultUrl = url;
- return true;
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Couldn't create mCacheResult");
- }
- return false;
- }
- }
-
- /**
- * Add data from the response body to the CacheResult created with
- * createCacheResult().
- * @param data A byte array of the next sequential bytes in the
- * response body.
- * @param bytes The number of bytes to write from the start of
- * the array.
- * @return True if all bytes successfully written, false on failure.
- */
- public synchronized boolean appendCacheResult(byte[] data, int bytes) {
- if (mCacheResult == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "appendCacheResult() called without a "
- + "CacheResult initialized");
- }
- return false;
- }
- try {
- mCacheResult.getOutputStream().write(data, 0, bytes);
- } catch (IOException ex) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got IOException writing cache data: " + ex);
- }
- return false;
- }
- return true;
- }
-
- /**
- * Save the completed CacheResult into the CacheManager. This must
- * have been created first with createCacheResult().
- * @return Returns true if the entry has been successfully saved.
- */
- public synchronized boolean saveCacheResult() {
- if (mCacheResult == null || mCacheResultUrl == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Tried to save cache result but "
- + "createCacheResult not called");
- }
- return false;
- }
-
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Saving cache result");
- }
- CacheManager.saveCacheFile(mCacheResultUrl, mCacheResult);
- mCacheResult = null;
- mCacheResultUrl = null;
- return true;
- }
-
- /**
- * Called by the main thread to interrupt the child thread.
- * We do not set mConnectionFailed here as we still need the
- * ability to receive a null packet for sendPostData().
- */
- public synchronized void abort() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "ABORT CALLED");
- }
- if (mMethod != null) {
- mMethod.abort();
- }
- }
-
- /**
- * Interrupt a blocking IO operation and wait for the
- * thread to complete.
- */
- public synchronized void interrupt() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "INTERRUPT CALLED");
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (mMethod != null) {
- mMethod.abort();
- }
- if (mHttpThread != null) {
- waitUntilConnectionFinished();
- }
- }
-
- /**
- * Receive the next sequential bytes of the response body after
- * successful connection. This will receive up to the size of the
- * provided byte array. If there is no body, this will return 0
- * bytes on the first call after connection.
- * @param buf A pre-allocated byte array to receive data into.
- * @return The number of bytes from the start of the array which
- * have been filled, 0 on EOF, or negative on error.
- */
- public synchronized int receive(byte[] buf) {
- if (mBodyInputStream == null) {
- // If this is the first call, setup the InputStream. This may
- // fail if there were headers, but no body returned by the
- // server.
- try {
- if (mResponse != null) {
- HttpEntity entity = mResponse.getEntity();
- mBodyInputStream = entity.getContent();
- }
- } catch (IOException inputException) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Failed to connect InputStream: "
- + inputException);
- }
- // Not unexpected. For example, 404 response return headers,
- // and sometimes a body with a detailed error.
- }
- if (mBodyInputStream == null) {
- // No error stream either. Treat as a 0 byte response.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No InputStream");
- }
- return 0; // EOF.
- }
- }
- int ret;
- try {
- int got = mBodyInputStream.read(buf);
- if (got > 0) {
- // Got some bytes, not EOF.
- ret = got;
- } else {
- // EOF.
- mBodyInputStream.close();
- ret = 0;
- }
- } catch (IOException e) {
- // An abort() interrupts us by calling close() on our stream.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got IOException in mBodyInputStream.read(): ", e);
- }
- ret = -1;
- }
- return ret;
- }
-
- /**
- * For POST method requests, send a stream of data provided by the
- * native side in repeated callbacks.
- * We put the data in mBuffer, and wait until it is consumed
- * by the StreamEntity in the request thread.
- * @param data A byte array containing the data to sent, or null
- * if indicating EOF.
- * @param bytes The number of bytes from the start of the array to
- * send, or 0 if indicating EOF.
- * @return True if all bytes were successfully sent, false on error.
- */
- public boolean sendPostData(byte[] data, int bytes) {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- if (mPostEntity == null) return false;
-
- // We block until the outputstream is available
- // (or in case of connection error)
- if (!mPostEntity.isReady()) return false;
-
- if (data == null && bytes == 0) {
- mBuffer.put(null);
- } else {
- mBuffer.put(new DataPacket(data, bytes));
- }
- mSignal.waitUntilPacketConsumed();
-
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- Log.e(LOG_TAG, "failure");
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- return true;
- }
-
-}
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
deleted file mode 100644
index a7a144b..0000000
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2008 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.provider.Browser;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Utility class to create a shortcut on Android
- */
-public class DesktopAndroid {
-
- private static final String TAG = "Gears-J-Desktop";
- private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
- private static final String ACTION_INSTALL_SHORTCUT =
- "com.android.launcher.action.INSTALL_SHORTCUT";
-
- // Android now enforces a 64x64 limit for the icon
- private static int MAX_WIDTH = 64;
- private static int MAX_HEIGHT = 64;
-
- /**
- * Small utility function returning a Bitmap object.
- *
- * @param path the icon path
- */
- private static Bitmap getBitmap(String path) {
- return BitmapFactory.decodeFile(path);
- }
-
- /**
- * Create a shortcut for a webpage.
- *
- * <p>To set a shortcut on Android, we use the ACTION_INSTALL_SHORTCUT
- * from the default Home application. We only have to create an Intent
- * containing extra parameters specifying the shortcut.
- * <p>Note: the shortcut mechanism is not system wide and depends on the
- * Home application; if phone carriers decide to rewrite a Home application
- * that does not accept this Intent, no shortcut will be added.
- *
- * @param webview the webview we are called from
- * @param title the shortcut's title
- * @param url the shortcut's url
- * @param imagePath the local path of the shortcut's icon
- */
- public static void setShortcut(WebView webview, String title,
- String url, String imagePath) {
- Context context = webview.getContext();
-
- Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
- viewWebPage.setData(Uri.parse(url));
- long urlHash = url.hashCode();
- long uniqueId = (urlHash << 32) | viewWebPage.hashCode();
- viewWebPage.putExtra(Browser.EXTRA_APPLICATION_ID,
- Long.toString(uniqueId));
-
- Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
- intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
-
- // We disallow the creation of duplicate shortcuts (i.e. same
- // url, same title, but different screen position).
- intent.putExtra(EXTRA_SHORTCUT_DUPLICATE, false);
-
- Bitmap bmp = getBitmap(imagePath);
- if (bmp != null) {
- if ((bmp.getWidth() > MAX_WIDTH) ||
- (bmp.getHeight() > MAX_HEIGHT)) {
- Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp,
- MAX_WIDTH, MAX_HEIGHT, true);
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
- } else {
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bmp);
- }
- } else {
- // This should not happen as we just downloaded the icon
- Log.e(TAG, "icon file <" + imagePath + "> not found");
- }
-
- context.sendBroadcast(intent);
- }
-
-}
diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java
deleted file mode 100644
index 9e2b375..0000000
--- a/core/java/android/webkit/gears/NativeDialog.java
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2008 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import java.io.File;
-import java.lang.InterruptedException;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Utility class to call a modal native dialog on Android
- * The dialog itself is an Activity defined in the Browser.
- * @hide
- */
-public class NativeDialog {
-
- private static final String TAG = "Gears-J-NativeDialog";
-
- private final String DIALOG_PACKAGE = "com.android.browser";
- private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog";
-
- private static Lock mLock = new ReentrantLock();
- private static Condition mDialogFinished = mLock.newCondition();
- private static String mResults = null;
-
- private static boolean mAsynchronousDialog;
-
- /**
- * Utility function to build the intent calling the
- * dialog activity
- */
- private Intent createIntent(String type, String arguments) {
- Intent intent = new Intent();
- intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra("dialogArguments", arguments);
- intent.putExtra("dialogType", type);
- return intent;
- }
-
- /**
- * Opens a native dialog synchronously and waits for its completion.
- *
- * The dialog is an activity (GearsNativeDialog) provided by the Browser
- * that we call via startActivity(). Contrary to a normal activity though,
- * we need to block until it returns. To do so, we define a static lock
- * object in this class, which GearsNativeDialog can unlock once done
- */
- public String showDialog(Context context, String file,
- String arguments) {
-
- try {
- mAsynchronousDialog = false;
- mLock.lock();
- File path = new File(file);
- String fileName = path.getName();
- String type = fileName.substring(0, fileName.indexOf(".html"));
- Intent intent = createIntent(type, arguments);
-
- mResults = null;
- context.startActivity(intent);
- mDialogFinished.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "exception e: " + e);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "exception e: " + e);
- } finally {
- mLock.unlock();
- }
-
- return mResults;
- }
-
- /**
- * Opens a native dialog asynchronously
- *
- * The dialog is an activity (GearsNativeDialog) provided by the
- * Browser.
- */
- public void showAsyncDialog(Context context, String type,
- String arguments) {
- mAsynchronousDialog = true;
- Intent intent = createIntent(type, arguments);
- context.startActivity(intent);
- }
-
- /**
- * Static method that GearsNativeDialog calls to unlock us
- */
- public static void signalFinishedDialog() {
- if (!mAsynchronousDialog) {
- mLock.lock();
- mDialogFinished.signal();
- mLock.unlock();
- } else {
- // we call the native callback
- closeAsynchronousDialog(mResults);
- }
- }
-
- /**
- * Static method that GearsNativeDialog calls to set the
- * dialog's result
- */
- public static void closeDialog(String res) {
- mResults = res;
- }
-
- /**
- * Native callback method
- */
- private native static void closeAsynchronousDialog(String res);
-}
diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java
deleted file mode 100644
index 2d0cc13..0000000
--- a/core/java/android/webkit/gears/PluginSettings.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2008 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.util.Log;
-import android.webkit.Plugin;
-import android.webkit.Plugin.PreferencesClickHandler;
-
-/**
- * Simple bridge class intercepting the click in the
- * browser plugin list and calling the Gears settings
- * dialog.
- */
-public class PluginSettings {
-
- private static final String TAG = "Gears-J-PluginSettings";
- private Context mContext;
-
- public PluginSettings(Plugin plugin) {
- plugin.setClickHandler(new ClickHandler());
- }
-
- /**
- * We do not call the dialog synchronously here as the main
- * message loop would be blocked, so we call it via a secondary thread.
- */
- private class ClickHandler implements PreferencesClickHandler {
- public void handleClickEvent(Context context) {
- mContext = context.getApplicationContext();
- Thread startDialog = new Thread(new StartDialog(context));
- startDialog.start();
- }
- }
-
- /**
- * Simple wrapper class to call the gears native method in
- * a separate thread (the native code will then instanciate a NativeDialog
- * object which will start the GearsNativeDialog activity defined in
- * the Browser).
- */
- private class StartDialog implements Runnable {
- Context mContext;
-
- public StartDialog(Context context) {
- mContext = context;
- }
-
- public void run() {
- runSettingsDialog(mContext);
- }
- }
-
- private static native void runSettingsDialog(Context c);
-
-}
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
deleted file mode 100644
index 43104bf..0000000
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.util.Log;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.Plugin;
-import android.webkit.PluginData;
-import android.webkit.UrlInterceptRegistry;
-import android.webkit.UrlInterceptHandler;
-import android.webkit.WebView;
-
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * Services requests to handle URLs coming from the browser or
- * HttpRequestAndroid. This registers itself with the
- * UrlInterceptRegister in Android so we get a chance to service all
- * URLs passing through the browser before anything else.
- */
-public class UrlInterceptHandlerGears implements UrlInterceptHandler {
- /** Singleton instance. */
- private static UrlInterceptHandlerGears instance;
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** Buffer size for reading/writing streams. */
- private static final int BUFFER_SIZE = 4096;
- /** Enable/disable all logging in this class. */
- private static boolean logEnabled = false;
- /** The unmodified (case-sensitive) key in the headers map is the
- * same index as used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_KEY =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_KEY;
- /** The associated value in the headers map is the same index as
- * used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_VALUE =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_VALUE;
-
- /**
- * Object passed to the native side, containing information about
- * the URL to service.
- */
- public static class ServiceRequest {
- // The URL being requested.
- private String url;
- // Request headers. Map of lowercase key to [ unmodified key, value ].
- private Map<String, String[]> requestHeaders;
-
- /**
- * Initialize members on construction.
- * @param url The URL being requested.
- * @param requestHeaders Headers associated with the request,
- * or null if none.
- * Map of lowercase key to [ unmodified key, value ].
- */
- public ServiceRequest(String url, Map<String, String[]> requestHeaders) {
- this.url = url;
- this.requestHeaders = requestHeaders;
- }
-
- /**
- * Returns the URL being requested.
- * @return The URL being requested.
- */
- public String getUrl() {
- return url;
- }
-
- /**
- * Get the value associated with a request header key, if any.
- * @param header The key to find, case insensitive.
- * @return The value associated with this header, or null if not found.
- */
- public String getRequestHeader(String header) {
- if (requestHeaders != null) {
- String[] value = requestHeaders.get(header.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
- }
-
- /**
- * Object returned by the native side, containing information needed
- * to pass the entire response back to the browser or
- * HttpRequestAndroid. Works from either an in-memory array or a
- * file on disk.
- */
- public class ServiceResponse {
- // The response status code, e.g 200.
- private int statusCode;
- // The full status line, e.g "HTTP/1.1 200 OK".
- private String statusLine;
- // All headers associated with the response. Map of lowercase key
- // to [ unmodified key, value ].
- private Map<String, String[]> responseHeaders =
- new HashMap<String, String[]>();
- // The MIME type, e.g "text/html".
- private String mimeType;
- // The encoding, e.g "utf-8", or null if none.
- private String encoding;
- // The stream which contains the body when read().
- private InputStream inputStream;
- // The length of the content body.
- private long contentLength;
-
- /**
- * Initialize members using an in-memory array to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param body The response body as a byte array, non-empty.
- */
- void setResultArray(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- byte[] body) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- // Setup a stream to read out of the byte array.
- this.contentLength = body.length;
- this.inputStream = new ByteArrayInputStream(body);
- }
-
- /**
- * Initialize members using a file on disk to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param path Full path to the file containing the body.
- * @return True if the file is successfully setup to stream,
- * false on error such as file not found.
- */
- boolean setResultFile(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- String path) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- try {
- // Setup a stream to read out of a file on disk.
- File file = new File(path);
- this.contentLength = file.length();
- this.inputStream = new FileInputStream(file);
- return true;
- } catch (java.io.FileNotFoundException ex) {
- log("File not found: " + path);
- return false;
- }
- }
-
- /**
- * Set a response header, adding its settings to the header members.
- * @param key The case sensitive key for the response header,
- * e.g "Set-Cookie".
- * @param value The value associated with this key, e.g "cookie1234".
- */
- public void setResponseHeader(String key, String value) {
- // The map value contains the unmodified key (not lowercase).
- String[] mapValue = { key, value };
- responseHeaders.put(key.toLowerCase(), mapValue);
- }
-
- /**
- * Return the "Content-Type" header possibly supplied by a
- * previous setResponseHeader().
- * @return The "Content-Type" value, or null if not present.
- */
- public String getContentType() {
- // The map keys are lowercase.
- String[] value = responseHeaders.get("content-type");
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- /**
- * Returns the HTTP status code for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue code, e.g 200.
- */
- public int getStatusCode() {
- return statusCode;
- }
-
- /**
- * Returns the full HTTP status line for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue line, e.g "HTTP/1.1 200 OK".
- */
- public String getStatusLine() {
- return statusLine;
- }
-
- /**
- * Get all response headers supplied in calls in
- * setResponseHeader().
- * @return A Map<String, String[]> containing all headers.
- */
- public Map<String, String[]> getResponseHeaders() {
- return responseHeaders;
- }
-
- /**
- * Returns the MIME type for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The MIME type, e.g "text/html".
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Returns the encoding for the response, supplied in
- * setResultArray() or setResultFile(), or null if none.
- * @return The encoding, e.g "utf-8", or null if none.
- */
- public String getEncoding() {
- return encoding;
- }
-
- /**
- * Returns the InputStream setup by setResultArray() or
- * setResultFile() to allow reading data either from memory or
- * disk.
- * @return The InputStream containing the response body.
- */
- public InputStream getInputStream() {
- return inputStream;
- }
-
- /**
- * @return The length of the response body.
- */
- public long getContentLength() {
- return contentLength;
- }
- }
-
- /**
- * Construct and initialize the singleton instance.
- */
- public UrlInterceptHandlerGears() {
- if (instance != null) {
- Log.e(LOG_TAG, "UrlInterceptHandlerGears singleton already constructed");
- throw new RuntimeException();
- }
- instance = this;
- }
-
- /**
- * Turn on/off logging in this class.
- * @param on Logging enable state.
- */
- public static void enableLogging(boolean on) {
- logEnabled = on;
- }
-
- /**
- * Get the singleton instance.
- * @return The singleton instance.
- */
- public static UrlInterceptHandlerGears getInstance() {
- return instance;
- }
-
- /**
- * Register the singleton instance with the browser's interception
- * mechanism.
- */
- public synchronized void register() {
- UrlInterceptRegistry.registerHandler(this);
- }
-
- /**
- * Unregister the singleton instance from the browser's interception
- * mechanism.
- */
- public synchronized void unregister() {
- UrlInterceptRegistry.unregisterHandler(this);
- }
-
- /**
- * Given an URL, returns the CacheResult which contains the
- * surrogate response for the request, or null if the handler is
- * not interested.
- *
- * @param url URL string.
- * @param headers The headers associated with the request. May be null.
- * @return The CacheResult containing the surrogate response.
- * @Deprecated Use PluginData getPluginData(String url,
- * Map<String, String> headers); instead
- */
- @Deprecated
- public CacheResult service(String url, Map<String, String> headers) {
- throw new UnsupportedOperationException("unimplemented");
- }
-
- /**
- * Given an URL, returns a PluginData instance which contains the
- * response for the request. This implements the UrlInterceptHandler
- * interface.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return a PluginData object.
- */
- public PluginData getPluginData(String url, Map<String, String> requestHeaders) {
- // Thankfully the browser does call us with case-sensitive
- // headers. We just need to map it case-insensitive.
- Map<String, String[]> lowercaseRequestHeaders =
- new HashMap<String, String[]>();
- Iterator<Map.Entry<String, String>> requestHeadersIt =
- requestHeaders.entrySet().iterator();
- while (requestHeadersIt.hasNext()) {
- Map.Entry<String, String> entry = requestHeadersIt.next();
- String key = entry.getKey();
- String mapValue[] = { key, entry.getValue() };
- lowercaseRequestHeaders.put(key.toLowerCase(), mapValue);
- }
- ServiceResponse response = getServiceResponse(url, lowercaseRequestHeaders);
- if (response == null) {
- // No result for this URL.
- return null;
- }
- return new PluginData(response.getInputStream(),
- response.getContentLength(),
- response.getResponseHeaders(),
- response.getStatusCode());
- }
-
- /**
- * Given an URL, returns a CacheResult and headers which contain the
- * response for the request.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a ServiceResponse is
- * created which contains all response headers and an InputStream
- * attached to the body. If there is no response, null is returned.
- */
- public ServiceResponse getServiceResponse(String url,
- Map<String, String[]> requestHeaders) {
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
- // Don't know how to service non-HTTP URLs
- return null;
- }
- // Call the native handler to craft a response for this URL.
- return nativeService(new ServiceRequest(url, requestHeaders));
- }
-
- /**
- * Convenience debug function. Calls the Android logging
- * mechanism. logEnabled is not a constant, so if the string
- * evaluation is potentially expensive, the caller also needs to
- * check it.
- * @param str String to log to the Android console.
- */
- private void log(String str) {
- if (logEnabled) {
- Log.i(LOG_TAG, str);
- }
- }
-
- /**
- * Native method which handles the bulk of the request in LocalServer.
- * @param request A ServiceRequest object containing information about
- * the request.
- * @return If serviced, a ServiceResponse object containing all the
- * information to provide a response for the URL, or null
- * if no response available for this URL.
- */
- private native static ServiceResponse nativeService(ServiceRequest request);
-}
diff --git a/core/java/android/webkit/gears/VersionExtractor.java b/core/java/android/webkit/gears/VersionExtractor.java
deleted file mode 100644
index 172dacb..0000000
--- a/core/java/android/webkit/gears/VersionExtractor.java
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.util.Log;
-import java.io.IOException;
-import java.io.StringReader;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.FactoryConfigurationError;
-import javax.xml.parsers.ParserConfigurationException;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.w3c.dom.Document;
-import org.w3c.dom.DOMException;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * A class that can extract the Gears version and upgrade URL from an
- * xml document.
- */
-public final class VersionExtractor {
-
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-VersionExtractor";
- /**
- * XML element names.
- */
- private static final String VERSION = "em:version";
- private static final String URL = "em:updateLink";
-
- /**
- * Parses the input xml string and invokes the native
- * setVersionAndUrl method.
- * @param xml is the XML string to parse.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean extract(String xml, long nativeObject) {
- try {
- // Build the builders.
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
-
- // Create the document.
- Document doc = builder.parse(new InputSource(new StringReader(xml)));
-
- // Look for the version and url elements and get their text
- // contents.
- String version = extractText(doc, VERSION);
- String url = extractText(doc, URL);
-
- // If we have both, let the native side know.
- if (version != null && url != null) {
- setVersionAndUrl(version, url, nativeObject);
- return true;
- }
-
- return false;
-
- } catch (FactoryConfigurationError ex) {
- Log.e(TAG, "Could not create the DocumentBuilderFactory " + ex);
- } catch (ParserConfigurationException ex) {
- Log.e(TAG, "Could not create the DocumentBuilder " + ex);
- } catch (SAXException ex) {
- Log.e(TAG, "Could not parse the xml " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read the xml " + ex);
- }
-
- return false;
- }
-
- /**
- * Extracts the text content of the first element with the given name.
- * @param doc is the Document where the element is searched for.
- * @param elementName is name of the element to searched for.
- * @return the text content of the element or null if no such
- * element is found.
- */
- private static String extractText(Document doc, String elementName) {
- String text = null;
- NodeList node_list = doc.getElementsByTagName(elementName);
-
- if (node_list.getLength() > 0) {
- // We are only interested in the first node. Normally there
- // should not be more than one anyway.
- Node node = node_list.item(0);
-
- // Iterate through the text children.
- NodeList child_list = node.getChildNodes();
-
- try {
- for (int i = 0; i < child_list.getLength(); ++i) {
- Node child = child_list.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- if (text == null) {
- text = new String();
- }
- text += child.getNodeValue();
- }
- }
- } catch (DOMException ex) {
- Log.e(TAG, "getNodeValue() failed " + ex);
- }
- }
-
- if (text != null) {
- text = text.trim();
- }
-
- return text;
- }
-
- /**
- * Native method used to send the version and url back to the C++
- * side.
- */
- private static native void setVersionAndUrl(
- String version, String url, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ZipInflater.java b/core/java/android/webkit/gears/ZipInflater.java
deleted file mode 100644
index f6b6be5..0000000
--- a/core/java/android/webkit/gears/ZipInflater.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2008, 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:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. 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.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-
-package android.webkit.gears;
-
-import android.os.StatFs;
-import android.util.Log;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-
-
-/**
- * A class that can inflate a zip archive.
- */
-public final class ZipInflater {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-ZipInflater";
-
- /**
- * The size of the buffer used to read from the archive.
- */
- private static final int BUFFER_SIZE_BYTES = 32 * 1024; // 32 KB.
- /**
- * The path navigation component (i.e. "../").
- */
- private static final String PATH_NAVIGATION_COMPONENT = ".." + File.separator;
- /**
- * The root of the data partition.
- */
- private static final String DATA_PARTITION_ROOT = "/data";
-
- /**
- * We need two be able to store two versions of gears in parallel:
- * - the zipped version
- * - the unzipped version, which will be loaded next time the browser is started.
- * We are conservative and do not attempt to unpack unless there enough free
- * space on the device to store 4 times the new Gears size.
- */
- private static final long SIZE_MULTIPLIER = 4;
-
- /**
- * Unzips the archive with the given name.
- * @param filename is the name of the zip to inflate.
- * @param path is the path where the zip should be unpacked. It must contain
- * a trailing separator, or the extraction will fail.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean inflate(String filename, String path) {
- Log.i(TAG, "Extracting " + filename + " to " + path);
-
- // Check that the path ends with a separator.
- if (!path.endsWith(File.separator)) {
- Log.e(TAG, "Path missing trailing separator: " + path);
- return false;
- }
-
- boolean result = false;
-
- // Use a ZipFile to get an enumeration of the entries and
- // calculate the overall uncompressed size of the archive. Also
- // check for existing files or directories that have the same
- // name as the entries in the archive. Also check for invalid
- // entry names (e.g names that attempt to navigate to the
- // parent directory).
- ZipInputStream zipStream = null;
- long uncompressedSize = 0;
- try {
- ZipFile zipFile = new ZipFile(filename);
- try {
- Enumeration entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
- uncompressedSize += entry.getSize();
- // Check against entry names that may attempt to navigate
- // out of the destination directory.
- if (entry.getName().indexOf(PATH_NAVIGATION_COMPONENT) >= 0) {
- throw new IOException("Illegal entry name: " + entry.getName());
- }
-
- // Check against entries with the same name as pre-existing files or
- // directories.
- File file = new File(path + entry.getName());
- if (file.exists()) {
- // A file or directory with the same name already exist.
- // This must not happen, so we treat this as an error.
- throw new IOException(
- "A file or directory with the same name already exists.");
- }
- }
- } finally {
- zipFile.close();
- }
-
- Log.i(TAG, "Determined uncompressed size: " + uncompressedSize);
- // Check we have enough space to unpack this archive.
- if (freeSpace() <= uncompressedSize * SIZE_MULTIPLIER) {
- throw new IOException("Not enough space to unpack this archive.");
- }
-
- zipStream = new ZipInputStream(
- new BufferedInputStream(new FileInputStream(filename)));
- ZipEntry entry;
- int counter;
- byte buffer[] = new byte[BUFFER_SIZE_BYTES];
-
- // Iterate through the entries and write each of them to a file.
- while ((entry = zipStream.getNextEntry()) != null) {
- File file = new File(path + entry.getName());
- if (entry.isDirectory()) {
- // If the entry denotes a directory, we need to create a
- // directory with the same name.
- file.mkdirs();
- } else {
- CRC32 checksum = new CRC32();
- BufferedOutputStream output = new BufferedOutputStream(
- new FileOutputStream(file),
- BUFFER_SIZE_BYTES);
- try {
- // Read the entry and write it to the file.
- while ((counter = zipStream.read(buffer, 0, BUFFER_SIZE_BYTES)) !=
- -1) {
- output.write(buffer, 0, counter);
- checksum.update(buffer, 0, counter);
- }
- output.flush();
- } finally {
- output.close();
- }
-
- if (checksum.getValue() != entry.getCrc()) {
- throw new IOException(
- "Integrity check failed for: " + entry.getName());
- }
- }
- zipStream.closeEntry();
- }
-
- result = true;
-
- } catch (FileNotFoundException ex) {
- Log.e(TAG, "The zip file could not be found. " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read or write an entry. " + ex);
- } catch(IllegalArgumentException ex) {
- Log.e(TAG, "Could not create the BufferedOutputStream. " + ex);
- } finally {
- if (zipStream != null) {
- try {
- zipStream.close();
- } catch (IOException ex) {
- // Ignored.
- }
- }
- // Discard any exceptions and return the result to the native side.
- return result;
- }
- }
-
- private static final long freeSpace() {
- StatFs data_partition = new StatFs(DATA_PARTITION_ROOT);
- long freeSpace = data_partition.getAvailableBlocks() *
- data_partition.getBlockSize();
- Log.i(TAG, "Free space on the data partition: " + freeSpace);
- return freeSpace;
- }
-}
diff --git a/core/java/android/webkit/gears/package.html b/core/java/android/webkit/gears/package.html
deleted file mode 100644
index db6f78b..0000000
--- a/core/java/android/webkit/gears/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body>
\ No newline at end of file
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 04cb8a0..f92eb99 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -320,11 +320,6 @@
final int max = getMax();
progress += scale * max;
- if (progress < 0) {
- progress = 0;
- } else if (progress > max) {
- progress = max;
- }
setProgress((int) progress, true);
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 7d2fcbc..fe6d91a 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -163,7 +163,7 @@
/**
* View to show if there are no items to show.
*/
- View mEmptyView;
+ private View mEmptyView;
/**
* The number of items in the current adapter.
diff --git a/core/java/android/widget/AlphabetIndexer.java b/core/java/android/widget/AlphabetIndexer.java
index f50676a..59b2c2a 100644
--- a/core/java/android/widget/AlphabetIndexer.java
+++ b/core/java/android/widget/AlphabetIndexer.java
@@ -28,7 +28,7 @@
* invalidates the cache if changes occur in the cursor.
* <p/>
* Your adapter is responsible for updating the cursor by calling {@link #setCursor} if the
- * cursor changes. {@link #getPositionForSection} method does the binary search for the starting
+ * cursor changes. {@link #getPositionForSection} method does the binary search for the starting
* index of a given section (alphabet).
*/
public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
@@ -37,33 +37,33 @@
* Cursor that is used by the adapter of the list view.
*/
protected Cursor mDataCursor;
-
+
/**
* The index of the cursor column that this list is sorted on.
*/
protected int mColumnIndex;
-
+
/**
* The string of characters that make up the indexing sections.
*/
protected CharSequence mAlphabet;
-
+
/**
* Cached length of the alphabet array.
*/
private int mAlphabetLength;
-
+
/**
* This contains a cache of the computed indices so far. It will get reset whenever
* the dataset changes or the cursor changes.
*/
private SparseIntArray mAlphaMap;
-
+
/**
* Use a collator to compare strings in a localized manner.
*/
private java.text.Collator mCollator;
-
+
/**
* The section array converted from the alphabet string.
*/
@@ -72,9 +72,9 @@
/**
* Constructs the indexer.
* @param cursor the cursor containing the data set
- * @param sortedColumnIndex the column number in the cursor that is sorted
+ * @param sortedColumnIndex the column number in the cursor that is sorted
* alphabetically
- * @param alphabet string containing the alphabet, with space as the first character.
+ * @param alphabet string containing the alphabet, with space as the first character.
* For example, use the string " ABCDEFGHIJKLMNOPQRSTUVWXYZ" for English indexing.
* The characters must be uppercase and be sorted in ascii/unicode order. Basically
* characters in the alphabet will show up as preview letters.
@@ -104,7 +104,7 @@
public Object[] getSections() {
return mAlphabetArray;
}
-
+
/**
* Sets a new cursor as the data set and resets the cache of indices.
* @param cursor the new cursor to use as the data set
@@ -124,9 +124,16 @@
* Default implementation compares the first character of word with letter.
*/
protected int compare(String word, String letter) {
- return mCollator.compare(word.substring(0, 1), letter);
+ final String firstLetter;
+ if (word.length() == 0) {
+ firstLetter = " ";
+ } else {
+ firstLetter = word.substring(0, 1);
+ }
+
+ return mCollator.compare(firstLetter, letter);
}
-
+
/**
* Performs a binary search or cache lookup to find the first row that
* matches a given section's starting letter.
@@ -143,7 +150,7 @@
if (cursor == null || mAlphabet == null) {
return 0;
}
-
+
// Check bounds
if (sectionIndex <= 0) {
return 0;
@@ -164,7 +171,7 @@
int key = letter;
// Check map
if (Integer.MIN_VALUE != (pos = alphaMap.get(key, Integer.MIN_VALUE))) {
- // Is it approximate? Using negative value to indicate that it's
+ // Is it approximate? Using negative value to indicate that it's
// an approximation and positive value when it is the accurate
// position.
if (pos < 0) {
@@ -204,7 +211,7 @@
}
int diff = compare(curName, targetLetter);
if (diff != 0) {
- // Commenting out approximation code because it doesn't work for certain
+ // TODO: Commenting out approximation code because it doesn't work for certain
// lists with custom comparators
// Enter approximation in hash if a better solution doesn't exist
// String startingLetter = Character.toString(getFirstLetter(curName));
@@ -259,9 +266,9 @@
return i;
}
}
- return 0; // Don't recognize the letter - falls under zero'th section
+ return 0; // Don't recognize the letter - falls under zero'th section
}
-
+
/*
* @hide
*/
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 02d77d1..d821a7d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -194,7 +194,7 @@
setFocusable(true);
addTextChangedListener(new MyWatcher());
-
+
mPassThroughClickListener = new PassThroughClickListener();
super.setOnClickListener(mPassThroughClickListener);
}
@@ -321,8 +321,6 @@
* @return the background drawable
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public Drawable getDropDownBackground() {
return mPopup.getBackground();
@@ -334,8 +332,6 @@
* @param d the drawable to set as the background
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public void setDropDownBackgroundDrawable(Drawable d) {
mPopup.setBackgroundDrawable(d);
@@ -347,14 +343,48 @@
* @param id the id of the drawable to set as the background
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public void setDropDownBackgroundResource(int id) {
mPopup.setBackgroundDrawable(getResources().getDrawable(id));
}
-
+
/**
+ * <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
+ *
+ * @param offset the vertical offset
+ */
+ public void setDropDownVerticalOffset(int offset) {
+ mDropDownVerticalOffset = offset;
+ }
+
+ /**
+ * <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
+ *
+ * @return the vertical offset
+ */
+ public int getDropDownVerticalOffset() {
+ return mDropDownVerticalOffset;
+ }
+
+ /**
+ * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
+ *
+ * @param offset the horizontal offset
+ */
+ public void setDropDownHorizontalOffset(int offset) {
+ mDropDownHorizontalOffset = offset;
+ }
+
+ /**
+ * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
+ *
+ * @return the horizontal offset
+ */
+ public int getDropDownHorizontalOffset() {
+ return mDropDownHorizontalOffset;
+ }
+
+ /**
* <p>Sets the animation style of the auto-complete drop-down list.</p>
*
* <p>If the drop-down is showing, calling this method will take effect only
@@ -381,50 +411,6 @@
public int getDropDownAnimationStyle() {
return mPopup.getAnimationStyle();
}
-
- /**
- * <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
- *
- * @param offset the vertical offset
- *
- * @hide Pending API council approval
- */
- public void setDropDownVerticalOffset(int offset) {
- mDropDownVerticalOffset = offset;
- }
-
- /**
- * <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
- *
- * @return the vertical offset
- *
- * @hide Pending API council approval
- */
- public int getDropDownVerticalOffset() {
- return mDropDownVerticalOffset;
- }
-
- /**
- * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
- *
- * @param offset the horizontal offset
- *
- * @hide Pending API council approval
- */
- public void setDropDownHorizontalOffset(int offset) {
- mDropDownHorizontalOffset = offset;
- }
-
- /**
- * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
- *
- * @return the horizontal offset
- *
- * @hide Pending API council approval
- */
- public int getDropDownHorizontalOffset() {
- return mDropDownHorizontalOffset;
- }
/**
* @return Whether the drop-down is visible as long as there is {@link #enoughToFilter()}
@@ -1595,7 +1581,7 @@
*/
CharSequence fixText(CharSequence invalidText);
}
-
+
/**
* Allows us a private hook into the on click event without preventing users from setting
* their own click listener.
@@ -1611,5 +1597,5 @@
if (mWrapped != null) mWrapped.onClick(v);
}
}
-
+
}
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/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index a9822f8..6cc794b 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -59,7 +59,7 @@
* Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
* with whether the children of this layout are baseline aligned.
*/
- private int mBaselineAlignedChildIndex = 0;
+ private int mBaselineAlignedChildIndex = -1;
/**
* The additional offset to the child's baseline.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index f8a6f89..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);
@@ -3264,12 +3265,13 @@
if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
mCheckStates.put(position, value);
} else {
- // Clear the old value: if something was selected and value == false
- // then it is unselected
- mCheckStates.clear();
- // If value == true, select the appropriate position
+ // Clear all values if we're checking something, or unchecking the currently
+ // selected item
+ if (value || isItemChecked(position)) {
+ mCheckStates.clear();
+ }
// this may end up selecting the value we just cleared but this way
- // we don't have to first to a get(position)
+ // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
if (value) {
mCheckStates.put(position, true);
}
@@ -3285,11 +3287,12 @@
/**
* Returns the checked state of the specified position. The result is only
- * valid if the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}
+ * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
* or {@link #CHOICE_MODE_MULTIPLE}.
*
* @param position The item whose checked state to return
- * @return The item's checked state
+ * @return The item's checked state or <code>false</code> if choice mode
+ * is invalid
*
* @see #setChoiceMode(int)
*/
@@ -3303,7 +3306,7 @@
/**
* Returns the currently checked item. The result is only valid if the choice
- * mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+ * mode has been set to {@link #CHOICE_MODE_SINGLE}.
*
* @return The position of the currently checked item or
* {@link #INVALID_POSITION} if nothing is selected
@@ -3320,10 +3323,12 @@
/**
* Returns the set of checked items in the list. The result is only valid if
- * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+ * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
*
* @return A SparseBooleanArray which will return true for each call to
- * get(int position) where position is a position in the list.
+ * get(int position) where position is a position in the list,
+ * or <code>null</code> if the choice mode is set to
+ * {@link #CHOICE_MODE_NONE}.
*/
public SparseBooleanArray getCheckedItemPositions() {
if (mChoiceMode != CHOICE_MODE_NONE) {
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/Scroller.java b/core/java/android/widget/Scroller.java
index c9ace0a..381641f 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.hardware.SensorManager;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -79,9 +80,9 @@
mFinished = true;
mInterpolator = interpolator;
float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = 9.8f // g (m/s^2)
- * 39.37f // inch/meter
- * ppi // pixels per inch
+ mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi // pixels per inch
* ViewConfiguration.getScrollFriction();
}
@@ -347,7 +348,11 @@
}
/**
- *
+ * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+ * aborting the animating cause the scroller to move to the final x and y
+ * position
+ *
+ * @see #forceFinished(boolean)
*/
public void abortAnimation() {
mCurrX = mFinalX;
@@ -356,10 +361,12 @@
}
/**
- * Extend the scroll animation. This allows a running animation to
- * scroll further and longer, when used with setFinalX() or setFinalY().
+ * Extend the scroll animation. This allows a running animation to scroll
+ * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
*
* @param extend Additional time to scroll in milliseconds.
+ * @see #setFinalX(int)
+ * @see #setFinalY(int)
*/
public void extendDuration(int extend) {
int passed = timePassed();
@@ -367,18 +374,37 @@
mDurationReciprocal = 1.0f / (float)mDuration;
mFinished = false;
}
-
+
+ /**
+ * Returns the time elapsed since the beginning of the scrolling.
+ *
+ * @return The elapsed time in milliseconds.
+ */
public int timePassed() {
return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
-
+
+ /**
+ * Sets the final position (X) for this scroller.
+ *
+ * @param newX The new X offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ * @see #setFinalY(int)
+ */
public void setFinalX(int newX) {
mFinalX = newX;
mDeltaX = mFinalX - mStartX;
mFinished = false;
}
- public void setFinalY(int newY) {
+ /**
+ * Sets the final position (Y) for this scroller.
+ *
+ * @param newY The new Y offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ * @see #setFinalX(int)
+ */
+ public void setFinalY(int newY) {
mFinalY = newY;
mDeltaY = mFinalY - mStartY;
mFinished = false;
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index c456f56..a1c65f0 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -26,9 +26,16 @@
* defined in an XML file. You can specify which columns you want, which views
* you want to display the columns, and the XML file that defines the appearance
* of these views. Separate XML files for child and groups are possible.
- * TextViews bind the values to their text property (see
- * {@link TextView#setText(CharSequence)}). ImageViews bind the values to their
- * image's Uri property (see {@link ImageView#setImageURI(android.net.Uri)}).
+ *
+ * Binding occurs in two phases. First, if a
+ * {@link android.widget.SimpleCursorTreeAdapter.ViewBinder} is available,
+ * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
+ * is invoked. If the returned value is true, binding has occurred. If the
+ * returned value is false and the view to bind is a TextView,
+ * {@link #setViewText(TextView, String)} is invoked. If the returned value
+ * is false and the view to bind is an ImageView,
+ * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
+ * binding can be found, an {@link IllegalStateException} is thrown.
*/
public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
/** The indices of columns that contain data to display for a group. */
@@ -48,6 +55,11 @@
private int[] mChildTo;
/**
+ * View binder, if supplied
+ */
+ private ViewBinder mViewBinder;
+
+ /**
* Constructor.
*
* @param context The context where the {@link ExpandableListView}
@@ -193,21 +205,53 @@
initFromColumns(childCursor, childFromNames, mChildFrom);
}
+ /**
+ * Returns the {@link ViewBinder} used to bind data to views.
+ *
+ * @return a ViewBinder or null if the binder does not exist
+ *
+ * @see #setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder)
+ */
+ public ViewBinder getViewBinder() {
+ return mViewBinder;
+ }
+
+ /**
+ * Sets the binder used to bind data to views.
+ *
+ * @param viewBinder the binder used to bind data to views, can be null to
+ * remove the existing binder
+ *
+ * @see #getViewBinder()
+ */
+ public void setViewBinder(ViewBinder viewBinder) {
+ mViewBinder = viewBinder;
+ }
+
private void bindView(View view, Context context, Cursor cursor, int[] from, int[] to) {
+ final ViewBinder binder = mViewBinder;
+
for (int i = 0; i < to.length; i++) {
View v = view.findViewById(to[i]);
if (v != null) {
- String text = cursor.getString(from[i]);
- if (text == null) {
- text = "";
+ boolean bound = false;
+ if (binder != null) {
+ bound = binder.setViewValue(v, cursor, from[i]);
}
- if (v instanceof TextView) {
- ((TextView) v).setText(text);
- } else if (v instanceof ImageView) {
- setViewImage((ImageView) v, text);
- } else {
- throw new IllegalStateException("SimpleCursorAdapter can bind values only to" +
- " TextView and ImageView!");
+
+ if (!bound) {
+ String text = cursor.getString(from[i]);
+ if (text == null) {
+ text = "";
+ }
+ if (v instanceof TextView) {
+ setViewText((TextView) v, text);
+ } else if (v instanceof ImageView) {
+ setViewImage((ImageView) v, text);
+ } else {
+ throw new IllegalStateException("SimpleCursorTreeAdapter can bind values" +
+ " only to TextView and ImageView!");
+ }
}
}
}
@@ -238,4 +282,48 @@
v.setImageURI(Uri.parse(value));
}
}
+
+ /**
+ * Called by bindView() to set the text for a TextView but only if
+ * there is no existing ViewBinder or if the existing ViewBinder cannot
+ * handle binding to an TextView.
+ *
+ * Intended to be overridden by Adapters that need to filter strings
+ * retrieved from the database.
+ *
+ * @param v TextView to receive text
+ * @param text the text to be set for the TextView
+ */
+ public void setViewText(TextView v, String text) {
+ v.setText(text);
+ }
+
+ /**
+ * This class can be used by external clients of SimpleCursorTreeAdapter
+ * to bind values from the Cursor to views.
+ *
+ * You should use this class to bind values from the Cursor to views
+ * that are not directly supported by SimpleCursorTreeAdapter or to
+ * change the way binding occurs for views supported by
+ * SimpleCursorTreeAdapter.
+ *
+ * @see SimpleCursorTreeAdapter#setViewImage(ImageView, String)
+ * @see SimpleCursorTreeAdapter#setViewText(TextView, String)
+ */
+ public static interface ViewBinder {
+ /**
+ * Binds the Cursor column defined by the specified index to the specified view.
+ *
+ * When binding is handled by this ViewBinder, this method must return true.
+ * If this method returns false, SimpleCursorTreeAdapter will attempts to handle
+ * the binding on its own.
+ *
+ * @param view the view to bind the data to
+ * @param cursor the cursor to get the data from
+ * @param columnIndex the column at which the data can be found in the cursor
+ *
+ * @return true if the data was bound to the view, false otherwise
+ */
+ boolean setViewValue(View view, Cursor cursor, int columnIndex);
+ }
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3fab692..e0a268e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -327,6 +327,7 @@
mText = "";
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint.density = getResources().getDisplayMetrics().density;
// If we get the paint from the skin, we should set it to left, since
// the layout always wants it to be left.
// mTextPaint.setTextAlign(Paint.Align.LEFT);
@@ -5769,7 +5770,7 @@
* Causes words in the text that are longer than the view is wide
* to be ellipsized instead of broken in the middle. You may also
* want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
- * to constrain the text toa single line. Use <code>null</code>
+ * to constrain the text to a single line. Use <code>null</code>
* to turn off ellipsizing.
*
* @attr ref android.R.styleable#TextView_ellipsize
@@ -6916,6 +6917,17 @@
}
}
+ boolean hasLetter = false;
+ for (int i = start; i < end; i++) {
+ if (Character.isLetter(mTransformed.charAt(i))) {
+ hasLetter = true;
+ break;
+ }
+ }
+ if (!hasLetter) {
+ return null;
+ }
+
if (start == end) {
return null;
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 20dd8a6..5bc2507 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -51,11 +51,26 @@
private Uri mUri;
private int mDuration;
+ // all possible internal states
+ private static final int STATE_ERROR = -1;
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_PREPARING = 1;
+ private static final int STATE_PREPARED = 2;
+ private static final int STATE_PLAYING = 3;
+ private static final int STATE_PAUSED = 4;
+ private static final int STATE_PLAYBACK_COMPLETED = 5;
+
+ // mCurrentState is a VideoView object's current state.
+ // mTargetState is the state that a method caller intends to reach.
+ // For instance, regardless the VideoView object's current state,
+ // calling pause() intends to bring the object to a target state
+ // of STATE_PAUSED.
+ private int mCurrentState = STATE_IDLE;
+ private int mTargetState = STATE_IDLE;
+
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder = null;
private MediaPlayer mMediaPlayer = null;
- private boolean mIsPrepared;
- private boolean mIsPlaybackCompleted;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
@@ -65,8 +80,7 @@
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
- private boolean mStartWhenPrepared;
- private int mSeekWhenPrepared;
+ private int mSeekWhenPrepared; // recording the seek position while preparing
public VideoView(Context context) {
super(context);
@@ -80,7 +94,6 @@
public VideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
initVideoView();
}
@@ -143,6 +156,8 @@
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
}
public void setVideoPath(String path) {
@@ -151,7 +166,6 @@
public void setVideoURI(Uri uri) {
mUri = uri;
- mStartWhenPrepared = false;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
@@ -163,6 +177,8 @@
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
}
}
@@ -176,18 +192,14 @@
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);
-
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
+
+ // we shouldn't clear the target state, because somebody might have
+ // called start() previously
+ release(false);
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
- mIsPrepared = false;
- Log.v(TAG, "reset duration to -1 in openVideo");
mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
@@ -198,12 +210,19 @@
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
+ // we don't set the target state here either, but preserve the
+ // target state that was there before.
+ mCurrentState = STATE_PREPARING;
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
return;
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
return;
}
}
@@ -222,7 +241,7 @@
View anchorView = this.getParent() instanceof View ?
(View)this.getParent() : this;
mMediaController.setAnchorView(anchorView);
- mMediaController.setEnabled(mIsPrepared);
+ mMediaController.setEnabled(isInPlaybackState());
}
}
@@ -239,8 +258,7 @@
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
- // briefly show the mediacontroller
- mIsPrepared = true;
+ mCurrentState = STATE_PREPARED;
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
@@ -249,6 +267,10 @@
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
+ int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
+ if (seekToPosition != 0) {
+ seekTo(seekToPosition);
+ }
if (mVideoWidth != 0 && mVideoHeight != 0) {
//Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
@@ -256,18 +278,13 @@
// We didn't actually change the size (it was already at the size
// we need), so we won't get a "surface changed" callback, so
// start the video here instead of in the callback.
- if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
- }
- if (mStartWhenPrepared) {
+ if (mTargetState == STATE_PLAYING) {
start();
- mStartWhenPrepared = false;
if (mMediaController != null) {
mMediaController.show();
}
} else if (!isPlaying() &&
- (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) {
+ (seekToPosition != 0 || getCurrentPosition() > 0)) {
if (mMediaController != null) {
// Show the media controls when we're paused into a video and make 'em stick.
mMediaController.show(0);
@@ -277,13 +294,8 @@
} else {
// We don't know the video size yet, but should start anyway.
// The video size might be reported to us later.
- if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
- }
- if (mStartWhenPrepared) {
+ if (mTargetState == STATE_PLAYING) {
start();
- mStartWhenPrepared = false;
}
}
}
@@ -292,7 +304,8 @@
private MediaPlayer.OnCompletionListener mCompletionListener =
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
- mIsPlaybackCompleted = true;
+ mCurrentState = STATE_PLAYBACK_COMPLETED;
+ mTargetState = STATE_PLAYBACK_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
}
@@ -306,6 +319,8 @@
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
if (mMediaController != null) {
mMediaController.hide();
}
@@ -402,14 +417,13 @@
{
mSurfaceWidth = w;
mSurfaceHeight = h;
- if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w && mVideoHeight == h) {
+ boolean isValidState = (mTargetState == STATE_PLAYING);
+ boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
+ if (mMediaPlayer != null && isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
+ seekTo(mSeekWhenPrepared);
}
- if (!mIsPlaybackCompleted) {
- start();
- }
+ start();
if (mMediaController != null) {
mMediaController.show();
}
@@ -427,17 +441,28 @@
// after we return from this we can't use the surface any more
mSurfaceHolder = null;
if (mMediaController != null) mMediaController.hide();
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
+ release(true);
}
};
+ /*
+ * release the media player in any state
+ */
+ private void release(boolean cleartargetstate) {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.reset();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ if (cleartargetstate) {
+ mTargetState = STATE_IDLE;
+ }
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
+ if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
@@ -445,7 +470,7 @@
@Override
public boolean onTrackballEvent(MotionEvent ev) {
- if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
+ if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
@@ -454,15 +479,13 @@
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
- if (mIsPrepared &&
- keyCode != KeyEvent.KEYCODE_BACK &&
- keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
- keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
- keyCode != KeyEvent.KEYCODE_MENU &&
- keyCode != KeyEvent.KEYCODE_CALL &&
- keyCode != KeyEvent.KEYCODE_ENDCALL &&
- mMediaPlayer != null &&
- mMediaController != null) {
+ boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
+ keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
+ keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
+ keyCode != KeyEvent.KEYCODE_MENU &&
+ keyCode != KeyEvent.KEYCODE_CALL &&
+ keyCode != KeyEvent.KEYCODE_ENDCALL;
+ if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
@@ -494,26 +517,26 @@
}
public void start() {
- mIsPlaybackCompleted = false;
- if (mMediaPlayer != null && mIsPrepared) {
- mMediaPlayer.start();
- mStartWhenPrepared = false;
- } else {
- mStartWhenPrepared = true;
+ if (isInPlaybackState()) {
+ mMediaPlayer.start();
+ mCurrentState = STATE_PLAYING;
}
+ mTargetState = STATE_PLAYING;
}
public void pause() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
+ mCurrentState = STATE_PAUSED;
}
}
- mStartWhenPrepared = false;
+ mTargetState = STATE_PAUSED;
}
+ // cache duration as mDuration for faster access
public int getDuration() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
if (mDuration > 0) {
return mDuration;
}
@@ -525,25 +548,23 @@
}
public int getCurrentPosition() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
}
return 0;
}
public void seekTo(int msec) {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
+ mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
public boolean isPlaying() {
- if (mMediaPlayer != null && mIsPrepared) {
- return mMediaPlayer.isPlaying();
- }
- return false;
+ return isInPlaybackState() && mMediaPlayer.isPlaying();
}
public int getBufferPercentage() {
@@ -552,4 +573,11 @@
}
return 0;
}
+
+ private boolean isInPlaybackState() {
+ return (mMediaPlayer != null &&
+ mCurrentState != STATE_ERROR &&
+ mCurrentState != STATE_IDLE &&
+ mCurrentState != STATE_PREPARING);
+ }
}
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index bae4dad..a41e2e3 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -69,7 +69,6 @@
* {@link #setVisible(boolean) setVisible(false)} from the
* {@link View#onDetachedFromWindow}.
*
- * @hide
*/
public class ZoomButtonsController implements View.OnTouchListener {
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/backup/SystemBackupAgent.java b/core/java/com/android/internal/backup/SystemBackupAgent.java
deleted file mode 100644
index 6b396d7..0000000
--- a/core/java/com/android/internal/backup/SystemBackupAgent.java
+++ /dev/null
@@ -1,35 +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 com.android.internal.backup;
-
-import android.backup.AbsoluteFileBackupHelper;
-import android.backup.BackupHelperAgent;
-
-/**
- * Backup agent for various system-managed data
- */
-public class SystemBackupAgent extends BackupHelperAgent {
- // the set of files that we back up whole, as absolute paths
- String[] mFiles = {
- /* WallpaperService.WALLPAPER_FILE */
- "/data/data/com.android.settings/files/wallpaper",
- };
-
- public void onCreate() {
- addHelper("system_files", new AbsoluteFileBackupHelper(this, mFiles));
- }
-}
diff --git a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
new file mode 100644
index 0000000..d2931a4b
--- /dev/null
+++ b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+import com.android.internal.util.ArrayUtils;
+
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.accounts.Account;
+import android.content.ContentValues;
+import android.provider.SyncStateContract;
+
+/**
+ * Extends the schema of a ContentProvider to include the _sync_state table
+ * and implements query/insert/update/delete to access that table using the
+ * authority "syncstate". This can be used to store the sync state for a
+ * set of accounts.
+ *
+ * @hide
+ */
+public class SyncStateContentProviderHelper {
+ private static final String SELECT_BY_ACCOUNT =
+ SyncStateContract.Columns.ACCOUNT_NAME + "=? AND "
+ + SyncStateContract.Columns.ACCOUNT_TYPE + "=?";
+
+ private static final String SYNC_STATE_TABLE = "_sync_state";
+ private static final String SYNC_STATE_META_TABLE = "_sync_state_metadata";
+ private static final String SYNC_STATE_META_VERSION_COLUMN = "version";
+
+ private static long DB_VERSION = 1;
+
+ private static final String[] ACCOUNT_PROJECTION =
+ new String[]{SyncStateContract.Columns.ACCOUNT_NAME,
+ SyncStateContract.Columns.ACCOUNT_TYPE};
+
+ public static final String PATH = "syncstate";
+
+ public void createDatabase(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE);
+ db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " ("
+ + SyncStateContract.Columns._ID + " INTEGER PRIMARY KEY,"
+ + SyncStateContract.Columns.ACCOUNT_NAME + " TEXT NOT NULL,"
+ + SyncStateContract.Columns.ACCOUNT_TYPE + " TEXT NOT NULL,"
+ + SyncStateContract.Columns.DATA + " TEXT,"
+ + "UNIQUE(" + SyncStateContract.Columns.ACCOUNT_NAME + ", "
+ + SyncStateContract.Columns.ACCOUNT_TYPE + "));");
+
+ db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_META_TABLE);
+ db.execSQL("CREATE TABLE " + SYNC_STATE_META_TABLE + " ("
+ + SYNC_STATE_META_VERSION_COLUMN + " INTEGER);");
+ ContentValues values = new ContentValues();
+ values.put(SYNC_STATE_META_VERSION_COLUMN, DB_VERSION);
+ db.insert(SYNC_STATE_META_TABLE, SYNC_STATE_META_VERSION_COLUMN, values);
+ }
+
+ public void onDatabaseOpened(SQLiteDatabase db) {
+ long version = DatabaseUtils.longForQuery(db,
+ "SELECT " + SYNC_STATE_META_VERSION_COLUMN + " FROM " + SYNC_STATE_META_TABLE,
+ null);
+ if (version != DB_VERSION) {
+ createDatabase(db);
+ }
+ }
+
+ public Cursor query(SQLiteDatabase db, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder) {
+ return db.query(SYNC_STATE_TABLE, projection, selection, selectionArgs,
+ null, null, sortOrder);
+ }
+
+ public long insert(SQLiteDatabase db, ContentValues values) {
+ return db.replace(SYNC_STATE_TABLE, SyncStateContract.Columns.ACCOUNT_NAME, values);
+ }
+
+ public int delete(SQLiteDatabase db, String userWhere, String[] whereArgs) {
+ return db.delete(SYNC_STATE_TABLE, userWhere, whereArgs);
+ }
+
+ public int update(SQLiteDatabase db, ContentValues values,
+ String selection, String[] selectionArgs) {
+ return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs);
+ }
+
+ public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) {
+ Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
+ try {
+ while (c.moveToNext()) {
+ final String accountName = c.getString(0);
+ final String accountType = c.getString(1);
+ Account account = new Account(accountName, accountType);
+ if (!ArrayUtils.contains(accounts, account)) {
+ db.delete(SYNC_STATE_TABLE, SELECT_BY_ACCOUNT,
+ new String[]{accountName, accountType});
+ }
+ }
+ } finally {
+ c.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 932555d..5825024 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -93,6 +93,18 @@
mH.sendMessage(msg);
}
+ public boolean hasMessages(int what) {
+ 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);
}
@@ -132,6 +144,14 @@
return mH.obtainMessage(what, arg1, arg2, arg3);
}
+ public Message obtainMessageIIOO(int what, int arg1, int arg2,
+ Object arg3, Object arg4) {
+ SomeArgs args = obtainArgs();
+ args.arg1 = arg3;
+ args.arg2 = arg4;
+ return mH.obtainMessage(what, arg1, arg2, args);
+ }
+
public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) {
SomeArgs args = obtainArgs();
args.arg1 = arg2;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 94149e1..a2d3cd8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -93,7 +93,26 @@
/** Controls whether we should preload resources during zygote init. */
private static final boolean PRELOAD_RESOURCES = true;
-
+
+ /**
+ * List of methods we "warm up" in the register map cache. These were
+ * chosen because they appeared on the stack in GCs in multiple
+ * applications.
+ *
+ * This is in a VM-ready format, to minimize string processing. If a
+ * class is not already loaded, or a method is not found, the entry
+ * will be skipped.
+ *
+ * This doesn't really merit a separately-generated input file at this
+ * time. The list is fairly short, and the consequences of failure
+ * are minor.
+ */
+ private static final String[] REGISTER_MAP_METHODS = {
+ // (currently not doing any)
+ //"Landroid/app/Activity;.setContentView:(I)V",
+ };
+
+
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
@@ -328,6 +347,45 @@
}
/**
+ * Pre-caches register maps for methods that are commonly used.
+ */
+ private static void cacheRegisterMaps() {
+ String failed = null;
+ int failure;
+ long startTime = System.nanoTime();
+
+ failure = 0;
+
+ for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) {
+ String str = REGISTER_MAP_METHODS[i];
+
+ if (!Debug.cacheRegisterMap(str)) {
+ if (failed == null)
+ failed = str;
+ failure++;
+ }
+ }
+
+ long delta = System.nanoTime() - startTime;
+
+ if (failure == REGISTER_MAP_METHODS.length) {
+ if (REGISTER_MAP_METHODS.length > 0) {
+ Log.i(TAG,
+ "Register map caching failed (precise GC not enabled?)");
+ }
+ return;
+ }
+
+ Log.i(TAG, "Register map cache: found " +
+ (REGISTER_MAP_METHODS.length - failure) + " of " +
+ REGISTER_MAP_METHODS.length + " methods in " +
+ (delta / 1000000L) + "ms");
+ if (failure > 0) {
+ Log.i(TAG, " First failure: " + failed);
+ }
+ }
+
+ /**
* Load in commonly used resources, so they can be shared across
* processes.
*
@@ -519,6 +577,7 @@
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preloadClasses();
+ //cacheRegisterMaps();
preloadResources();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
new file mode 100644
index 0000000..3f2979f
--- /dev/null
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -0,0 +1,152 @@
+/*
+ * 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 com.android.internal.service.wallpaper;
+
+import android.app.WallpaperManager;
+import android.graphics.Canvas;
+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;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+
+/**
+ * Default built-in wallpaper that simply shows a static image.
+ */
+public class ImageWallpaper extends WallpaperService {
+ WallpaperManager mWallpaperManager;
+ ImageWallpaper.DrawableEngine mEngine;
+ private WallpaperObserver mReceiver;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+ mReceiver = new WallpaperObserver();
+ registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
+
+ public Engine onCreateEngine() {
+ mEngine = new DrawableEngine();
+ return mEngine;
+ }
+
+ class WallpaperObserver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ mEngine.updateWallpaper();
+ mEngine.drawFrame();
+ }
+ }
+
+ class DrawableEngine extends Engine {
+ private final Object mLock = new Object();
+ private final Rect mBounds = new Rect();
+ Drawable mBackground;
+ float mXOffset;
+ float mYOffset;
+
+ @Override
+ public void onCreate(SurfaceHolder surfaceHolder) {
+ super.onCreate(surfaceHolder);
+ updateWallpaper();
+ surfaceHolder.setSizeFromLayout();
+ //setTouchEventsEnabled(true);
+ }
+
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ drawFrame();
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ Log.i("foo", "Touch event: " + event);
+ }
+
+ @Override
+ public void onOffsetsChanged(float xOffset, float yOffset,
+ int xPixels, int yPixels) {
+ mXOffset = xOffset;
+ mYOffset = xOffset;
+ drawFrame();
+ }
+
+ @Override
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ super.onSurfaceChanged(holder, format, width, height);
+ drawFrame();
+ }
+
+ @Override
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ super.onSurfaceCreated(holder);
+ }
+
+ @Override
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
+ super.onSurfaceDestroyed(holder);
+ }
+
+ void drawFrame() {
+ SurfaceHolder sh = getSurfaceHolder();
+ Canvas c = sh.lockCanvas();
+ if (c != null) {
+ final Rect frame = sh.getSurfaceFrame();
+ synchronized (mLock) {
+ final Drawable background = mBackground;
+ 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) : -(int)(availw/2);
+ int yPixels = availh > 0
+ ? -(int)(availh*mYOffset+.5f) : -(int)(availh/2);
+ c.translate(xPixels, yPixels);
+ c.drawColor(0xff000000);
+ background.draw(c);
+ }
+ sh.unlockCanvasAndPost(c);
+ }
+ }
+
+ void updateWallpaper() {
+ synchronized (mLock) {
+ mBackground = mWallpaperManager.getDrawable();
+ mBounds.left = mBounds.top = 0;
+ mBounds.right = mBackground.getIntrinsicWidth();
+ mBounds.bottom = mBackground.getIntrinsicHeight();
+ mBackground.setBounds(mBounds);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
new file mode 100644
index 0000000..f4f6297
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -0,0 +1,95 @@
+package com.android.internal.view;
+
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BaseIWindow extends IWindow.Stub {
+ private IWindowSession mSession;
+
+ public void setSession(IWindowSession session) {
+ mSession = session;
+ }
+
+ public void resized(int w, int h, Rect coveredInsets,
+ Rect visibleInsets, boolean reportDraw) {
+ if (reportDraw) {
+ try {
+ mSession.finishDrawing(this);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public void dispatchKey(KeyEvent event) {
+ try {
+ mSession.finishKey(this);
+ } catch (RemoteException ex) {
+ }
+ }
+
+ 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);
+ onDispatchPointer(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchPointer(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchPointer(event, eventTime, false);
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+
+ 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);
+ onDispatchTrackball(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchTrackball(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchTrackball(event, eventTime, false);
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+
+ public void dispatchAppVisibility(boolean visible) {
+ }
+
+ public void dispatchGetNewSurface() {
+ }
+
+ public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
+ }
+
+ public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
+ }
+
+ public void dispatchWallpaperOffsets(float x, float y) {
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
new file mode 100644
index 0000000..2823689
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -0,0 +1,174 @@
+package com.android.internal.view;
+
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+
+public abstract class BaseSurfaceHolder implements SurfaceHolder {
+ private static final String TAG = "BaseSurfaceHolder";
+ static final boolean DEBUG = false;
+
+ public final ArrayList<SurfaceHolder.Callback> mCallbacks
+ = new ArrayList<SurfaceHolder.Callback>();
+
+ public final ReentrantLock mSurfaceLock = new ReentrantLock();
+ public final Surface mSurface = new Surface();
+
+ int mRequestedWidth = -1;
+ int mRequestedHeight = -1;
+ int mRequestedFormat = PixelFormat.OPAQUE;
+ int mRequestedType = -1;
+
+ long mLastLockTime = 0;
+
+ int mType = -1;
+ final Rect mSurfaceFrame = new Rect();
+
+ public abstract void onUpdateSurface();
+ public abstract void onRelayoutContainer();
+ public abstract boolean onAllowLockCanvas();
+
+ public int getRequestedWidth() {
+ return mRequestedWidth;
+ }
+
+ public int getRequestedHeight() {
+ return mRequestedHeight;
+ }
+
+ public int getRequestedFormat() {
+ return mRequestedFormat;
+ }
+
+ public int getRequestedType() {
+ return mRequestedType;
+ }
+
+ public void addCallback(Callback callback) {
+ synchronized (mCallbacks) {
+ // This is a linear search, but in practice we'll
+ // have only a couple callbacks, so it doesn't matter.
+ if (mCallbacks.contains(callback) == false) {
+ mCallbacks.add(callback);
+ }
+ }
+ }
+
+ public void removeCallback(Callback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.remove(callback);
+ }
+ }
+
+ public void setFixedSize(int width, int height) {
+ if (mRequestedWidth != width || mRequestedHeight != height) {
+ mRequestedWidth = width;
+ mRequestedHeight = height;
+ onRelayoutContainer();
+ }
+ }
+
+ public void setSizeFromLayout() {
+ if (mRequestedWidth != -1 || mRequestedHeight != -1) {
+ mRequestedWidth = mRequestedHeight = -1;
+ onRelayoutContainer();
+ }
+ }
+
+ public void setFormat(int format) {
+ if (mRequestedFormat != format) {
+ mRequestedFormat = format;
+ onUpdateSurface();
+ }
+ }
+
+ public void setType(int type) {
+ switch (type) {
+ case SURFACE_TYPE_HARDWARE:
+ case SURFACE_TYPE_GPU:
+ // these are deprecated, treat as "NORMAL"
+ type = SURFACE_TYPE_NORMAL;
+ break;
+ }
+ switch (type) {
+ case SURFACE_TYPE_NORMAL:
+ case SURFACE_TYPE_PUSH_BUFFERS:
+ if (mRequestedType != type) {
+ mRequestedType = type;
+ onUpdateSurface();
+ }
+ break;
+ }
+ }
+
+ public Canvas lockCanvas() {
+ return internalLockCanvas(null);
+ }
+
+ public Canvas lockCanvas(Rect dirty) {
+ return internalLockCanvas(dirty);
+ }
+
+ private final Canvas internalLockCanvas(Rect dirty) {
+ if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
+ throw new BadSurfaceTypeException(
+ "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
+ }
+ mSurfaceLock.lock();
+
+ if (DEBUG) Log.i(TAG, "Locking canvas..,");
+
+ Canvas c = null;
+ if (onAllowLockCanvas()) {
+ Rect frame = dirty != null ? dirty : mSurfaceFrame;
+ try {
+ c = mSurface.lockCanvas(frame);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception locking surface", e);
+ }
+ }
+
+ if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+ if (c != null) {
+ mLastLockTime = SystemClock.uptimeMillis();
+ return c;
+ }
+
+ // If the Surface is not ready to be drawn, then return null,
+ // but throttle calls to this function so it isn't called more
+ // than every 100ms.
+ long now = SystemClock.uptimeMillis();
+ long nextTime = mLastLockTime + 100;
+ if (nextTime > now) {
+ try {
+ Thread.sleep(nextTime-now);
+ } catch (InterruptedException e) {
+ }
+ now = SystemClock.uptimeMillis();
+ }
+ mLastLockTime = now;
+ mSurfaceLock.unlock();
+
+ return null;
+ }
+
+ public void unlockCanvasAndPost(Canvas canvas) {
+ mSurface.unlockCanvasAndPost(canvas);
+ mSurfaceLock.unlock();
+ }
+
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ public Rect getSurfaceFrame() {
+ return mSurfaceFrame;
+ }
+};
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
new file mode 100644
index 0000000..30349b3
--- /dev/null
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -0,0 +1,480 @@
+/*
+ * 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 com.android.internal.widget;
+
+import android.Manifest;
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+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.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.SocialContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.Presence;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.SocialContract.Activities;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * Header used across system for displaying a title bar with contact info. You
+ * can bind specific values on the header, or use helper methods like
+ * {@link #bindFromContactId(long)} to populate asynchronously.
+ * <p>
+ * The parent must request the {@link Manifest.permission#READ_CONTACTS}
+ * permission to access contact data.
+ */
+public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener,
+ View.OnLongClickListener {
+
+ private static final String TAG = "ContactHeaderWidget";
+
+ private TextView mDisplayNameView;
+ private TextView mPhoneticNameView;
+ private CheckBox mStarredView;
+ private ImageView mPhotoView;
+ private ImageView mPresenceView;
+ private TextView mStatusView;
+ private int mNoPhotoResource;
+ private QueryHandler mQueryHandler;
+
+ protected long mContactId;
+ protected Uri mContactSummaryUri;
+ protected Uri mContactUri;
+ protected Uri mStatusUri;
+
+ protected ContentResolver mContentResolver;
+
+ /**
+ * Interface for callbacks invoked when the user interacts with a header.
+ */
+ public interface ContactHeaderListener {
+ public void onPhotoLongClick(View view);
+ public void onDisplayNameLongClick(View view);
+ }
+
+ private ContactHeaderListener mListener;
+
+ //Projection used for the summary info in the header.
+ protected static final String[] HEADER_PROJECTION = new String[] {
+ Contacts.DISPLAY_NAME,
+ Contacts.STARRED,
+ Contacts.PHOTO_ID,
+ Contacts.PRESENCE_STATUS,
+ };
+ protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0;
+ //TODO: We need to figure out how we're going to get the phonetic name.
+ //static final int HEADER_PHONETIC_NAME_COLUMN_INDEX
+ protected static final int HEADER_STARRED_COLUMN_INDEX = 1;
+ protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2;
+ protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3;
+
+ //Projection used for finding the most recent social status.
+ protected static final String[] SOCIAL_PROJECTION = new String[] {
+ Activities.TITLE,
+ Activities.PUBLISHED,
+ };
+ protected static final int SOCIAL_TITLE_COLUMN_INDEX = 0;
+ protected static final int SOCIAL_PUBLISHED_COLUMN_INDEX = 1;
+
+ //Projection used for looking up contact id from phone number
+ protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
+ RawContacts.CONTACT_ID,
+ };
+ protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+
+ //Projection used for looking up contact id from email address
+ protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
+ RawContacts.CONTACT_ID,
+ };
+ protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+
+
+ private static final int TOKEN_CONTACT_INFO = 0;
+ private static final int TOKEN_SOCIAL = 1;
+
+ public ContactHeaderWidget(Context context) {
+ this(context, null);
+ }
+
+ public ContactHeaderWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ContactHeaderWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mContentResolver = mContext.getContentResolver();
+
+ LayoutInflater inflater =
+ (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.contact_header, this);
+
+ mDisplayNameView = (TextView) findViewById(R.id.name);
+ mDisplayNameView.setOnLongClickListener(this);
+
+ mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
+
+ mStarredView = (CheckBox)findViewById(R.id.star);
+ mStarredView.setOnClickListener(this);
+
+ mPhotoView = (ImageView)findViewById(R.id.photo);
+ mPhotoView.setOnClickListener(this);
+ mPhotoView.setOnLongClickListener(this);
+
+ mPresenceView = (ImageView) findViewById(R.id.presence);
+
+ mStatusView = (TextView)findViewById(R.id.status);
+
+ // Set the photo with a random "no contact" image
+ long now = SystemClock.elapsedRealtime();
+ int num = (int) now & 0xf;
+ if (num < 9) {
+ // Leaning in from right, common
+ mNoPhotoResource = R.drawable.ic_contact_picture;
+ } else if (num < 14) {
+ // Leaning in from left uncommon
+ mNoPhotoResource = R.drawable.ic_contact_picture_2;
+ } else {
+ // Coming in from the top, rare
+ mNoPhotoResource = R.drawable.ic_contact_picture_3;
+ }
+
+ mQueryHandler = new QueryHandler(mContentResolver);
+ }
+
+ /**
+ * Set the given {@link ContactHeaderListener} to handle header events.
+ */
+ public void setContactHeaderListener(ContactHeaderListener listener) {
+ mListener = listener;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onLongClick(View v) {
+ switch (v.getId()) {
+ case R.id.photo:
+ performPhotoLongClick();
+ return true;
+ case R.id.name:
+ performDisplayNameLongClick();
+ return true;
+ }
+ return false;
+ }
+
+ private void performPhotoLongClick() {
+ if (mListener != null) {
+ mListener.onPhotoLongClick(mPhotoView);
+ }
+ }
+
+ private void performDisplayNameLongClick() {
+ if (mListener != null) {
+ mListener.onDisplayNameLongClick(mDisplayNameView);
+ }
+ }
+
+ private class QueryHandler extends AsyncQueryHandler {
+
+ public QueryHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ try{
+ if (token == TOKEN_CONTACT_INFO) {
+ bindContactInfo(cursor);
+ invalidate();
+ } else if (token == TOKEN_SOCIAL) {
+ bindSocial(cursor);
+ invalidate();
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ /**
+ * Turn on/off showing of the star element.
+ */
+ public void showStar(boolean showStar) {
+ mStarredView.setVisibility(showStar ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Manually set the starred state of this header widget. This doesn't change
+ * the underlying {@link Contacts} value, only the UI state.
+ */
+ public void setStared(boolean starred) {
+ mStarredView.setChecked(starred);
+ }
+
+ /**
+ * Manually set the presence.
+ */
+ public void setPresence(int presence) {
+ mPresenceView.setImageResource(Presence.getPresenceIconResourceId(presence));
+ }
+
+ /**
+ * Manually set the contact uri
+ */
+ public void setContactUri(Uri uri) {
+ mContactUri = uri;
+ }
+
+ /**
+ * Manually set the photo to display in the header. This doesn't change the
+ * underlying {@link Contacts}, only the UI state.
+ */
+ public void setPhoto(Bitmap bitmap) {
+ mPhotoView.setImageBitmap(bitmap);
+ }
+
+ /**
+ * Manually set the display name and phonetic name to show in the header.
+ * This doesn't change the underlying {@link Contacts}, only the UI state.
+ */
+ public void setDisplayName(CharSequence displayName, CharSequence phoneticName) {
+ mDisplayNameView.setText(displayName);
+ if (mPhoneticNameView != null) {
+ mPhoneticNameView.setText(phoneticName);
+ }
+ }
+
+ /**
+ * Manually set the social snippet text to display in the header.
+ */
+ public void setSocialSnippet(CharSequence snippet) {
+ mStatusView.setText(snippet);
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param contactId the contact id of the contact whose info should be displayed.
+ */
+ public void bindFromContactId(long contactId) {
+ mContactId = contactId;
+ mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId);
+
+ bindSummaryUri(ContentUris.withAppendedId(Contacts.CONTENT_SUMMARY_URI, mContactId));
+ bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId));
+ }
+
+ /**
+ * Convenience method for binding {@link Contacts} header details from a
+ * {@link Contacts#CONTENT_SUMMARY_URI} reference.
+ */
+ public void bindSummaryUri(Uri contactSummary) {
+ mContactSummaryUri = contactSummary;
+ mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, mContactSummaryUri, HEADER_PROJECTION,
+ null, null, null);
+ }
+
+ /**
+ * Convenience method for binding {@link Activities} header details from a
+ * {@link Activities#CONTENT_CONTACT_STATUS_URI}.
+ */
+ public void bindSocialUri(Uri contactSocial) {
+ mStatusUri = contactSocial;
+ mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null,
+ null);
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param emailAddress The email address used to do a reverse lookup in
+ * the contacts database. If more than one contact contains this email
+ * address, one of them will be chosen to bind to.
+ */
+ 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);
+ if (c != null && c.moveToFirst()) {
+ long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ bindFromContactId(contactId);
+ } else {
+ setDisplayName(emailAddress, null);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param number The phone number used to do a reverse lookup in
+ * the contacts database. If more than one contact contains this phone
+ * number, one of them will be chosen to bind to.
+ */
+ public void bindFromPhoneNumber(String number) {
+ Cursor c = null;
+ try {
+ c = mContentResolver.query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+ PHONE_LOOKUP_PROJECTION, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ bindFromContactId(contactId);
+ } else {
+ setDisplayName(number, null);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Bind the contact details provided by the given {@link Cursor}.
+ */
+ protected void bindContactInfo(Cursor c) {
+ if (c == null || !c.moveToFirst()) return;
+
+ // TODO: Bring back phonetic name
+ final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX);
+ final String phoneticName = null;
+ this.setDisplayName(displayName, null);
+
+ final boolean starred = c.getInt(HEADER_STARRED_COLUMN_INDEX) != 0;
+ mStarredView.setChecked(starred);
+
+ //Set the photo
+ Bitmap photoBitmap = loadContactPhoto(c.getLong(HEADER_PHOTO_ID_COLUMN_INDEX), null);
+ if (photoBitmap == null) {
+ photoBitmap = loadPlaceholderPhoto(null);
+ }
+ mPhotoView.setImageBitmap(photoBitmap);
+
+ //Set the presence status
+ int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX);
+ mPresenceView.setImageResource(Presence.getPresenceIconResourceId(presence));
+ }
+
+ /**
+ * Bind the social data provided by the given {@link Cursor}.
+ */
+ protected void bindSocial(Cursor c) {
+ if (c == null || !c.moveToFirst()) return;
+ final String status = c.getString(SOCIAL_TITLE_COLUMN_INDEX);
+ this.setSocialSnippet(status);
+ }
+
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.star: {
+ // Toggle "starred" state
+ final ContentValues values = new ContentValues(1);
+ values.put(Contacts.STARRED, mStarredView.isChecked());
+ mContentResolver.update(mContactUri, values, null, null);
+ break;
+ }
+ case R.id.photo: {
+ // Photo launches contact detail action
+ final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
+ final Rect target = getTargetRect(view);
+ intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
+ intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
+ mContext.startActivity(intent);
+ break;
+ }
+ }
+ }
+
+ private Rect getTargetRect(View anchor) {
+ final int[] location = new int[2];
+ anchor.getLocationOnScreen(location);
+
+ final Rect rect = new Rect();
+ rect.left = location[0];
+ rect.top = location[1];
+ rect.right = rect.left + anchor.getWidth();
+ rect.bottom = rect.top + anchor.getHeight();
+ return rect;
+ }
+
+ private Bitmap loadContactPhoto(long photoId, BitmapFactory.Options options) {
+ Cursor photoCursor = null;
+ Bitmap photoBm = null;
+
+ try {
+ photoCursor = mContentResolver.query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
+ new String[] { Photo.PHOTO },
+ null, null, null);
+
+ if (photoCursor != null && photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
+ byte[] photoData = photoCursor.getBlob(0);
+ photoBm = BitmapFactory.decodeByteArray(photoData, 0,
+ photoData.length, options);
+ }
+ } finally {
+ if (photoCursor != null) {
+ photoCursor.close();
+ }
+ }
+
+ return photoBm;
+ }
+
+ private Bitmap loadPlaceholderPhoto(BitmapFactory.Options options) {
+ if (mNoPhotoResource == 0) {
+ return null;
+ }
+ return BitmapFactory.decodeResource(mContext.getResources(),
+ mNoPhotoResource, options);
+ }
+}
diff --git a/core/java/com/google/android/gdata/client/QueryParamsImpl.java b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
index e27b36f..fbe0d22 100644
--- a/core/java/com/google/android/gdata/client/QueryParamsImpl.java
+++ b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
@@ -60,6 +60,8 @@
sb.append('?');
}
for (String param : params) {
+ String value = mParams.get(param);
+ if (value == null) continue;
if (first) {
first = false;
} else {
@@ -67,7 +69,7 @@
}
sb.append(param);
sb.append('=');
- String value = mParams.get(param);
+
String encodedValue = null;
try {
diff --git a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
new file mode 100644
index 0000000..6ba791d
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
@@ -0,0 +1,590 @@
+// Copyright 2007 The Android Open Source Project
+
+package com.google.android.gdata2.client;
+
+import com.google.android.net.GoogleHttpClient;
+import com.google.wireless.gdata2.client.GDataClient;
+import com.google.wireless.gdata2.client.HttpException;
+import com.google.wireless.gdata2.client.QueryParams;
+import com.google.wireless.gdata2.data.StringUtils;
+import com.google.wireless.gdata2.parser.ParseException;
+import com.google.wireless.gdata2.serializer.GDataSerializer;
+import com.google.android.gdata2.client.QueryParamsImpl;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.AbstractHttpEntity;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.http.AndroidHttpClient;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.BufferedInputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+
+/**
+ * Implementation of a GDataClient using GoogleHttpClient to make HTTP
+ * requests. Always issues GETs and POSTs, using the X-HTTP-Method-Override
+ * header when a PUT or DELETE is desired, to avoid issues with firewalls, etc.,
+ * that do not allow methods other than GET or POST.
+ */
+public class AndroidGDataClient implements GDataClient {
+
+ private static final String TAG = "GDataClient";
+ private static final boolean DEBUG = false;
+ private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private static final String X_HTTP_METHOD_OVERRIDE =
+ "X-HTTP-Method-Override";
+
+ private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.2";
+
+ private static final int MAX_REDIRECTS = 10;
+ private static String DEFAULT_GDATA_VERSION = "2.0";
+
+
+ private String mGDataVersion;
+ private final GoogleHttpClient mHttpClient;
+ private ContentResolver mResolver;
+
+ /**
+ * Interface for creating HTTP requests. Used by
+ * {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for
+ * changing the URI after creation, e.g., when you want to follow a redirect.
+ */
+ private interface HttpRequestCreator {
+ HttpUriRequest createRequest(URI uri);
+ }
+
+ private static class GetRequestCreator implements HttpRequestCreator {
+ public GetRequestCreator() {
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpGet get = new HttpGet(uri);
+ return get;
+ }
+ }
+
+ private static class PostRequestCreator implements HttpRequestCreator {
+ private final String mMethodOverride;
+ private final HttpEntity mEntity;
+ public PostRequestCreator(String methodOverride, HttpEntity entity) {
+ mMethodOverride = methodOverride;
+ mEntity = entity;
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpPost post = new HttpPost(uri);
+ if (mMethodOverride != null) {
+ post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride);
+ }
+ post.setEntity(mEntity);
+ return post;
+ }
+ }
+
+ // MAJOR TODO: make this work across redirects (if we can reset the InputStream).
+ // OR, read the bits into a local buffer (yuck, the media could be large).
+ private static class MediaPutRequestCreator implements HttpRequestCreator {
+ private final InputStream mMediaInputStream;
+ private final String mContentType;
+ public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) {
+ mMediaInputStream = mediaInputStream;
+ mContentType = contentType;
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpPost post = new HttpPost(uri);
+ post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
+ // mMediaInputStream.reset();
+ InputStreamEntity entity = new InputStreamEntity(mMediaInputStream,
+ -1 /* read until EOF */);
+ entity.setContentType(mContentType);
+ post.setEntity(entity);
+ return post;
+ }
+ }
+
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ */
+ public AndroidGDataClient(Context context) {
+ this(context, DEFAULT_USER_AGENT_APP_VERSION);
+ }
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ * @param appAndVersion The application name and version to be used as the basis of the
+ * User-Agent. e.g., Android-GData/1.5.0.
+ */
+ public AndroidGDataClient(Context context, String appAndVersion) {
+ this(context, appAndVersion, DEFAULT_GDATA_VERSION);
+ }
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ * @param appAndVersion The application name and version to be used as the basis of the
+ * User-Agent. e.g., Android-GData/1.5.0.
+ * @param gdataVersion The gdata service version that should be
+ * used, e.g. "2.0"
+ *
+ */
+ public AndroidGDataClient(Context context, String appAndVersion, String gdataVersion) {
+ mHttpClient = new GoogleHttpClient(context, appAndVersion,
+ true /* gzip capable */);
+ mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
+ mResolver = context.getContentResolver();
+ mGDataVersion = gdataVersion;
+ }
+
+
+ public void close() {
+ mHttpClient.close();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see GDataClient#encodeUri(java.lang.String)
+ */
+ public String encodeUri(String uri) {
+ String encodedUri;
+ try {
+ encodedUri = URLEncoder.encode(uri, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen.
+ Log.e("JakartaGDataClient",
+ "UTF-8 not supported -- should not happen. "
+ + "Using default encoding.", uee);
+ encodedUri = URLEncoder.encode(uri);
+ }
+ return encodedUri;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
+ */
+ public QueryParams createQueryParams() {
+ return new QueryParamsImpl();
+ }
+
+ // follows redirects
+ private InputStream createAndExecuteMethod(HttpRequestCreator creator,
+ String uriString,
+ String authToken,
+ String eTag,
+ String protocolVersion)
+ throws HttpException, IOException {
+
+ HttpResponse response = null;
+ int status = 500;
+ int redirectsLeft = MAX_REDIRECTS;
+
+ URI uri;
+ try {
+ uri = new URI(uriString);
+ } catch (URISyntaxException use) {
+ Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
+ throw new IOException("Unable to parse " + uriString + " as URI: "
+ + use.getMessage());
+ }
+
+ // we follow redirects ourselves, since we want to follow redirects even on POSTs, which
+ // the HTTP library does not do. following redirects ourselves also allows us to log
+ // the redirects using our own logging.
+ while (redirectsLeft > 0) {
+
+ HttpUriRequest request = creator.createRequest(uri);
+
+ AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+ // only add the auth token if not null (to allow for GData feeds that do not require
+ // authentication.)
+ if (!TextUtils.isEmpty(authToken)) {
+ request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
+ }
+
+ // while by default we have a 2.0 in this variable, it is possible to construct
+ // a client that has an empty version field, to work with 1.0 services.
+ if (!TextUtils.isEmpty(mGDataVersion)) {
+ request.addHeader("GDataVersion", mGDataVersion);
+ }
+
+ // if we have a passed down eTag value, we need to add several headers
+ if (!TextUtils.isEmpty(eTag)) {
+ String method = request.getMethod();
+ Header overrideMethodHeader = request.getFirstHeader(X_HTTP_METHOD_OVERRIDE);
+ if (overrideMethodHeader != null) {
+ method = overrideMethodHeader.getValue();
+ }
+ if ("GET".equals(method)) {
+ // add the none match header, if the resource is not changed
+ // this request will result in a 304 now.
+ request.addHeader("If-None-Match", eTag);
+ } else if ("DELETE".equals(method)
+ || "PUT".equals(method)) {
+ // now we send an if-match, but only if the passed in eTag is a strong eTag
+ // as this only makes sense for a strong eTag
+ if (!eTag.startsWith("W/")) {
+ request.addHeader("If-Match", eTag);
+ }
+ }
+ }
+
+ if (LOCAL_LOGV) {
+ for (Header h : request.getAllHeaders()) {
+ Log.v(TAG, h.getName() + ": " + h.getValue());
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Executing " + request.getRequestLine().toString());
+ }
+
+ response = null;
+
+ try {
+ response = mHttpClient.execute(request);
+ } catch (IOException ioe) {
+ Log.w(TAG, "Unable to execute HTTP request." + ioe);
+ throw ioe;
+ }
+
+ StatusLine statusLine = response.getStatusLine();
+ if (statusLine == null) {
+ Log.w(TAG, "StatusLine is null.");
+ throw new NullPointerException("StatusLine is null -- should not happen.");
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, response.getStatusLine().toString());
+ for (Header h : response.getAllHeaders()) {
+ Log.d(TAG, h.getName() + ": " + h.getValue());
+ }
+ }
+ status = statusLine.getStatusCode();
+
+ HttpEntity entity = response.getEntity();
+
+ if ((status >= 200) && (status < 300) && entity != null) {
+ InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ in = logInputStreamContents(in);
+ }
+ return in;
+ }
+
+ // TODO: handle 301, 307?
+ // TODO: let the http client handle the redirects, if we can be sure we'll never get a
+ // redirect on POST.
+ if (status == 302) {
+ // consume the content, so the connection can be closed.
+ entity.consumeContent();
+ Header location = response.getFirstHeader("Location");
+ if (location == null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Redirect requested but no Location "
+ + "specified.");
+ }
+ break;
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Following redirect to " + location.getValue());
+ }
+ try {
+ uri = new URI(location.getValue());
+ } catch (URISyntaxException use) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
+ throw new IOException("Unable to parse " + location.getValue()
+ + " as URI.");
+ }
+ break;
+ }
+ --redirectsLeft;
+ } else {
+ break;
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Received " + status + " status code.");
+ }
+ String errorMessage = null;
+ HttpEntity entity = response.getEntity();
+ try {
+ if (response != null && entity != null) {
+ InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ int bytesRead = -1;
+ while ((bytesRead = in.read(buf)) != -1) {
+ baos.write(buf, 0, bytesRead);
+ }
+ // TODO: use appropriate encoding, picked up from Content-Type.
+ errorMessage = new String(baos.toByteArray());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, errorMessage);
+ }
+ }
+ } finally {
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ }
+ String exceptionMessage = "Received " + status + " status code";
+ if (errorMessage != null) {
+ exceptionMessage += (": " + errorMessage);
+ }
+ throw new HttpException(exceptionMessage, status, null /* InputStream */);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
+ */
+ public InputStream getFeedAsStream(String feedUrl,
+ String authToken,
+ String eTag,
+ String protocolVersion)
+ throws HttpException, IOException {
+
+ InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken, eTag, protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to access feed.");
+ }
+
+ /**
+ * Log the contents of the input stream.
+ * The original input stream is consumed, so the caller must use the
+ * BufferedInputStream that is returned.
+ * @param in InputStream
+ * @return replacement input stream for caller to use
+ * @throws IOException
+ */
+ private InputStream logInputStreamContents(InputStream in) throws IOException {
+ if (in == null) {
+ return in;
+ }
+ // bufferSize is the (arbitrary) maximum amount to log.
+ // The original InputStream is wrapped in a
+ // BufferedInputStream with a 16K buffer. This lets
+ // us read up to 16K, write it to the log, and then
+ // reset the stream so the the original client can
+ // then read the data. The BufferedInputStream
+ // provides the mark and reset support, even when
+ // the original InputStream does not.
+ final int bufferSize = 16384;
+ BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
+ bin.mark(bufferSize);
+ int wanted = bufferSize;
+ int totalReceived = 0;
+ byte buf[] = new byte[wanted];
+ while (wanted > 0) {
+ int got = bin.read(buf, totalReceived, wanted);
+ if (got <= 0) break; // EOF
+ wanted -= got;
+ totalReceived += got;
+ }
+ Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
+ bin.reset();
+ return bin;
+ }
+
+ public InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken, String eTag, String protocolVersion)
+ throws HttpException, IOException {
+
+ InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken, eTag, protocolVersion);
+
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to access media entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#createEntry
+ */
+ public InputStream createEntry(String feedUrl,
+ String authToken,
+ String protocolVersion,
+ GDataSerializer entry)
+ throws HttpException, IOException {
+
+ HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator(null /* override */, entity),
+ feedUrl,
+ authToken,
+ null,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to create entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#updateEntry
+ */
+ public InputStream updateEntry(String editUri,
+ String authToken,
+ String eTag,
+ String protocolVersion,
+ GDataSerializer entry)
+ throws HttpException, IOException {
+ HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
+ final String method = entry.getSupportsPartial() ? "PATCH" : "PUT";
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator(method, entity),
+ editUri,
+ authToken,
+ eTag,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to update entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#deleteEntry
+ */
+ public void deleteEntry(String editUri, String authToken, String eTag)
+ throws HttpException, IOException {
+ if (StringUtils.isEmpty(editUri)) {
+ throw new IllegalArgumentException(
+ "you must specify an non-empty edit url");
+ }
+ InputStream in =
+ createAndExecuteMethod(
+ new PostRequestCreator("DELETE", null /* entity */),
+ editUri,
+ authToken,
+ eTag,
+ null /* protocolVersion, not required for a delete */);
+ if (in == null) {
+ throw new IOException("Unable to delete entry.");
+ }
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ public InputStream updateMediaEntry(String editUri, String authToken, String eTag,
+ String protocolVersion, InputStream mediaEntryInputStream, String contentType)
+ throws HttpException, IOException {
+ InputStream in = createAndExecuteMethod(
+ new MediaPutRequestCreator(mediaEntryInputStream, contentType),
+ editUri,
+ authToken,
+ eTag,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to write media entry.");
+ }
+
+ private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ entry.serialize(baos, format);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to serialize entry.", ioe);
+ throw ioe;
+ } catch (ParseException pe) {
+ Log.e(TAG, "Unable to serialize entry.", pe);
+ throw new IOException("Unable to serialize entry: " + pe.getMessage());
+ }
+
+ byte[] entryBytes = baos.toByteArray();
+
+ if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
+ try {
+ Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen
+ throw new IllegalStateException("UTF-8 should be supported!",
+ uee);
+ }
+ }
+
+ AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+ entity.setContentType(entry.getContentType());
+ return entity;
+ }
+
+ /**
+ * Connects to a GData server (specified by the batchUrl) and submits a
+ * batch for processing. The response from the server is returned as an
+ * {@link InputStream}. The caller is responsible for calling
+ * {@link InputStream#close()} on the returned {@link InputStream}.
+ *
+ * @param batchUrl The batch url to which the batch is submitted.
+ * @param authToken the authentication token that should be used when
+ * submitting the batch.
+ * @param protocolVersion The version of the protocol that
+ * should be used for this request.
+ * @param batch The batch of entries to submit.
+ * @throws IOException Thrown if an io error occurs while communicating with
+ * the service.
+ * @throws HttpException if the service returns an error response.
+ */
+ public InputStream submitBatch(String batchUrl,
+ String authToken,
+ String protocolVersion,
+ GDataSerializer batch)
+ throws HttpException, IOException
+ {
+ HttpEntity entity = createEntityForEntry(batch, GDataSerializer.FORMAT_BATCH);
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator("POST", entity),
+ batchUrl,
+ authToken,
+ null,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to process batch request.");
+ }
+}
+
diff --git a/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
new file mode 100644
index 0000000..f097706
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
@@ -0,0 +1,31 @@
+package com.google.android.gdata2.client;
+
+import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Xml;
+
+/**
+ * XmlParserFactory for the Android platform.
+ */
+public class AndroidXmlParserFactory implements XmlParserFactory {
+
+ /*
+ * (non-javadoc)
+ * @see XmlParserFactory#createParser
+ */
+ public XmlPullParser createParser() throws XmlPullParserException {
+ return Xml.newPullParser();
+ }
+
+ /*
+ * (non-javadoc)
+ * @see XmlParserFactory#createSerializer
+ */
+ public XmlSerializer createSerializer() throws XmlPullParserException {
+ return Xml.newSerializer();
+ }
+}
diff --git a/core/java/com/google/android/gdata2/client/QueryParamsImpl.java b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
new file mode 100644
index 0000000..a26f4ce
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
@@ -0,0 +1,99 @@
+package com.google.android.gdata2.client;
+import com.google.wireless.gdata2.client.QueryParams;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Simple implementation of the QueryParams interface.
+ */
+// TODO: deal with categories
+public class QueryParamsImpl extends QueryParams {
+
+ private final Map<String,String> mParams = new HashMap<String,String>();
+
+ /**
+ * Creates a new empty QueryParamsImpl.
+ */
+ public QueryParamsImpl() {
+ }
+
+ @Override
+ public void clear() {
+ setEntryId(null);
+ mParams.clear();
+ }
+
+ @Override
+ public String generateQueryUrl(String feedUrl) {
+
+ if (TextUtils.isEmpty(getEntryId()) &&
+ mParams.isEmpty()) {
+ // nothing to do
+ return feedUrl;
+ }
+
+ // handle entry IDs
+ if (!TextUtils.isEmpty(getEntryId())) {
+ if (!mParams.isEmpty()) {
+ throw new IllegalStateException("Cannot set both an entry ID "
+ + "and other query paramters.");
+ }
+ return feedUrl + '/' + getEntryId();
+ }
+
+ // otherwise, append the querystring params.
+ StringBuilder sb = new StringBuilder();
+ sb.append(feedUrl);
+ Set<String> params = mParams.keySet();
+ boolean first = true;
+ if (feedUrl.contains("?")) {
+ first = false;
+ } else {
+ sb.append('?');
+ }
+ for (String param : params) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append('&');
+ }
+ sb.append(param);
+ sb.append('=');
+ String value = mParams.get(param);
+ String encodedValue = null;
+
+ try {
+ encodedValue = URLEncoder.encode(value, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen.
+ Log.w("QueryParamsImpl",
+ "UTF-8 not supported -- should not happen. "
+ + "Using default encoding.", uee);
+ encodedValue = URLEncoder.encode(value);
+ }
+ sb.append(encodedValue);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String getParamValue(String param) {
+ if (!(mParams.containsKey(param))) {
+ return null;
+ }
+ return mParams.get(param);
+ }
+
+ @Override
+ public void setParamValue(String param, String value) {
+ mParams.put(param, value);
+ }
+
+}
diff --git a/core/java/com/google/android/mms/pdu/EncodedStringValue.java b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
index 7696c5e..a27962d 100644
--- a/core/java/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
@@ -269,4 +269,16 @@
return new EncodedStringValue(value.mCharacterSet, value.mData);
}
+
+ public static EncodedStringValue[] encodeStrings(String[] array) {
+ int count = array.length;
+ if (count > 0) {
+ EncodedStringValue[] encodedArray = new EncodedStringValue[count];
+ for (int i = 0; i < count; i++) {
+ encodedArray[i] = new EncodedStringValue(array[i]);
+ }
+ return encodedArray;
+ }
+ return null;
+ }
}
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index d2a41f1..74af7650 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -31,6 +31,7 @@
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
+import android.provider.Telephony;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Threads;
@@ -54,6 +55,8 @@
import java.util.Set;
import java.util.Map.Entry;
+import com.google.android.mms.pdu.EncodedStringValue;
+
/**
* This class is the high-level manager of PDU storage.
*/
@@ -159,6 +162,7 @@
Part.CONTENT_TYPE,
Part.FILENAME,
Part.NAME,
+ Part.TEXT
};
private static final int PART_COLUMN_ID = 0;
@@ -169,6 +173,7 @@
private static final int PART_COLUMN_CONTENT_TYPE = 5;
private static final int PART_COLUMN_FILENAME = 6;
private static final int PART_COLUMN_NAME = 7;
+ private static final int PART_COLUMN_TEXT = 8;
private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP;
// These map are used for convenience in persist() and load().
@@ -414,26 +419,36 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = null;
- try {
- is = mContentResolver.openInputStream(partURI);
+ // Store simple string values directly in the database instead of an
+ // external file. This makes the text searchable and retrieval slightly
+ // faster.
+ if ("text/plain".equals(type) || "application/smil".equals(type)) {
+ String text = c.getString(PART_COLUMN_TEXT);
+ byte [] blob = new EncodedStringValue(text).getTextString();
+ baos.write(blob, 0, blob.length);
+ } else {
- byte[] buffer = new byte[256];
- int len = is.read(buffer);
- while (len >= 0) {
- baos.write(buffer, 0, len);
- len = is.read(buffer);
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to load part data", e);
- c.close();
- throw new MmsException(e);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to close stream", e);
- } // Ignore
+ try {
+ is = mContentResolver.openInputStream(partURI);
+
+ byte[] buffer = new byte[256];
+ int len = is.read(buffer);
+ while (len >= 0) {
+ baos.write(buffer, 0, len);
+ len = is.read(buffer);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to load part data", e);
+ c.close();
+ throw new MmsException(e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close stream", e);
+ } // Ignore
+ }
}
}
part.setData(baos.toByteArray());
@@ -719,29 +734,37 @@
InputStream is = null;
try {
- os = mContentResolver.openOutputStream(uri);
byte[] data = part.getData();
- if (data == null) {
- Uri dataUri = part.getDataUri();
- if ((dataUri == null) || (dataUri == uri)) {
- Log.w(TAG, "Can't find data for this part.");
- return;
- }
- is = mContentResolver.openInputStream(dataUri);
-
- if (LOCAL_LOGV) {
- Log.v(TAG, "Saving data to: " + uri);
- }
-
- byte[] buffer = new byte[256];
- for (int len = 0; (len = is.read(buffer)) != -1; ) {
- os.write(buffer, 0, len);
+ if ("text/plain".equals(contentType) || "application/smil".equals(contentType)) {
+ ContentValues cv = new ContentValues();
+ cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString());
+ if (mContentResolver.update(uri, cv, null, null) != 1) {
+ throw new MmsException("unable to update " + uri.toString());
}
} else {
- if (LOCAL_LOGV) {
- Log.v(TAG, "Saving data to: " + uri);
+ os = mContentResolver.openOutputStream(uri);
+ if (data == null) {
+ Uri dataUri = part.getDataUri();
+ if ((dataUri == null) || (dataUri == uri)) {
+ Log.w(TAG, "Can't find data for this part.");
+ return;
+ }
+ is = mContentResolver.openInputStream(dataUri);
+
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Saving data to: " + uri);
+ }
+
+ byte[] buffer = new byte[256];
+ for (int len = 0; (len = is.read(buffer)) != -1; ) {
+ os.write(buffer, 0, len);
+ }
+ } else {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Saving data to: " + uri);
+ }
+ os.write(data);
}
- os.write(data);
}
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to open Input/Output stream.", e);
diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java
index 922f5be..8a1298f 100644
--- a/core/java/com/google/android/net/GoogleHttpClient.java
+++ b/core/java/com/google/android/net/GoogleHttpClient.java
@@ -58,8 +58,8 @@
* and otherwise tweak HTTP requests.
*/
public class GoogleHttpClient implements HttpClient {
-
private static final String TAG = "GoogleHttpClient";
+ private static final boolean LOCAL_LOGV = Config.LOGV || false;
/** Exception thrown when a request is blocked by the URL rules. */
public static class BlockedRequestException extends IOException {
@@ -289,9 +289,7 @@
wrapper.setURI(uri);
request = wrapper;
- if (Config.LOGV) {
- Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
- }
+ if (LOCAL_LOGV) Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
return executeWithoutRewriting(request, context);
}
diff --git a/core/java/com/google/android/net/UrlRules.java b/core/java/com/google/android/net/UrlRules.java
index c269d1b..54d139d 100644
--- a/core/java/com/google/android/net/UrlRules.java
+++ b/core/java/com/google/android/net/UrlRules.java
@@ -20,6 +20,7 @@
import android.database.Cursor;
import android.provider.Checkin;
import android.provider.Settings;
+import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
@@ -53,6 +54,9 @@
* </pre>
*/
public class UrlRules {
+ public static final String TAG = "UrlRules";
+ public static final boolean LOCAL_LOGV = Config.LOGV || false;
+
/** Thrown when the rewrite rules can't be parsed. */
public static class RuleFormatException extends Exception {
public RuleFormatException(String msg) { super(msg); }
@@ -192,10 +196,11 @@
Settings.Gservices.PROVISIONING_DIGEST);
if (sCachedDigest != null && sCachedDigest.equals(digest)) {
// The digest is the same, so the rules are the same.
+ if (LOCAL_LOGV) Log.v(TAG, "Using cached rules for digest: " + digest);
return sCachedRules;
}
- // Get all the Gservices settings with names starting with "url:".
+ if (LOCAL_LOGV) Log.v(TAG, "Scanning for Gservices \"url:*\" rules");
Cursor cursor = resolver.query(Settings.Gservices.CONTENT_URI,
new String[] {
Settings.Gservices.NAME,
@@ -210,16 +215,18 @@
String name = cursor.getString(0).substring(4); // "url:X"
String value = cursor.getString(1);
if (value == null || value.length() == 0) continue;
+ if (LOCAL_LOGV) Log.v(TAG, " Rule " + name + ": " + value);
rules.add(new Rule(name, value));
} catch (RuleFormatException e) {
// Oops, Gservices has an invalid rule! Skip it.
- Log.e("UrlRules", "Invalid rule from Gservices", e);
+ Log.e(TAG, "Invalid rule from Gservices", e);
Checkin.logEvent(resolver,
Checkin.Events.Tag.GSERVICES_ERROR, e.toString());
}
}
sCachedRules = new UrlRules(rules.toArray(new Rule[rules.size()]));
sCachedDigest = digest;
+ if (LOCAL_LOGV) Log.v(TAG, "New rules stored for digest: " + digest);
} finally {
cursor.close();
}
diff --git a/core/jni/.android_server_BluetoothEventLoop.cpp.swp b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
new file mode 100644
index 0000000..d36e403
--- /dev/null
+++ b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
Binary files differ
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp
index 9017827..8950dfb 100644
--- a/core/jni/ActivityManager.cpp
+++ b/core/jni/ActivityManager.cpp
@@ -16,9 +16,9 @@
#include <unistd.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IBinder.h>
-#include <utils/IServiceManager.h>
-#include <utils/Parcel.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
namespace android {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 888cb11..015268b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,10 +11,16 @@
LOCAL_CFLAGS += -DPACKED=""
endif
+ifeq ($(WITH_JIT),true)
+ LOCAL_CFLAGS += -DWITH_JIT
+endif
+
ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
endif
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
LOCAL_SRC_FILES:= \
ActivityManager.cpp \
AndroidRuntime.cpp \
@@ -39,7 +45,6 @@
android_text_AndroidCharacter.cpp \
android_text_KeyCharacterMap.cpp \
android_os_Debug.cpp \
- android_os_Exec.cpp \
android_os_FileUtils.cpp \
android_os_MemoryFile.cpp \
android_os_ParcelFileDescriptor.cpp \
@@ -104,13 +109,12 @@
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
- android_bluetooth_Database.cpp \
android_bluetooth_HeadsetBase.cpp \
android_bluetooth_common.cpp \
android_bluetooth_BluetoothAudioGateway.cpp \
- android_bluetooth_RfcommSocket.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 \
@@ -150,11 +154,11 @@
libnativehelper \
libcutils \
libutils \
+ libbinder \
libnetutils \
libui \
libskiagl \
- libsgl \
- libcorecg \
+ libskia \
libsqlite \
libdvm \
libEGL \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c815301..2e73372 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -19,12 +19,12 @@
//#define LOG_NDEBUG 0
#include <android_runtime/AndroidRuntime.h>
-#include <utils/IBinder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <utils/misc.h>
-#include <utils/Parcel.h>
-#include <utils/string_array.h>
+#include <binder/Parcel.h>
+#include <utils/StringArray.h>
#include <utils/threads.h>
#include <cutils/properties.h>
@@ -130,7 +130,6 @@
extern int register_android_os_StatFs(JNIEnv *env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_Hardware(JNIEnv* env);
-extern int register_android_os_Exec(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_FileUtils(JNIEnv *env);
@@ -143,12 +142,11 @@
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_KeyCharacterMap(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
-extern int register_android_bluetooth_Database(JNIEnv* env);
extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
-extern int register_android_bluetooth_RfcommSocket(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);
@@ -509,11 +507,17 @@
//LOGD("language=%s region=%s\n", language, region);
}
-void AndroidRuntime::start(const char* className, const bool startSystemServer)
+/*
+ * Start the Dalvik Virtual Machine.
+ *
+ * Various arguments, most determined by system properties, are passed in.
+ * The "mOptions" vector is updated.
+ *
+ * Returns 0 on success.
+ */
+int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
- LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
-
- JNIEnv* env;
+ int result = -1;
JavaVMInitArgs initArgs;
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
@@ -522,24 +526,18 @@
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
- char* slashClassName = NULL;
- char* cp;
bool checkJni = false;
+ bool checkDexSum = false;
bool logStdio = false;
- enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
+ enum {
+ kEMDefault,
+ kEMIntPortable,
+ kEMIntFast,
+#if defined(WITH_JIT)
+ kEMJitCompiler,
+#endif
+ } executionMode = kEMDefault;
- blockSigpipe();
-
- /*
- * 'startSystemServer == true' means runtime is obslete and not run from
- * init.rc anymore, so we print out the boot start event here.
- */
- if (startSystemServer) {
- /* track our progress through the boot sequence */
- const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
- ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- }
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
@@ -557,10 +555,19 @@
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == 0) {
executionMode = kEMIntFast;
+#if defined(WITH_JIT)
+ } else if (strcmp(propBuf, "int:jit") == 0) {
+ executionMode = kEMJitCompiler;
+#endif
}
property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
+ property_get("dalvik.vm.check-dex-sum", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ checkDexSum = true;
+ }
+
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
logStdio = true;
@@ -572,19 +579,6 @@
strcpy(jniOptsBuf, "-Xjniopts:");
property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
- const char* rootDir = getenv("ANDROID_ROOT");
- if (rootDir == NULL) {
- rootDir = "/system";
- if (!hasDir("/system")) {
- LOG_FATAL("No root directory specified, and /android does not exist.");
- return;
- }
- setenv("ANDROID_ROOT", rootDir, 1);
- }
-
- const char* kernelHack = getenv("LD_ASSUME_KERNEL");
- //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
-
/* route exit() to our handler */
opt.extraInfo = (void*) runtime_exit;
opt.optionString = "exit";
@@ -658,6 +652,10 @@
if (opc != NULL) {
opt.optionString = "-Xgenregmap";
mOptions.add(opt);
+
+ /* turn on precise GC while we're at it */
+ opt.optionString = "-Xgc:precise";
+ mOptions.add(opt);
}
}
@@ -697,13 +695,87 @@
//opt.optionString = "-verbose:jni";
//mOptions.add(opt);
}
+
+#if defined(WITH_JIT)
+ /* Minimal profile threshold to trigger JIT compilation */
+ char jitThresholdBuf[sizeof("-Xthreshold:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.threshold", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitThresholdBuf, "-Xthreshold:");
+ strcat(jitThresholdBuf, propBuf);
+ opt.optionString = jitThresholdBuf;
+ mOptions.add(opt);
+ }
+
+ /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
+ char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.op", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitOpBuf, "-Xjitop:");
+ strcat(jitOpBuf, propBuf);
+ opt.optionString = jitOpBuf;
+ mOptions.add(opt);
+ }
+
+ /*
+ * Reverse the polarity of dalvik.vm.jit.op and force interpreter-only
+ * for non-selected opcodes.
+ */
+ property_get("dalvik.vm.jit.includeop", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xincludeselectedop";
+ mOptions.add(opt);
+ }
+
+ /* Force interpreter-only mode for selected methods */
+ char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.method", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitMethodBuf, "-Xjitmethod:");
+ strcat(jitMethodBuf, propBuf);
+ opt.optionString = jitMethodBuf;
+ mOptions.add(opt);
+ }
+
+ /*
+ * Reverse the polarity of dalvik.vm.jit.method and force interpreter-only
+ * for non-selected methods.
+ */
+ property_get("dalvik.vm.jit.includemethod", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xincludeselectedmethod";
+ mOptions.add(opt);
+ }
+
+ /*
+ * Enable profile collection on JIT'ed code.
+ */
+ property_get("dalvik.vm.jit.profile", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xjitprofile";
+ mOptions.add(opt);
+ }
+#endif
+
if (executionMode == kEMIntPortable) {
opt.optionString = "-Xint:portable";
mOptions.add(opt);
} else if (executionMode == kEMIntFast) {
opt.optionString = "-Xint:fast";
mOptions.add(opt);
+#if defined(WITH_JIT)
+ } else if (executionMode == kEMJitCompiler) {
+ opt.optionString = "-Xint:jit";
+ mOptions.add(opt);
+#endif
}
+
+ if (checkDexSum) {
+ /* perform additional DEX checksum tests */
+ opt.optionString = "-Xcheckdexsum";
+ mOptions.add(opt);
+ }
+
if (logStdio) {
/* convert stdout/stderr to log messages */
opt.optionString = "-Xlog-stdio";
@@ -771,11 +843,61 @@
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
- if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) {
+ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
LOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
+ result = 0;
+
+bail:
+ free(stackTraceFile);
+ return result;
+}
+
+/*
+ * Start the Android runtime. This involves starting the virtual machine
+ * and calling the "static void main(String[] args)" method in the class
+ * named by "className".
+ */
+void AndroidRuntime::start(const char* className, const bool startSystemServer)
+{
+ LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
+
+ char* slashClassName = NULL;
+ char* cp;
+ JNIEnv* env;
+
+ blockSigpipe();
+
+ /*
+ * 'startSystemServer == true' means runtime is obslete and not run from
+ * init.rc anymore, so we print out the boot start event here.
+ */
+ if (startSystemServer) {
+ /* track our progress through the boot sequence */
+ const int LOG_BOOT_PROGRESS_START = 3000;
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+ }
+
+ const char* rootDir = getenv("ANDROID_ROOT");
+ if (rootDir == NULL) {
+ rootDir = "/system";
+ if (!hasDir("/system")) {
+ LOG_FATAL("No root directory specified, and /android does not exist.");
+ goto bail;
+ }
+ setenv("ANDROID_ROOT", rootDir, 1);
+ }
+
+ //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
+ //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
+
+ /* start the virtual machine */
+ if (startVm(&mJavaVM, &env) != 0)
+ goto bail;
+
/*
* Register android functions.
*/
@@ -845,7 +967,6 @@
bail:
free(slashClassName);
- free(stackTraceFile);
}
void AndroidRuntime::start()
@@ -1095,7 +1216,6 @@
REG_JNI(register_android_database_SQLiteQuery),
REG_JNI(register_android_database_SQLiteStatement),
REG_JNI(register_android_os_Debug),
- REG_JNI(register_android_os_Exec),
REG_JNI(register_android_os_FileObserver),
REG_JNI(register_android_os_FileUtils),
REG_JNI(register_android_os_ParcelFileDescriptor),
@@ -1117,12 +1237,11 @@
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_bluetooth_Database),
REG_JNI(register_android_bluetooth_HeadsetBase),
REG_JNI(register_android_bluetooth_BluetoothAudioGateway),
- REG_JNI(register_android_bluetooth_RfcommSocket),
+ 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/CursorWindow.cpp b/core/jni/CursorWindow.cpp
index fb891c9..7864189 100644
--- a/core/jni/CursorWindow.cpp
+++ b/core/jni/CursorWindow.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "CursorWindow"
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <assert.h>
#include <string.h>
diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h
index 0fb074f..e98b009 100644
--- a/core/jni/CursorWindow.h
+++ b/core/jni/CursorWindow.h
@@ -21,7 +21,7 @@
#include <stddef.h>
#include <stdint.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <utils/RefBase.h>
#include <jni.h>
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3fb07a7..002d3db 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -5,7 +5,7 @@
#include "SkDither.h"
#include "SkUnPreMultiply.h"
-#include "Parcel.h"
+#include <binder/Parcel.h>
#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 1c2e055..dc72008 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -23,6 +23,7 @@
#include "SkGLCanvas.h"
#include "SkGraphics.h"
#include "SkImageRef_GlobalPool.h"
+#include "SkPorterDuff.h"
#include "SkShader.h"
#include "SkTemplates.h"
@@ -324,7 +325,7 @@
static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
jint color, SkPorterDuff::Mode mode) {
- canvas->drawColor(color, mode);
+ canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
}
static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index b6ec4a2..ebfb209 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -21,6 +21,7 @@
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
+#include "SkPorterDuff.h"
namespace android {
@@ -32,8 +33,9 @@
}
static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject,
- jint srcColor, SkPorterDuff::Mode porterDuffMode) {
- return SkColorFilter::CreatePorterDuffFilter(srcColor, porterDuffMode);
+ jint srcColor, SkPorterDuff::Mode mode) {
+ return SkColorFilter::CreateModeFilter(srcColor,
+ SkPorterDuff::ToXfermodeMode(mode));
}
static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d1fe83e..6b7f045 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -48,6 +48,13 @@
static jclass gFontMetricsInt_class;
static JMetricsID gFontMetricsInt_fieldID;
+static void defaultSettingsForAndroid(SkPaint* paint) {
+ // looks best we decided
+ paint->setHinting(SkPaint::kSlight_Hinting);
+ // utf16 is required for java
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
class SkPaintGlue {
public:
@@ -57,8 +64,7 @@
static SkPaint* init(JNIEnv* env, jobject clazz) {
SkPaint* obj = new SkPaint();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
return obj;
}
@@ -69,8 +75,7 @@
static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
obj->reset();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
}
static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index effb1c8..11c608c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -75,9 +75,8 @@
return result;
}
- static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, SkPath::BoundsType btype) {
- SkRect bounds_;
- obj->computeBounds(&bounds_, btype);
+ static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, int boundstype) {
+ const SkRect& bounds_ = obj->getBounds();
GraphicsJNI::rect_to_jrectf(bounds_, env, bounds);
}
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 1dc0314..723cd37 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -134,7 +134,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include "Parcel.h"
+#include <binder/Parcel.h>
#include "android_util_Binder.h"
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
new file mode 100644
index 0000000..9c4f7c7
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright 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_TAG "BluetoothSocket.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "utils/Log.h"
+#include "cutils/abort_socket.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sco.h>
+#endif
+
+#define TYPE_AS_STR(t) \
+ ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP"))
+
+namespace android {
+
+static jfieldID field_mAuth; /* read-only */
+static jfieldID field_mEncrypt; /* read-only */
+static jfieldID field_mType; /* read-only */
+static jfieldID field_mAddress; /* read-only */
+static jfieldID field_mPort; /* read-only */
+static jfieldID field_mSocketData;
+static jmethodID method_BluetoothSocket_ctor;
+static jclass class_BluetoothSocket;
+
+/* Keep TYPE_RFCOMM etc in sync with BluetoothSocket.java */
+static const int TYPE_RFCOMM = 1;
+static const int TYPE_SCO = 2;
+static const int TYPE_L2CAP = 3; // TODO: Test l2cap code paths
+
+static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
+ struct asocket *s =
+ (struct asocket *) env->GetIntField(obj, field_mSocketData);
+ if (!s)
+ jniThrowException(env, "java/io/IOException", "null socketData");
+ return s;
+}
+
+static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ struct asocket *s = asocket_init(fd);
+
+ if (!s) {
+ LOGV("asocket_init() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ env->SetIntField(obj, field_mSocketData, (jint)s);
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void initSocketNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int fd;
+ int lm = 0;
+ jboolean auth;
+ jboolean encrypt;
+ jint type;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ break;
+ case TYPE_SCO:
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ break;
+ case TYPE_L2CAP:
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ if (fd < 0) {
+ LOGV("socket() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ auth = env->GetBooleanField(obj, field_mAuth);
+ encrypt = env->GetBooleanField(obj, field_mEncrypt);
+
+ /* kernel does not yet support LM for SCO */
+ switch (type) {
+ case TYPE_RFCOMM:
+ lm |= auth ? RFCOMM_LM_AUTH : 0;
+ lm |= encrypt? RFCOMM_LM_ENCRYPT : 0;
+ break;
+ case TYPE_L2CAP:
+ lm |= auth ? L2CAP_LM_AUTH : 0;
+ lm |= encrypt? L2CAP_LM_ENCRYPT : 0;
+ break;
+ }
+
+ if (lm) {
+ if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
+ LOGV("setsockopt() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+ }
+
+ LOGV("...fd %d created (%s, lm = %x)", fd, TYPE_AS_STR(type), lm);
+
+ initSocketFromFdNative(env, obj, fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void connectNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jint type;
+ const char *c_address;
+ jstring address;
+ bdaddr_t bdaddress;
+ socklen_t addr_sz;
+ struct sockaddr *addr;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ type = env->GetIntField(obj, field_mType);
+
+ /* parse address into bdaddress */
+ address = (jstring) env->GetObjectField(obj, field_mAddress);
+ c_address = env->GetStringUTFChars(address, NULL);
+ if (get_bdaddr(c_address, &bdaddress)) {
+ env->ReleaseStringUTFChars(address, c_address);
+ jniThrowIOException(env, EINVAL);
+ return;
+ }
+ env->ReleaseStringUTFChars(address, c_address);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+
+ memset(addr, 0, addr_sz);
+ addr_rc.rc_family = AF_BLUETOOTH;
+ addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+
+ memset(addr, 0, addr_sz);
+ addr_sco.sco_family = AF_BLUETOOTH;
+ memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+
+ memset(addr, 0, addr_sz);
+ addr_l2.l2_family = AF_BLUETOOTH;
+ addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ ret = asocket_connect(s, addr, addr_sz, -1);
+ LOGV("...connect(%d, %s) = %d (errno %d)",
+ s->fd, TYPE_AS_STR(type), ret, errno);
+
+ if (ret)
+ jniThrowIOException(env, errno);
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void bindListenNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ jint type;
+ socklen_t addr_sz;
+ struct sockaddr *addr;
+ bdaddr_t bdaddr = *BDADDR_ANY;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+
+ memset(addr, 0, addr_sz);
+ addr_rc.rc_family = AF_BLUETOOTH;
+ addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+
+ memset(addr, 0, addr_sz);
+ addr_sco.sco_family = AF_BLUETOOTH;
+ memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+
+ memset(addr, 0, addr_sz);
+ addr_l2.l2_family = AF_BLUETOOTH;
+ addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ if (bind(s->fd, addr, addr_sz)) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ if (listen(s->fd, 1)) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int fd;
+ jint type;
+ struct sockaddr *addr;
+ socklen_t addr_sz;
+ jstring addr_jstr;
+ char addr_cstr[BTADDR_SIZE];
+ bdaddr_t *bdaddr;
+ jboolean auth;
+ jboolean encrypt;
+
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return NULL;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+ bdaddr = &addr_rc.rc_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+ bdaddr = &addr_sco.sco_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+ bdaddr = &addr_l2.l2_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return NULL;
+ }
+
+ fd = asocket_accept(s, addr, &addr_sz, timeout);
+
+ LOGV("...accept(%d, %s) = %d (errno %d)",
+ s->fd, TYPE_AS_STR(type), fd, errno);
+
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ /* Connected - return new BluetoothSocket */
+ auth = env->GetBooleanField(obj, field_mAuth);
+ encrypt = env->GetBooleanField(obj, field_mEncrypt);
+
+ get_bdaddr_as_string(bdaddr, addr_cstr);
+
+ addr_jstr = env->NewStringUTF(addr_cstr);
+ return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor,
+ type, fd, auth, encrypt, addr_jstr, -1);
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return NULL;
+}
+
+static jint availableNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int available;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ if (ioctl(s->fd, FIONREAD, &available) < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ return available;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+/** jb must not be null. offset and offset+length must be within array */
+static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ b = env->GetByteArrayElements(jb, NULL);
+ if (b == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+
+ ret = asocket_read(s, &b[offset], length, -1);
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
+ return -1;
+ }
+
+ env->ReleaseByteArrayElements(jb, b, 0);
+ return (jint)ret;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+/** jb must not be null. offset and offset+length must be within array */
+static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ b = env->GetByteArrayElements(jb, NULL);
+ if (b == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+
+ ret = asocket_write(s, &b[offset], length, -1);
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
+ return -1;
+ }
+
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit
+ return (jint)ret;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+static void closeNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ asocket_abort(s);
+
+ LOGV("...asocket_abort(%d) complete", s->fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void destroyNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ struct asocket *s = get_socketData(env, obj);
+ int fd = s->fd;
+
+ if (!s)
+ return;
+
+ asocket_destroy(s);
+
+ LOGV("...asocket_destroy(%d) complete", fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static JNINativeMethod sMethods[] = {
+ {"initSocketNative", "()V", (void*) initSocketNative},
+ {"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative},
+ {"connectNative", "()V", (void *) connectNative},
+ {"bindListenNative", "()V", (void *) bindListenNative},
+ {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
+ {"availableNative", "()I", (void *) availableNative},
+ {"readNative", "([BII)I", (void *) readNative},
+ {"writeNative", "([BII)I", (void *) writeNative},
+ {"closeNative", "()V", (void *) closeNative},
+ {"destroyNative", "()V", (void *) destroyNative},
+};
+
+int register_android_bluetooth_BluetoothSocket(JNIEnv *env) {
+ jclass clazz = env->FindClass("android/bluetooth/BluetoothSocket");
+ if (clazz == NULL)
+ return -1;
+ class_BluetoothSocket = (jclass) env->NewGlobalRef(clazz);
+ field_mType = env->GetFieldID(clazz, "mType", "I");
+ field_mAddress = env->GetFieldID(clazz, "mAddress", "Ljava/lang/String;");
+ field_mPort = env->GetFieldID(clazz, "mPort", "I");
+ field_mAuth = env->GetFieldID(clazz, "mAuth", "Z");
+ field_mEncrypt = env->GetFieldID(clazz, "mEncrypt", "Z");
+ field_mSocketData = env->GetFieldID(clazz, "mSocketData", "I");
+ method_BluetoothSocket_ctor = env->GetMethodID(clazz, "<init>", "(IIZZLjava/lang/String;I)V");
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/BluetoothSocket", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
+
diff --git a/core/jni/android_bluetooth_Database.cpp b/core/jni/android_bluetooth_Database.cpp
deleted file mode 100644
index 73b8efd..0000000
--- a/core/jni/android_bluetooth_Database.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Database"
-#define LOG_TAG "bluetooth_Database.cpp"
-
-#include "android_bluetooth_common.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-
-#ifdef HAVE_BLUETOOTH
-#include <dbus/dbus.h>
-#endif
-
-namespace android {
-
-#ifdef HAVE_BLUETOOTH
-static DBusConnection* conn = NULL; // Singleton thread-safe connection
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- conn = NULL;
-#endif
-}
-
-static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-
-#ifdef HAVE_BLUETOOTH
- if (conn == NULL) {
- DBusError err;
- dbus_error_init(&err);
- dbus_threads_init_default();
- conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (dbus_error_is_set(&err)) {
- LOGE("Could not get onto the system bus!");
- dbus_error_free(&err);
- }
- dbus_connection_set_exit_on_disconnect(conn, FALSE);
- }
-#endif
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-}
-
-static jint addServiceRecordNative(JNIEnv *env, jobject object,
- jbyteArray record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- jbyte* c_record = env->GetByteArrayElements(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "AddServiceRecord",
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &c_record,
- env->GetArrayLength(record),
- DBUS_TYPE_INVALID);
- env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static jint addServiceRecordFromXmlNative(JNIEnv *env, jobject object,
- jstring record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- const char *c_record = env->GetStringUTFChars(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "AddServiceRecordFromXML",
- DBUS_TYPE_STRING, &c_record,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(record, c_record);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static void updateServiceRecordNative(JNIEnv *env, jobject object,
- jint handle,
- jbyteArray record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- jbyte* c_record = env->GetByteArrayElements(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "UpdateServiceRecord",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &c_record,
- env->GetArrayLength(record),
- DBUS_TYPE_INVALID);
- env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
- }
-#endif
-}
-
-static void updateServiceRecordFromXmlNative(JNIEnv *env, jobject object,
- jint handle,
- jstring record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- const char *c_record = env->GetStringUTFChars(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "UpdateServiceRecordFromXML",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_STRING, &c_record,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(record, c_record);
- }
-#endif
-}
-
-/* private static native void removeServiceRecordNative(int handle); */
-static void removeServiceRecordNative(JNIEnv *env, jobject object,
- jint handle) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "RemoveServiceRecord",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_INVALID);
- }
-#endif
-}
-
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
- {"addServiceRecordNative", "([B)I", (void*)addServiceRecordNative},
- {"addServiceRecordFromXmlNative", "(Ljava/lang/String;)I", (void*)addServiceRecordFromXmlNative},
- {"updateServiceRecordNative", "(I[B)V", (void*)updateServiceRecordNative},
- {"updateServiceRecordFromXmlNative", "(ILjava/lang/String;)V", (void*)updateServiceRecordFromXmlNative},
- {"removeServiceRecordNative", "(I)V", (void*)removeServiceRecordNative},
-};
-
-int register_android_bluetooth_Database(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/bluetooth/Database", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_bluetooth_RfcommSocket.cpp b/core/jni/android_bluetooth_RfcommSocket.cpp
deleted file mode 100644
index 3ed35d9..0000000
--- a/core/jni/android_bluetooth_RfcommSocket.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "bluetooth_RfcommSocket.cpp"
-
-#include "android_bluetooth_common.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-#endif
-
-namespace android {
-
-#ifdef HAVE_BLUETOOTH
-static jfieldID field_mNativeData;
-static jfieldID field_mTimeoutRemainingMs;
-static jfieldID field_mAcceptTimeoutRemainingMs;
-static jfieldID field_mAddress;
-static jfieldID field_mPort;
-
-typedef struct {
- jstring address;
- const char *c_address;
- int rfcomm_channel;
- int last_read_err;
- int rfcomm_sock;
- // < 0 -- in progress,
- // 0 -- not connected
- // > 0 connected
- // 1 input is open
- // 2 output is open
- // 3 both input and output are open
- int rfcomm_connected;
- int rfcomm_sock_flags;
-} native_data_t;
-
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
- return (native_data_t *)(env->GetIntField(object, field_mNativeData));
-}
-
-static inline void init_socket_info(
- JNIEnv *env, jobject object,
- native_data_t *nat,
- jstring address,
- jint rfcomm_channel) {
- nat->address = (jstring)env->NewGlobalRef(address);
- nat->c_address = env->GetStringUTFChars(nat->address, NULL);
- nat->rfcomm_channel = (int)rfcomm_channel;
-}
-
-static inline void cleanup_socket_info(JNIEnv *env, native_data_t *nat) {
- if (nat->c_address != NULL) {
- env->ReleaseStringUTFChars(nat->address, nat->c_address);
- env->DeleteGlobalRef(nat->address);
- nat->c_address = NULL;
- }
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
- field_mAcceptTimeoutRemainingMs = get_field(env, clazz, "mAcceptTimeoutRemainingMs", "I");
- field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
- field_mPort = get_field(env, clazz, "mPort", "I");
-#endif
-}
-
-static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-
- native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
- if (nat == NULL) {
- LOGE("%s: out of memory!", __FUNCTION__);
- return;
- }
-
- env->SetIntField(object, field_mNativeData, (jint)nat);
- nat->rfcomm_sock = -1;
- nat->rfcomm_connected = 0;
-#endif
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- free(nat);
- }
-#endif
-}
-
-static jobject createNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- int lm;
- native_data_t *nat = get_native_data(env, obj);
- nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
- strerror(errno));
- return NULL;
- }
-
- lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
-
- if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
- sizeof(lm)) < 0) {
- LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
- close(nat->rfcomm_sock);
- return NULL;
- }
-
- return jniCreateFileDescriptor(env, nat->rfcomm_sock);
-#else
- return NULL;
-#endif
-}
-
-static void destroyNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
- cleanup_socket_info(env, nat);
- if (nat->rfcomm_sock >= 0) {
- close(nat->rfcomm_sock);
- nat->rfcomm_sock = -1;
- }
-#endif
-}
-
-
-static jboolean connectNative(JNIEnv *env, jobject obj,
- jstring address, jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
-
- if (nat->rfcomm_sock >= 0) {
- if (nat->rfcomm_connected) {
- LOGI("RFCOMM socket: %s.",
- (nat->rfcomm_connected > 0) ? "already connected" : "connection is in progress");
- return JNI_TRUE;
- }
-
- init_socket_info(env, obj, nat, address, port);
-
- struct sockaddr_rc addr;
- memset(&addr, 0, sizeof(struct sockaddr_rc));
- get_bdaddr(nat->c_address, &addr.rc_bdaddr);
- addr.rc_channel = nat->rfcomm_channel;
- addr.rc_family = AF_BLUETOOTH;
- nat->rfcomm_connected = 0;
-
- while (nat->rfcomm_connected == 0) {
- if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
- sizeof(addr)) < 0) {
- if (errno == EINTR) continue;
- LOGE("connect error: %s (%d)\n", strerror(errno), errno);
- break;
- } else {
- nat->rfcomm_connected = 3; // input and output
- }
- }
- } else {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- }
-
- if (nat->rfcomm_connected > 0) {
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean connectAsyncNative(JNIEnv *env, jobject obj,
- jstring address, jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- return JNI_FALSE;
- }
-
- if (nat->rfcomm_connected) {
- LOGI("RFCOMM socket: %s.",
- (nat->rfcomm_connected > 0) ?
- "already connected" : "connection is in progress");
- return JNI_TRUE;
- }
-
- init_socket_info(env, obj, nat, address, port);
-
- struct sockaddr_rc addr;
- memset(&addr, 0, sizeof(struct sockaddr_rc));
- get_bdaddr(nat->c_address, &addr.rc_bdaddr);
- addr.rc_channel = nat->rfcomm_channel;
- addr.rc_family = AF_BLUETOOTH;
-
- nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
- if (fcntl(nat->rfcomm_sock,
- F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
- int rc;
- nat->rfcomm_connected = 0;
- errno = 0;
- rc = connect(nat->rfcomm_sock,
- (struct sockaddr *)&addr,
- sizeof(addr));
-
- if (rc >= 0) {
- nat->rfcomm_connected = 3;
- LOGI("RFCOMM async connect immediately successful");
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
- else if (rc < 0) {
- if (errno == EINPROGRESS || errno == EAGAIN)
- {
- LOGI("RFCOMM async connect is in progress (%s)",
- strerror(errno));
- nat->rfcomm_connected = -1;
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
- else
- {
- LOGE("RFCOMM async connect error (%d): %s (%d)",
- nat->rfcomm_sock, strerror(errno), errno);
- return JNI_FALSE;
- }
- }
- } // fcntl(nat->rfcomm_sock ...)
-#endif
- return JNI_FALSE;
-}
-
-static jboolean interruptAsyncConnectNative(JNIEnv *env, jobject obj) {
- //WRITEME
- return JNI_TRUE;
-}
-
-static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
- jint timeout_ms) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- struct sockaddr_rc addr;
- native_data_t *nat = get_native_data(env, obj);
-
- env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- return -1;
- }
-
- if (nat->rfcomm_connected > 0) {
- LOGI("%s: RFCOMM is already connected!", __FUNCTION__);
- return 1;
- }
-
- /* Do an asynchronous select() */
- int n;
- fd_set rset, wset;
- struct timeval to;
-
- FD_ZERO(&rset);
- FD_ZERO(&wset);
- FD_SET(nat->rfcomm_sock, &rset);
- FD_SET(nat->rfcomm_sock, &wset);
- if (timeout_ms >= 0) {
- to.tv_sec = timeout_ms / 1000;
- to.tv_usec = 1000 * (timeout_ms % 1000);
- }
- n = select(nat->rfcomm_sock + 1,
- &rset,
- &wset,
- NULL,
- (timeout_ms < 0 ? NULL : &to));
-
- if (timeout_ms > 0) {
- jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
- LOGI("Remaining time %ldms", (long)remaining);
- env->SetIntField(obj, field_mTimeoutRemainingMs,
- remaining);
- }
-
- if (n <= 0) {
- if (n < 0) {
- LOGE("select() on RFCOMM socket: %s (%d)",
- strerror(errno),
- errno);
- return -1;
- }
- return 0;
- }
- /* n must be equal to 1 and either rset or wset must have the
- file descriptor set. */
- LOGI("select() returned %d.", n);
- if (FD_ISSET(nat->rfcomm_sock, &rset) ||
- FD_ISSET(nat->rfcomm_sock, &wset)) {
- /* A trial async read() will tell us if everything is OK. */
- char ch;
- errno = 0;
- int nr = read(nat->rfcomm_sock, &ch, 1);
- /* It should be that nr != 1 because we just opened a socket
- and we haven't sent anything over it for the other side to
- respond... but one can't be paranoid enough.
- */
- if (nr >= 0 || errno != EAGAIN) {
- LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
- strerror(errno),
- errno,
- nr);
- /* Clear the rfcomm_connected flag to cause this function
- to re-create the socket and re-attempt the connect()
- the next time it is called.
- */
- nat->rfcomm_connected = 0;
- /* Restore the blocking properties of the socket. */
- fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
- return -1;
- }
- /* Restore the blocking properties of the socket. */
- fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
- LOGI("Successful RFCOMM socket connect.");
- nat->rfcomm_connected = 3; // input and output
- return 1;
- }
-#endif
- return -1;
-}
-
-static jboolean shutdownNative(JNIEnv *env, jobject obj,
- jboolean shutdownInput) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- /* NOTE: If you change the bcode to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
- int rc = shutdown(nat->rfcomm_sock,
- shutdownInput ? SHUT_RD : SHUT_WR);
- if (!rc) {
- nat->rfcomm_connected &=
- shutdownInput ? ~1 : ~2;
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint isConnectedNative(JNIEnv *env, jobject obj) {
- LOGI(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- const native_data_t *nat = get_native_data(env, obj);
- return nat->rfcomm_connected;
-#endif
- return 0;
-}
-
-//@@@@@@@@@ bind to device???
-static jboolean bindNative(JNIEnv *env, jobject obj, jstring device,
- jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-
- /* NOTE: If you change the code to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- const native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
-
- struct sockaddr_rc laddr;
- int lm;
-
- lm = 0;
-/*
- lm |= RFCOMM_LM_MASTER;
- lm |= RFCOMM_LM_AUTH;
- lm |= RFCOMM_LM_ENCRYPT;
- lm |= RFCOMM_LM_SECURE;
-*/
-
- if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
- LOGE("Can't set RFCOMM link mode");
- return JNI_FALSE;
- }
-
- laddr.rc_family = AF_BLUETOOTH;
- bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
- laddr.rc_channel = port;
-
- if (bind(nat->rfcomm_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
- LOGE("Can't bind RFCOMM socket");
- return JNI_FALSE;
- }
-
- env->SetIntField(obj, field_mPort, port);
-
- return JNI_TRUE;
-#endif
- return JNI_FALSE;
-}
-
-static jboolean listenNative(JNIEnv *env, jobject obj, jint backlog) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- /* NOTE: If you change the code to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- const native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
- return listen(nat->rfcomm_sock, backlog) < 0 ? JNI_FALSE : JNI_TRUE;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static int set_nb(int sk, bool nb) {
- int flags = fcntl(sk, F_GETFL);
- if (flags < 0) {
- LOGE("Can't get socket flags with fcntl(): %s (%d)",
- strerror(errno), errno);
- close(sk);
- return -1;
- }
- flags &= ~O_NONBLOCK;
- if (nb) flags |= O_NONBLOCK;
- int status = fcntl(sk, F_SETFL, flags);
- if (status < 0) {
- LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
- strerror(errno), errno);
- close(sk);
- return -1;
- }
- return 0;
-}
-
-// Note: the code should check at a higher level to see whether
-// listen() has been called.
-#ifdef HAVE_BLUETOOTH
-static int do_accept(JNIEnv* env, jobject object, int sock,
- jobject newsock,
- jfieldID out_address,
- bool must_succeed) {
-
- if (must_succeed && set_nb(sock, true) < 0)
- return -1;
-
- struct sockaddr_rc raddr;
- int alen = sizeof(raddr);
- int nsk = accept(sock, (struct sockaddr *) &raddr, &alen);
- if (nsk < 0) {
- LOGE("Error on accept from socket fd %d: %s (%d).",
- sock,
- strerror(errno),
- errno);
- if (must_succeed) set_nb(sock, false);
- return -1;
- }
-
- char addr[BTADDR_SIZE];
- get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
- env->SetObjectField(newsock, out_address, env->NewStringUTF(addr));
-
- LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
- sock,
- nsk,
- addr,
- raddr.rc_channel);
- if (must_succeed) set_nb(sock, false);
- return nsk;
-}
-#endif /*HAVE_BLUETOOTH*/
-
-static jobject acceptNative(JNIEnv *env, jobject obj,
- jobject newsock, jint timeoutMs) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
-
- if (newsock == NULL) {
- LOGE("%s: newsock = NULL\n", __FUNCTION__);
- return JNI_FALSE;
- }
-
- int nsk = -1;
- if (timeoutMs < 0) {
- /* block until accept() succeeds */
- nsk = do_accept(env, obj, nat->rfcomm_sock,
- newsock, field_mAddress, false);
- if (nsk < 0) {
- return NULL;
- }
- }
- else {
- /* wait with a timeout */
-
- struct pollfd fds;
- fds.fd = nat->rfcomm_sock;
- fds.events = POLLIN | POLLPRI | POLLOUT | POLLERR;
-
- env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, 0);
- int n = poll(&fds, 1, timeoutMs);
- if (n <= 0) {
- if (n < 0) {
- LOGE("listening poll() on RFCOMM socket: %s (%d)",
- strerror(errno),
- errno);
- env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, timeoutMs);
- }
- else {
- LOGI("listening poll() on RFCOMM socket timed out");
- }
- return NULL;
- }
-
- LOGI("listening poll() on RFCOMM socket returned %d", n);
- if (fds.fd == nat->rfcomm_sock) {
- if (fds.revents & (POLLIN | POLLPRI | POLLOUT)) {
- LOGI("Accepting connection.\n");
- nsk = do_accept(env, obj, nat->rfcomm_sock,
- newsock, field_mAddress, true);
- if (nsk < 0) {
- return NULL;
- }
- }
- }
- }
-
- LOGI("Connection accepted, new socket fd = %d.", nsk);
- native_data_t *newnat = get_native_data(env, newsock);
- newnat->rfcomm_sock = nsk;
- newnat->rfcomm_connected = 3;
- return jniCreateFileDescriptor(env, nsk);
-#else
- return NULL;
-#endif
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
-
- {"createNative", "()Ljava/io/FileDescriptor;", (void *)createNative},
- {"destroyNative", "()V", (void *)destroyNative},
- {"connectNative", "(Ljava/lang/String;I)Z", (void *)connectNative},
- {"connectAsyncNative", "(Ljava/lang/String;I)Z", (void *)connectAsyncNative},
- {"interruptAsyncConnectNative", "()Z", (void *)interruptAsyncConnectNative},
- {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
- {"shutdownNative", "(Z)Z", (void *)shutdownNative},
- {"isConnectedNative", "()I", (void *)isConnectedNative},
-
- {"bindNative", "(Ljava/lang/String;I)Z", (void*)bindNative},
- {"listenNative", "(I)Z", (void*)listenNative},
- {"acceptNative", "(Landroid/bluetooth/RfcommSocket;I)Ljava/io/FileDescriptor;", (void*)acceptNative},
-};
-
-int register_android_bluetooth_RfcommSocket(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/bluetooth/RfcommSocket", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp
index 0b8a604..343fa53 100644
--- a/core/jni/android_bluetooth_common.cpp
+++ b/core/jni/android_bluetooth_common.cpp
@@ -36,6 +36,43 @@
namespace android {
#ifdef HAVE_BLUETOOTH
+
+static Properties remote_device_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Icon", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"UUIDs", DBUS_TYPE_ARRAY},
+ {"Paired", DBUS_TYPE_BOOLEAN},
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ {"Trusted", DBUS_TYPE_BOOLEAN},
+ {"Alias", DBUS_TYPE_STRING},
+ {"Nodes", DBUS_TYPE_ARRAY},
+ {"Adapter", DBUS_TYPE_OBJECT_PATH},
+ {"LegacyPairing", DBUS_TYPE_BOOLEAN},
+ {"RSSI", DBUS_TYPE_INT16},
+ {"TX", DBUS_TYPE_UINT32}
+};
+
+static Properties adapter_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"Powered", DBUS_TYPE_BOOLEAN},
+ {"Discoverable", DBUS_TYPE_BOOLEAN},
+ {"DiscoverableTimeout", DBUS_TYPE_UINT32},
+ {"Pairable", DBUS_TYPE_BOOLEAN},
+ {"PairableTimeout", DBUS_TYPE_UINT32},
+ {"Discovering", DBUS_TYPE_BOOLEAN},
+ {"Devices", DBUS_TYPE_ARRAY},
+};
+
+typedef union {
+ char *str_val;
+ int int_val;
+ char **array_val;
+} property_value;
+
jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
const char *mtype) {
jfieldID field = env->GetFieldID(clazz, member, mtype);
@@ -332,6 +369,44 @@
return ret;
}
+static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
+ const char *value, int index) {
+ jstring obj;
+ obj = env->NewStringUTF(value);
+ env->SetObjectArrayElement(strArray, index, obj);
+ env->DeleteLocalRef(obj);
+}
+
+jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
+ DBusMessage *reply) {
+
+ DBusError err;
+ char **list;
+ int i, len;
+ jobjectArray strArray = NULL;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args (reply,
+ &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
+ &list, &len,
+ DBUS_TYPE_INVALID)) {
+ jclass stringClass;
+ jstring classNameStr;
+
+ stringClass = env->FindClass("java/lang/String");
+ strArray = env->NewObjectArray(len, stringClass, NULL);
+
+ for (i = 0; i < len; i++)
+ set_object_array_element(env, strArray, list[i], i);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ return strArray;
+}
+
jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
DBusError err;
@@ -353,11 +428,8 @@
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(len, stringClass, NULL);
- for (i = 0; i < len; i++) {
- //LOGV("%s: array[%d] = [%s]", __FUNCTION__, i, list[i]);
- env->SetObjectArrayElement(strArray, i,
- env->NewStringUTF(list[i]));
- }
+ for (i = 0; i < len; i++)
+ set_object_array_element(env, strArray, list[i], i);
} else {
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
}
@@ -390,17 +462,263 @@
return byteArray;
}
-void get_bdaddr(const char *str, bdaddr_t *ba) {
+void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+ DBusMessageIter value_iter;
+ char var_type[2] = { type, '\0'};
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
+ dbus_message_iter_append_basic(&value_iter, type, val);
+ dbus_message_iter_close_container(iter, &value_iter);
+}
+
+int get_property(DBusMessageIter iter, Properties *properties,
+ int max_num_properties, int *prop_index, property_value *value, int *len) {
+ DBusMessageIter prop_val, array_val_iter;
+ char *property = NULL;
+ uint32_t array_type;
+ char *str_val;
+ int i, j, type, int_val;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -1;
+ dbus_message_iter_get_basic(&iter, &property);
+ if (!dbus_message_iter_next(&iter))
+ return -1;
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return -1;
+ for (i = 0; i < max_num_properties; i++) {
+ if (!strncmp(property, properties[i].name, strlen(property)))
+ break;
+ }
+ *prop_index = i;
+ if (i == max_num_properties)
+ return -1;
+
+ dbus_message_iter_recurse(&iter, &prop_val);
+ type = properties[*prop_index].type;
+ if (dbus_message_iter_get_arg_type(&prop_val) != type) {
+ LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
+ dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
+ return -1;
+ }
+
+ switch(type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(&prop_val, &value->str_val);
+ *len = 1;
+ break;
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_BOOLEAN:
+ dbus_message_iter_get_basic(&prop_val, &int_val);
+ value->int_val = int_val;
+ *len = 1;
+ break;
+ case DBUS_TYPE_ARRAY:
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ array_type = dbus_message_iter_get_arg_type(&array_val_iter);
+ *len = 0;
+ value->array_val = NULL;
+ if (array_type == DBUS_TYPE_OBJECT_PATH ||
+ array_type == DBUS_TYPE_STRING){
+ j = 0;
+ do {
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ // Allocate an array of char *
+ *len = j;
+ char **tmp = (char **)malloc(sizeof(char *) * *len);
+ if (!tmp)
+ return -1;
+ j = 0;
+ do {
+ dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ value->array_val = tmp;
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
+ property_value *value, int len, int *array_index ) {
+ char **prop_val = NULL;
+ char buf[32] = {'\0'}, buf1[32] = {'\0'};
+ int i;
+
+ char *name = property->name;
+ int prop_type = property->type;
+
+ set_object_array_element(env, strArray, name, *array_index);
+ *array_index += 1;
+
+ if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
+ sprintf(buf, "%d", value->int_val);
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_BOOLEAN) {
+ sprintf(buf, "%s", value->int_val ? "true" : "false");
+
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_ARRAY) {
+ // Write the length first
+ sprintf(buf1, "%d", len);
+ set_object_array_element(env, strArray, buf1, *array_index);
+ *array_index += 1;
+
+ prop_val = value->array_val;
+ for (i = 0; i < len; i++) {
+ set_object_array_element(env, strArray, prop_val[i], *array_index);
+ *array_index += 1;
+ }
+ } else {
+ set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
+ *array_index += 1;
+ }
+}
+
+jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
+ const int max_num_properties) {
+ DBusMessageIter dict_entry, dict;
+ jobjectArray strArray = NULL;
+ property_value value;
+ int i, size = 0,array_index = 0;
+ int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
+ struct {
+ property_value value;
+ int len;
+ bool used;
+ } values[max_num_properties];
+ int t, j;
+
+ jclass stringClass = env->FindClass("java/lang/String");
+ DBusError err;
+ dbus_error_init(&err);
+
+ for (i = 0; i < max_num_properties; i++) {
+ values[i].used = false;
+ }
+
+ if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ goto failure;
+ dbus_message_iter_recurse(iter, &dict);
+ do {
+ len = 0;
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+ goto failure;
+ dbus_message_iter_recurse(&dict, &dict_entry);
+
+ if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
+ &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ values[prop_index].value = value;
+ values[prop_index].len = len;
+ values[prop_index].used = true;
+ } else {
+ goto failure;
+ }
+ } while(dbus_message_iter_next(&dict));
+
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ for (i = 0; i < max_num_properties; i++) {
+ if (values[i].used) {
+ create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
+ &array_index);
+
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ }
+
+ }
+ return strArray;
+
+failure:
+ if (dbus_error_is_set(&err))
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ for (i = 0; i < max_num_properties; i++)
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ return NULL;
+}
+
+jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
+ Properties *properties, int max_num_properties) {
+ DBusMessageIter iter;
+ DBusError err;
+ jobjectArray strArray = NULL;
+ jclass stringClass= env->FindClass("java/lang/String");
+ int len = 0, prop_index = -1;
+ int array_index = 0, size = 0;
+ property_value value;
+
+ dbus_error_init(&err);
+ if (!dbus_message_iter_init(msg, &iter))
+ goto failure;
+
+ if (!get_property(iter, properties, max_num_properties,
+ &prop_index, &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ create_prop_array(env, strArray, &properties[prop_index],
+ &value, len, &array_index);
+
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
+ free(value.array_val);
+
+ return strArray;
+ }
+failure:
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return NULL;
+}
+
+jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
+ return parse_property_change(env, msg, (Properties *) &adapter_properties,
+ sizeof(adapter_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
+ return parse_property_change(env, msg, (Properties *) &remote_device_properties,
+ sizeof(remote_device_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
+ return parse_properties(env, iter, (Properties *) &adapter_properties,
+ sizeof(adapter_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
+ return parse_properties(env, iter, (Properties *) &remote_device_properties,
+ sizeof(remote_device_properties) / sizeof(Properties));
+}
+
+int get_bdaddr(const char *str, bdaddr_t *ba) {
char *d = ((char *)ba) + 5, *endp;
int i;
for(i = 0; i < 6; i++) {
*d-- = strtol(str, &endp, 16);
if (*endp != ':' && i != 5) {
memset(ba, 0, sizeof(bdaddr_t));
- return;
+ return -1;
}
str = endp + 1;
}
+ return 0;
}
void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 69092dd..ef9b66b 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -68,6 +68,7 @@
struct event_loop_native_data_t {
DBusConnection *conn;
+ const char *adapter;
/* protects the thread */
pthread_mutex_t thread_mutex;
@@ -89,6 +90,12 @@
jobject me;
};
+struct _Properties {
+ char name[32];
+ int type;
+};
+typedef struct _Properties Properties;
+
dbus_bool_t dbus_func_args_async(JNIEnv *env,
DBusConnection *conn,
int timeout_ms,
@@ -142,9 +149,19 @@
jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply);
jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply);
jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply);
+jobjectArray dbus_returns_array_of_object_path(JNIEnv *env, DBusMessage *reply);
jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply);
-void get_bdaddr(const char *str, bdaddr_t *ba);
+jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
+ const int max_num_properties);
+jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
+ Properties *properties, int max_num_properties);
+jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter);
+jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter);
+jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg);
+jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg);
+void append_variant(DBusMessageIter *iter, int type, void *val);
+int get_bdaddr(const char *str, bdaddr_t *ba);
void get_bdaddr_as_string(const bdaddr_t *ba, char *str);
bool debug_no_encrypt();
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index f19fbbf..91449bc 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -229,7 +229,7 @@
{
int32_t err;
CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window);
+LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window);
field_slot_t field;
err = window->read_field_slot(row, column, &field);
@@ -241,6 +241,54 @@
return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL;
}
+static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL;
+}
+
+static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_INTEGER;
+}
+
+static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_FLOAT;
+}
+
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
{
int32_t err;
@@ -326,11 +374,11 @@
jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot");
return NULL;
}
-
+
jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField);
if (buffer == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null");
- return NULL;
+ return NULL;
}
jchar* dst = env->GetCharArrayElements(buffer, NULL);
uint8_t type = field.type;
@@ -338,7 +386,7 @@
jcharArray newArray = NULL;
if (type == FIELD_TYPE_STRING) {
uint32_t size = field.data.buffer.size;
- if (size > 0) {
+ if (size > 0) {
#if WINDOW_STORAGE_UTF8
// Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
@@ -346,7 +394,7 @@
if (strSize > bufferSize || dst == NULL) {
newArray = env->NewCharArray(strSize);
env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string());
- } else {
+ } else {
memcpy(dst, (jchar const *)utf16.string(), strSize * 2);
}
sizeCopied = strSize;
@@ -359,7 +407,7 @@
memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
}
#endif
- }
+ }
} else if (type == FIELD_TYPE_INTEGER) {
int64_t value;
if (window->getLong(row, column, &value)) {
@@ -628,6 +676,9 @@
{"putDouble_native", "(DII)Z", (void *)putDouble_native},
{"freeLastRow_native", "()V", (void *)freeLastRow},
{"putNull_native", "(II)Z", (void *)putNull_native},
+ {"isString_native", "(II)Z", (void *)isString_native},
+ {"isFloat_native", "(II)Z", (void *)isFloat_native},
+ {"isInteger_native", "(II)Z", (void *)isInteger_native},
};
int register_android_database_CursorWindow(JNIEnv * env)
@@ -646,7 +697,7 @@
LOGE("Error locating fields");
return -1;
}
-
+
clazz = env->FindClass("android/database/CharArrayBuffer");
if (clazz == NULL) {
LOGE("Can't find android/database/CharArrayBuffer");
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 66858f9..020aff4a 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -28,7 +28,10 @@
#include <sqlite3.h>
#include <sqlite3_android.h>
#include <string.h>
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <ctype.h>
#include <stdio.h>
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9053468..8a312d9 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -25,7 +25,7 @@
#include <ui/Surface.h>
#include <ui/Camera.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
using namespace android;
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index bf0bd65..90a0487 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -32,6 +32,7 @@
static jmethodID method_reportStatus;
static jmethodID method_reportSvStatus;
static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
static jmethodID method_xtraDownloadRequest;
static const GpsInterface* sGpsInterface = NULL;
@@ -44,12 +45,23 @@
static GpsSvStatus sGpsSvStatus;
static AGpsStatus sAGpsStatus;
+// buffer for NMEA data
+#define NMEA_SENTENCE_LENGTH 100
+#define NMEA_SENTENCE_COUNT 40
+struct NmeaSentence {
+ GpsUtcTime timestamp;
+ char nmea[NMEA_SENTENCE_LENGTH];
+};
+static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_LENGTH];
+static int mNmeaSentenceCount = 0;
+
// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
// and android_location_GpsLocationProvider_read_status
static GpsLocation sGpsLocationCopy;
static GpsStatus sGpsStatusCopy;
static GpsSvStatus sGpsSvStatusCopy;
static AGpsStatus sAGpsStatusCopy;
+static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
enum CallbackType {
kLocation = 1,
@@ -58,6 +70,7 @@
kAGpsStatus = 8,
kXtraDownloadRequest = 16,
kDisableRequest = 32,
+ kNmeaAvailable = 64,
};
static int sPendingCallbacks;
@@ -96,6 +109,30 @@
pthread_mutex_unlock(&sEventMutex);
}
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ if (length >= NMEA_SENTENCE_LENGTH) {
+ LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
+ length = NMEA_SENTENCE_LENGTH - 1;
+ }
+ if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
+ LOGE("NMEA data overflowed buffer\n");
+ pthread_mutex_unlock(&sEventMutex);
+ return;
+ }
+
+ sPendingCallbacks |= kNmeaAvailable;
+ sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
+ memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
+ sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
+ mNmeaSentenceCount++;
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
static void agps_status_callback(AGpsStatus* agps_status)
{
pthread_mutex_lock(&sEventMutex);
@@ -111,6 +148,7 @@
location_callback,
status_callback,
sv_status_callback,
+ nmea_callback
};
static void
@@ -135,6 +173,7 @@
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
}
@@ -200,13 +239,21 @@
// copy and clear the callback flags
int pendingCallbacks = sPendingCallbacks;
sPendingCallbacks = 0;
+ int nmeaSentenceCount = mNmeaSentenceCount;
+ mNmeaSentenceCount = 0;
// copy everything and unlock the mutex before calling into Java code to avoid the possibility
// of timeouts in the GPS engine.
- memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
- memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
- memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
- memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kLocation)
+ memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
+ if (pendingCallbacks & kStatus)
+ memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
+ if (pendingCallbacks & kSvStatus)
+ memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
+ if (pendingCallbacks & kAGpsStatus)
+ memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kNmeaAvailable)
+ memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
pthread_mutex_unlock(&sEventMutex);
if (pendingCallbacks & kLocation) {
@@ -225,6 +272,11 @@
if (pendingCallbacks & kAGpsStatus) {
env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
}
+ if (pendingCallbacks & kNmeaAvailable) {
+ for (int i = 0; i < nmeaSentenceCount; i++) {
+ env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
+ }
+ }
if (pendingCallbacks & kXtraDownloadRequest) {
env->CallVoidMethod(obj, method_xtraDownloadRequest);
}
@@ -264,6 +316,21 @@
return num_svs;
}
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
+{
+ // this should only be called from within a call to reportStatus, so we don't need to lock here
+
+ jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
+
+ int length = strlen(sNmeaBuffer[index].nmea);
+ if (length > buffer_size)
+ length = buffer_size;
+ memcpy(nmea, sNmeaBuffer[index].nmea, length);
+
+ env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
+ return length;
+}
+
static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
jlong timeReference, jint uncertainty)
{
@@ -360,6 +427,7 @@
{"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
{"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
{"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
{"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 44a9e8c..0be996d 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -28,8 +28,8 @@
#include "android_runtime/AndroidRuntime.h"
#include "utils/Log.h"
-#include "media/AudioSystem.h"
#include "media/AudioRecord.h"
+#include "media/mediarecorder.h"
// ----------------------------------------------------------------------------
@@ -62,7 +62,7 @@
#define AUDIORECORD_ERROR_BAD_VALUE -2
#define AUDIORECORD_ERROR_INVALID_OPERATION -3
#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
-#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
@@ -122,17 +122,18 @@
// ----------------------------------------------------------------------------
static int
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint source, jint sampleRateInHertz, jint nbChannels,
+ jint source, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes)
{
//LOGV(">> Entering android_media_AudioRecord_setup");
- //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
- // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
+ // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
- if ((nbChannels == 0) || (nbChannels > 2)) {
+ if (!AudioSystem::isInputChannel(channels)) {
LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
- return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ uint32_t nbChannels = AudioSystem::popCount(channels);
// compare the format against the Java constants
if ((audioFormat != javaAudioRecordFields.PCM16)
@@ -152,12 +153,7 @@
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- // convert and check input source value
- // input_source values defined in AudioRecord.h are equal to
- // JAVA MediaRecord.AudioSource values minus 1.
- AudioRecord::input_source arSource = (AudioRecord::input_source)(source - 1);
- if (arSource < AudioRecord::DEFAULT_INPUT ||
- arSource >= AudioRecord::NUM_INPUT_SOURCES) {
+ if (source >= AUDIO_SOURCE_LIST_END) {
LOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -184,10 +180,10 @@
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
- lpRecorder->set(arSource,
+ lpRecorder->set(source,
sampleRateInHertz,
format, // word length, PCM
- nbChannels,
+ channels,
frameCount,
0, // flags
recorderCallback,// callback_t
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 692610e..3d8d296 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -50,25 +50,6 @@
}
static int
-android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
-{
- LOGV("setVolume(%d)", int(volume));
-
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
-}
-
-static int
-android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
-{
- float v;
- int v_int = -1;
- if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
- v_int = AudioSystem::logToLinear(v);
- }
- return v_int;
-}
-
-static int
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
@@ -82,34 +63,6 @@
return state;
}
-static int
-android_media_AudioSystem_setRouting(JNIEnv *env, jobject clazz, jint mode, jint routes, jint mask)
-{
- return check_AudioSystem_Command(AudioSystem::setRouting(mode, uint32_t(routes), uint32_t(mask)));
-}
-
-static jint
-android_media_AudioSystem_getRouting(JNIEnv *env, jobject clazz, jint mode)
-{
- uint32_t routes = -1;
- AudioSystem::getRouting(mode, &routes);
- return jint(routes);
-}
-
-static int
-android_media_AudioSystem_setMode(JNIEnv *env, jobject clazz, jint mode)
-{
- return check_AudioSystem_Command(AudioSystem::setMode(mode));
-}
-
-static jint
-android_media_AudioSystem_getMode(JNIEnv *env, jobject clazz)
-{
- int mode = AudioSystem::MODE_INVALID;
- AudioSystem::getMode(&mode);
- return jint(mode);
-}
-
static jboolean
android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
{
@@ -118,16 +71,29 @@
return state;
}
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-static void
-android_media_AudioSystem_setParameter(JNIEnv *env, jobject thiz, jstring key, jstring value)
+static int
+android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
- const char *c_key = env->GetStringUTFChars(key, NULL);
- const char *c_value = env->GetStringUTFChars(value, NULL);
- AudioSystem::setParameter(c_key, c_value);
- env->ReleaseStringUTFChars(key, c_key);
- env->ReleaseStringUTFChars(value, c_value);
+ const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
+ String8 c_keyValuePairs8;
+ if (keyValuePairs) {
+ c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
+ env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
+ }
+ int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
+ return status;
+}
+
+static jstring
+android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
+{
+ const jchar* c_keys = env->GetStringCritical(keys, 0);
+ String8 c_keys8;
+ if (keys) {
+ c_keys8 = String8(c_keys, env->GetStringLength(keys));
+ env->ReleaseStringCritical(keys, c_keys);
+ }
+ return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
}
void android_media_AudioSystem_error_callback(status_t err)
@@ -152,19 +118,93 @@
env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
}
+static int
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ static_cast <AudioSystem::device_connection_state>(state),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return status;
+}
+
+static int
+android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return state;
+}
+
+static int
+android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
+{
+ return check_AudioSystem_Command(AudioSystem::setPhoneState(state));
+}
+
+static int
+android_media_AudioSystem_setRingerMode(JNIEnv *env, jobject thiz, jint mode, jint mask)
+{
+ return check_AudioSystem_Command(AudioSystem::setRingerMode(mode, mask));
+}
+
+static int
+android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
+{
+ return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <AudioSystem::force_use>(usage),
+ static_cast <AudioSystem::forced_config>(config)));
+}
+
+static int
+android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
+{
+ return static_cast <int>(AudioSystem::getForceUse(static_cast <AudioSystem::force_use>(usage)));
+}
+
+static int
+android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
+{
+ return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <AudioSystem::stream_type>(stream),
+ indexMin,
+ indexMax));
+}
+
+static int
+android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream, jint index)
+{
+ return check_AudioSystem_Command(AudioSystem::setStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), index));
+}
+
+static int
+android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream)
+{
+ int index;
+ if (AudioSystem::getStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), &index) != NO_ERROR) {
+ index = -1;
+ }
+ return index;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"setVolume", "(II)I", (void *)android_media_AudioSystem_setVolume},
- {"getVolume", "(I)I", (void *)android_media_AudioSystem_getVolume},
- {"setParameter", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)android_media_AudioSystem_setParameter},
+ {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
+ {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
{"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
{"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
- {"setRouting", "(III)I", (void *)android_media_AudioSystem_setRouting},
- {"getRouting", "(I)I", (void *)android_media_AudioSystem_getRouting},
- {"setMode", "(I)I", (void *)android_media_AudioSystem_setMode},
- {"getMode", "()I", (void *)android_media_AudioSystem_getMode},
{"isMusicActive", "()Z", (void *)android_media_AudioSystem_isMusicActive},
+ {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+ {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
+ {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
+ {"setRingerMode", "(II)I", (void *)android_media_AudioSystem_setRingerMode},
+ {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
+ {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
+ {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
+ {"setStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
+ {"getStreamVolumeIndex","(I)I", (void *)android_media_AudioSystem_getStreamVolumeIndex}
};
const char* const kClassPathName = "android/media/AudioSystem";
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index fd92fbe..65c0435 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -30,8 +30,8 @@
#include "media/AudioSystem.h"
#include "media/AudioTrack.h"
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
// ----------------------------------------------------------------------------
@@ -53,10 +53,11 @@
int STREAM_MUSIC; //... stream type constants
int STREAM_ALARM; //... stream type constants
int STREAM_NOTIFICATION; //... stream type constants
- int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_DTMF; //... stream type constants
int MODE_STREAM; //... memory mode
int MODE_STATIC; //... memory mode
- jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+ jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
};
static fields_t javaAudioTrackFields;
@@ -103,7 +104,7 @@
#define AUDIOTRACK_ERROR_BAD_VALUE -2
#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
@@ -164,11 +165,11 @@
// ----------------------------------------------------------------------------
static int
android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint streamType, jint sampleRateInHertz, jint nbChannels,
+ jint streamType, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes, jint memoryMode)
{
- LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
- sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
+ sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
int afSampleRate;
int afFrameCount;
@@ -181,10 +182,11 @@
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
- if ((nbChannels == 0) || (nbChannels > 2)) {
- LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
- return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Error creating AudioTrack: invalid channel mask.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ int nbChannels = AudioSystem::popCount(channels);
// check the stream type
AudioSystem::stream_type atStreamType;
@@ -202,6 +204,8 @@
atStreamType = AudioSystem::NOTIFICATION;
} else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
atStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (streamType == javaAudioTrackFields.STREAM_DTMF) {
+ atStreamType = AudioSystem::DTMF;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -231,15 +235,7 @@
int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
int format = audioFormat == javaAudioTrackFields.PCM16 ?
AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
- int frameCount;
- if (buffSizeInBytes == -1) {
- // compute the frame count based on the system's output frame count
- // and the native sample rate
- frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
- } else {
- // compute the frame count based on the specified buffer size
- frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
- }
+ int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
@@ -271,7 +267,7 @@
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
@@ -291,7 +287,7 @@
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
@@ -734,6 +730,8 @@
nativeStreamType = AudioSystem::NOTIFICATION;
} else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
nativeStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_DTMF) {
+ nativeStreamType = AudioSystem::DTMF;
} else {
nativeStreamType = AudioSystem::DEFAULT;
}
@@ -829,6 +827,7 @@
#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
+#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
@@ -950,8 +949,10 @@
JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
JAVA_AUDIOMANAGER_CLASS_NAME,
- JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME,
- &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))) {
+ JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME, &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_DTMF_NAME, &(javaAudioTrackFields.STREAM_DTMF))) {
// error log performed in android_media_getIntConstantFromClass()
return -1;
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8383deb..feb0dad 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
extern "C" {
+int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
int ifc_add_host_route(const char *ifname, uint32_t addr);
int ifc_remove_host_routes(const char *ifname);
@@ -66,6 +67,16 @@
jfieldID leaseDuration;
} dhcpInfoFieldIds;
+static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_enable(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -209,6 +220,7 @@
static JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
+ { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
{ "addHostRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute },
{ "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index ae744a8..38f3fda 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -311,18 +311,26 @@
return result;
}
-static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiHelper(const char *cmd)
{
char reply[256];
int rssi = -200;
- if (doCommand("DRIVER RSSI", reply, sizeof(reply)) != 0) {
+ if (doCommand(cmd, reply, sizeof(reply)) != 0) {
return (jint)-1;
}
+
// reply comes back in the form "<SSID> rssi XX" where XX is the
// number we're interested in. if we're associating, it returns "OK".
// beware - <SSID> can contain spaces.
if (strcmp(reply, "OK") != 0) {
+ // beware of trailing spaces
+ char* end = reply + strlen(reply);
+ while (end > reply && end[-1] == ' ') {
+ end--;
+ }
+ *end = 0;
+
char* lastSpace = strrchr(reply, ' ');
// lastSpace should be preceded by "rssi" and followed by the value
if (lastSpace && !strncmp(lastSpace - 4, "rssi", 4)) {
@@ -332,6 +340,16 @@
return (jint)rssi;
}
+static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+{
+ return android_net_wifi_getRssiHelper("DRIVER RSSI");
+}
+
+static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject clazz)
+{
+ return android_net_wifi_getRssiHelper("DRIVER RSSI-APPROX");
+}
+
static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
{
char reply[256];
@@ -527,6 +545,8 @@
{ "setBluetoothCoexistenceScanModeCommand", "(Z)Z",
(void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand },
{ "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
+ { "getRssiApproxCommand", "()I",
+ (void*) android_net_wifi_getRssiApproxCommand},
{ "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand },
{ "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
{ "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand },
diff --git a/core/jni/android_os_Exec.cpp b/core/jni/android_os_Exec.cpp
deleted file mode 100644
index ca5e695..0000000
--- a/core/jni/android_os_Exec.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "Exec"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <termios.h>
-
-namespace android
-{
-
-static jclass class_fileDescriptor;
-static jfieldID field_fileDescriptor_descriptor;
-static jmethodID method_fileDescriptor_init;
-
-
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1,
- int* pProcessId)
-{
- char *devname;
- int ptm;
- pid_t pid;
-
- ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
- if(ptm < 0){
- LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
- return -1;
- }
- fcntl(ptm, F_SETFD, FD_CLOEXEC);
-
- if(grantpt(ptm) || unlockpt(ptm) ||
- ((devname = (char*) ptsname(ptm)) == 0)){
- LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
- return -1;
- }
-
- pid = fork();
- if(pid < 0) {
- LOGE("- fork failed: %s -\n", strerror(errno));
- return -1;
- }
-
- if(pid == 0){
- int pts;
-
- setsid();
-
- pts = open(devname, O_RDWR);
- if(pts < 0) exit(-1);
-
- dup2(pts, 0);
- dup2(pts, 1);
- dup2(pts, 2);
-
- close(ptm);
-
- execl(cmd, cmd, arg0, arg1, NULL);
- exit(-1);
- } else {
- *pProcessId = (int) pid;
- return ptm;
- }
-}
-
-
-static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
- jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray)
-{
- const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
- String8 cmd_8;
- if (str) {
- cmd_8 = String8(str, env->GetStringLength(cmd));
- env->ReleaseStringCritical(cmd, str);
- }
-
- str = arg0 ? env->GetStringCritical(arg0, 0) : 0;
- const char* arg0Str = 0;
- String8 arg0_8;
- if (str) {
- arg0_8 = String8(str, env->GetStringLength(arg0));
- env->ReleaseStringCritical(arg0, str);
- arg0Str = arg0_8.string();
- }
-
- str = arg1 ? env->GetStringCritical(arg1, 0) : 0;
- const char* arg1Str = 0;
- String8 arg1_8;
- if (str) {
- arg1_8 = String8(str, env->GetStringLength(arg1));
- env->ReleaseStringCritical(arg1, str);
- arg1Str = arg1_8.string();
- }
-
- int procId;
- int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId);
-
- if (processIdArray) {
- int procIdLen = env->GetArrayLength(processIdArray);
- if (procIdLen > 0) {
- jboolean isCopy;
-
- int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
- if (pProcId) {
- *pProcId = procId;
- env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
- }
- }
- }
-
- jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
-
- if (!result) {
- LOGE("Couldn't create a FileDescriptor.");
- }
- else {
- env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
- }
-
- return result;
-}
-
-
-static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
- jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
-{
- int fd;
- struct winsize sz;
-
- fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (env->ExceptionOccurred() != NULL) {
- return;
- }
-
- sz.ws_row = row;
- sz.ws_col = col;
- sz.ws_xpixel = xpixel;
- sz.ws_ypixel = ypixel;
-
- ioctl(fd, TIOCSWINSZ, &sz);
-}
-
-static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
- jint procId) {
- int status;
- waitpid(procId, &status, 0);
- int result = 0;
- if (WIFEXITED(status)) {
- result = WEXITSTATUS(status);
- }
- return result;
-}
-
-static JNINativeMethod method_table[] = {
- { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
- (void*) android_os_Exec_createSubProcess },
- { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V",
- (void*) android_os_Exec_setPtyWindowSize},
- { "waitFor", "(I)I",
- (void*) android_os_Exec_waitFor}
-};
-
-int register_android_os_Exec(JNIEnv *env)
-{
- class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
-
- if (class_fileDescriptor == NULL) {
- LOGE("Can't find java/io/FileDescriptor");
- return -1;
- }
-
- field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
-
- if (field_fileDescriptor_descriptor == NULL) {
- LOGE("Can't find FileDescriptor.descriptor");
- return -1;
- }
-
- method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V");
- if (method_fileDescriptor_init == NULL) {
- LOGE("Can't find FileDescriptor.init");
- return -1;
- }
-
- return AndroidRuntime::registerNativeMethods(
- env, "android/os/Exec",
- method_table, NELEM(method_table));
-}
-
-};
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index 8643393..1ae3ec7 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -118,7 +118,7 @@
}
}
-static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject clazz,
+static jint android_os_MemoryFile_get_mapped_size(JNIEnv* env, jobject clazz,
jobject fileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
// Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region.
@@ -129,13 +129,13 @@
if (errno == ENOTTY) {
// ENOTTY means that the ioctl does not apply to this object,
// i.e., it is not an ashmem region.
- return JNI_FALSE;
+ return (jint) -1;
}
// Some other error, throw exception
jniThrowIOException(env, errno);
- return JNI_FALSE;
+ return (jint) -1;
}
- return JNI_TRUE;
+ return (jint) result;
}
static const JNINativeMethod methods[] = {
@@ -146,8 +146,8 @@
{"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read},
{"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write},
{"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
- {"native_is_ashmem_region", "(Ljava/io/FileDescriptor;)Z",
- (void*)android_os_MemoryFile_is_ashmem_region}
+ {"native_get_mapped_size", "(Ljava/io/FileDescriptor;)I",
+ (void*)android_os_MemoryFile_get_mapped_size}
};
static const char* const kClassPathName = "android/os/MemoryFile";
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index ca4fa11..406884b 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -36,9 +36,9 @@
"key must not be null.");
goto error;
}
-
+
key = env->GetStringUTFChars(keyJ, NULL);
-
+
len = property_get(key, buf, "");
if ((len <= 0) && (defJ != NULL)) {
rvJ = defJ;
@@ -47,9 +47,9 @@
} else {
rvJ = env->NewStringUTF("");
}
-
+
env->ReleaseStringUTFChars(keyJ, key);
-
+
error:
return rvJ;
}
@@ -60,6 +60,101 @@
return SystemProperties_getSS(env, clazz, keyJ, NULL);
}
+static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
+ jstring keyJ, jint defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jint result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jint temp;
+ if (sscanf(buf, "%d", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
+ jstring keyJ, jlong defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jlong result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jlong temp;
+ if (sscanf(buf, "%lld", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
+ jstring keyJ, jboolean defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jboolean result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n')
+ result = false;
+ else if (ch == '1' || ch == 'y')
+ result = true;
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
static void SystemProperties_set(JNIEnv *env, jobject clazz,
jstring keyJ, jstring valJ)
{
@@ -94,6 +189,12 @@
(void*) SystemProperties_getS },
{ "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getSS },
+ { "native_get_int", "(Ljava/lang/String;I)I",
+ (void*) SystemProperties_get_int },
+ { "native_get_long", "(Ljava/lang/String;J)J",
+ (void*) SystemProperties_get_long },
+ { "native_get_boolean", "(Ljava/lang/String;Z)Z",
+ (void*) SystemProperties_get_boolean },
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SystemProperties_set },
};
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 91a8e8e..14da1fd 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -37,12 +37,7 @@
namespace android {
#ifdef HAVE_BLUETOOTH
-static jmethodID method_onHeadsetCreated;
-static jmethodID method_onHeadsetRemoved;
-static jmethodID method_onSinkConnected;
-static jmethodID method_onSinkDisconnected;
-static jmethodID method_onSinkPlaying;
-static jmethodID method_onSinkStopped;
+static jmethodID method_onSinkPropertyChanged;
typedef struct {
JavaVM *vm;
@@ -53,11 +48,11 @@
static native_data_t *nat = NULL; // global native data
-#endif
-
-#ifdef HAVE_BLUETOOTH
-static void onConnectSinkResult(DBusMessage *msg, void *user, void *nat);
-static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *nat);
+static Properties sink_properties[] = {
+ {"State", DBUS_TYPE_STRING},
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ {"Playing", DBUS_TYPE_BOOLEAN},
+ };
#endif
/* Returns true on success (even if adapter is present but disabled).
@@ -100,91 +95,58 @@
}
#endif
}
-static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "ListHeadsets",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-static jstring createHeadsetNative(JNIEnv *env, jobject object,
- jstring address) {
+static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object,
+ jstring path) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s\n", c_address);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "CreateHeadset",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
-static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "RemoveHeadset",
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID);
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "GetProperties",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_string(env, reply) : NULL;
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return NULL;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ DBusMessageIter iter;
+ if (dbus_message_iter_init(reply, &iter))
+ return parse_properties(env, &iter, (Properties *)&sink_properties,
+ sizeof(sink_properties) / sizeof(Properties));
}
#endif
return NULL;
}
-static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, c_path,
- "org.bluez.audio.Device", "GetAddress",
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- size_t path_sz = env->GetStringUTFLength(path) + 1;
- char *c_path_copy = (char *)malloc(path_sz); // callback data
- strncpy(c_path_copy, c_path, path_sz);
+ DBusError err;
+ dbus_error_init(&err);
- bool ret =
- dbus_func_args_async(env, nat->conn, -1,
- onConnectSinkResult, (void *)c_path_copy, nat,
- c_path,
- "org.bluez.audio.Sink", "Connect",
- DBUS_TYPE_INVALID);
-
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "Connect",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
+
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return JNI_FALSE;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return JNI_FALSE;
}
return JNI_TRUE;
@@ -199,19 +161,20 @@
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- size_t path_sz = env->GetStringUTFLength(path) + 1;
- char *c_path_copy = (char *)malloc(path_sz); // callback data
- strncpy(c_path_copy, c_path, path_sz);
+ DBusError err;
+ dbus_error_init(&err);
- bool ret =
- dbus_func_args_async(env, nat->conn, -1,
- onDisconnectSinkResult, (void *)c_path_copy, nat,
- c_path,
- "org.bluez.audio.Sink", "Disconnect",
- DBUS_TYPE_INVALID);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "Disconnect",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
+
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return JNI_FALSE;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return JNI_FALSE;
}
return JNI_TRUE;
@@ -220,93 +183,7 @@
return JNI_FALSE;
}
-static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, c_path,
- "org.bluez.audio.Sink", "IsConnected",
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-#ifdef HAVE_BLUETOOTH
-static void onConnectSinkResult(DBusMessage *msg, void *user, void *natData) {
- LOGV(__FUNCTION__);
-
- char *c_path = (char *)user;
- DBusError err;
- JNIEnv *env;
-
- if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) {
- LOGE("%s: error finding Env for our VM\n", __FUNCTION__);
- return;
- }
-
- dbus_error_init(&err);
-
- LOGV("... path = %s", c_path);
- if (dbus_set_error_from_message(&err, msg)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- dbus_error_free(&err);
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- if (env->ExceptionCheck()) {
- LOGE("VM Exception occurred in native function %s (%s:%d)",
- __FUNCTION__, __FILE__, __LINE__);
- }
- } // else Java callback is triggered by signal in a2dp_event_filter
-
- free(c_path);
-}
-
-static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *natData) {
- LOGV(__FUNCTION__);
-
- char *c_path = (char *)user;
- DBusError err;
- JNIEnv *env;
-
- if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) {
- LOGE("%s: error finding Env for our VM\n", __FUNCTION__);
- return;
- }
-
- dbus_error_init(&err);
-
- LOGV("... path = %s", c_path);
- if (dbus_set_error_from_message(&err, msg)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- if (strcmp(err.name, "org.bluez.Error.NotConnected") == 0) {
- // we were already disconnected, so report disconnect
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- } else {
- // Assume it is still connected
- env->CallVoidMethod(nat->me,
- method_onSinkConnected,
- env->NewStringUTF(c_path));
- }
- dbus_error_free(&err);
- if (env->ExceptionCheck()) {
- LOGE("VM Exception occurred in native function %s (%s:%d)",
- __FUNCTION__, __FILE__, __LINE__);
- }
- } // else Java callback is triggered by signal in a2dp_event_filter
-
- free(c_path);
-}
-
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
DBusError err;
@@ -324,71 +201,23 @@
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (dbus_message_is_signal(msg,
- "org.bluez.audio.Manager",
- "HeadsetCreated")) {
- char *c_path;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID)) {
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onHeadsetCreated,
- env->NewStringUTF(c_path));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Manager",
- "HeadsetRemoved")) {
- char *c_path;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID)) {
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onHeadsetRemoved,
- env->NewStringUTF(c_path));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Connected")) {
+ if (dbus_message_is_signal(msg, "org.bluez.AudioSink",
+ "PropertyChanged")) {
+ jobjectArray str_array =
+ parse_property_change(env, msg, (Properties *)&sink_properties,
+ sizeof(sink_properties) / sizeof(Properties));
const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
env->CallVoidMethod(nat->me,
- method_onSinkConnected,
- env->NewStringUTF(c_path));
+ 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;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Disconnected")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Playing")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkPlaying,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Stopped")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkStopped,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- }
-
- if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) {
+ return result;
+ } else {
LOGV("... ignored");
}
if (env->ExceptionCheck()) {
@@ -407,14 +236,11 @@
{"initNative", "()Z", (void *)initNative},
{"cleanupNative", "()V", (void *)cleanupNative},
- /* Bluez audio 3.36 API */
- {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative},
- {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative},
- {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative},
- {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative},
- {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative},
- {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative},
- {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative},
+ /* Bluez audio 4.40 API */
+ {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
+ {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
+ {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getSinkPropertiesNative},
};
int register_android_server_BluetoothA2dpService(JNIEnv *env) {
@@ -425,12 +251,8 @@
}
#ifdef HAVE_BLUETOOTH
- method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V");
- method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V");
- method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V");
- method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V");
- method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V");
- method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V");
+ method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
#endif
return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp
deleted file mode 100644
index 58ae4f6..0000000
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ /dev/null
@@ -1,1035 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter"
-#define LOG_TAG "BluetoothDeviceService.cpp"
-
-#include "android_bluetooth_common.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <dbus/dbus.h>
-#include <bluedroid/bluetooth.h>
-#endif
-
-#include <cutils/properties.h>
-
-namespace android {
-
-#define BLUETOOTH_CLASS_ERROR 0xFF000000
-
-#ifdef HAVE_BLUETOOTH
-// We initialize these variables when we load class
-// android.server.BluetoothDeviceService
-static jfieldID field_mNativeData;
-static jfieldID field_mEventLoop;
-
-typedef struct {
- JNIEnv *env;
- DBusConnection *conn;
- const char *adapter; // dbus object name of the local adapter
-} native_data_t;
-
-extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
- jobject);
-void onCreateBondingResult(DBusMessage *msg, void *user, void *nat);
-void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat);
-
-/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
- * Perform quick sanity check, if there are any problems return NULL
- */
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
- native_data_t *nat =
- (native_data_t *)(env->GetIntField(object, field_mNativeData));
- if (nat == NULL || nat->conn == NULL) {
- LOGE("Uninitialized native data\n");
- return NULL;
- }
- return nat;
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mEventLoop = get_field(env, clazz, "mEventLoop",
- "Landroid/server/BluetoothEventLoop;");
-#endif
-}
-
-/* Returns true on success (even if adapter is present but disabled).
- * Return false if dbus is down, or another serious error (out of memory)
-*/
-static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
- if (NULL == nat) {
- LOGE("%s: out of memory!", __FUNCTION__);
- return false;
- }
- nat->env = env;
-
- env->SetIntField(object, field_mNativeData, (jint)nat);
- DBusError err;
- dbus_error_init(&err);
- dbus_threads_init_default();
- nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (dbus_error_is_set(&err)) {
- LOGE("Could not get onto the system bus: %s", err.message);
- dbus_error_free(&err);
- return false;
- }
- dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
-
- nat->adapter = BLUEZ_ADAPTER_OBJECT_NAME;
-#endif /*HAVE_BLUETOOTH*/
- return true;
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat =
- (native_data_t *)env->GetIntField(object, field_mNativeData);
- if (nat) {
- free(nat);
- nat = NULL;
- }
-#endif
-}
-
-static jstring getNameNative(JNIEnv *env, jobject object){
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetName",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- return (env->NewStringUTF(nat->adapter));
- }
-#endif
- return NULL;
-}
-
-
-static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "DiscoverDevices");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.message, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s, treating as startDiscoveryNative success\n",
- __FUNCTION__, err.message);
- ret = JNI_TRUE;
- goto done;
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static void cancelDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jstring ret;
- native_data_t *nat;
-
- dbus_error_init(&err);
-
- nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "CancelDiscovery");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized") == 0) {
- // hcid sends this if there is no active discovery to cancel
- LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
- dbus_error_free(&err);
- } else {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- }
- }
-
-done:
- if (msg) dbus_message_unref(msg);
- if (reply) dbus_message_unref(reply);
-#endif
-}
-
-static jboolean startPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "StartPeriodicDiscovery");
- if (msg == NULL) {
- LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s (%s), treating as "
- "startPeriodicDiscoveryNative success\n",
- __FUNCTION__, err.name, err.message);
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static jboolean stopPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "StopPeriodicDiscovery");
- if (msg == NULL) {
- LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s (%s), treating as "
- "stopPeriodicDiscoveryNative success\n",
- __FUNCTION__, err.name, err.message);
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static jboolean isPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsPeriodicDiscovery",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean setDiscoverableTimeoutNative(JNIEnv *env, jobject object, jint timeout_s) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
-
- if (timeout_s < 0) {
- return JNI_FALSE;
- }
-
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetDiscoverableTimeout",
- DBUS_TYPE_UINT32, &timeout_s,
- DBUS_TYPE_INVALID);
- if (reply != NULL) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint getDiscoverableTimeoutNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetDiscoverableTimeout",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static jboolean isConnectedNative(JNIEnv *env, jobject object, jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsConnected",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- // Set a timeout of 5 seconds. Specifying the default timeout is
- // not long enough, as a remote-device disconnect results in
- // signal RemoteDisconnectRequested being sent, followed by a
- // delay of 2 seconds, after which the actual disconnect takes
- // place.
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, 60000, nat->adapter,
- DBUS_CLASS_NAME, "DisconnectRemoteDevice",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) dbus_message_unref(reply);
- }
-#endif
-}
-
-static jstring getModeNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetMode",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_mode = env->GetStringUTFChars(mode, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetMode",
- DBUS_TYPE_STRING, &c_mode,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(mode, c_mode);
- if (reply) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- return JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean createBondingNative(JNIEnv *env, jobject object,
- jstring address, jint timeout_ms) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
- struct event_loop_native_data_t *eventLoopNat =
- get_EventLoop_native_data(env, eventLoop);
-
- if (nat && eventLoopNat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
- strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
- bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
- onCreateBondingResult, // callback
- context_address,
- eventLoopNat,
- nat->adapter,
- DBUS_CLASS_NAME, "CreateBonding",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return ret ? JNI_TRUE : JNI_FALSE;
-
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object,
- jstring address) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, -1, nat->adapter,
- DBUS_CLASS_NAME, "CancelBondingProcess",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- dbus_message_unref(reply);
- }
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean removeBondingNative(JNIEnv *env, jobject object, jstring address) {
- LOGV(__FUNCTION__);
- jboolean result = JNI_FALSE;
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, "RemoveBonding",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- if (dbus_error_is_set(&err)) {
- if (dbus_error_has_name(&err,
- BLUEZ_DBUS_BASE_IFC ".Error.DoesNotExist")) {
- LOGW("%s: Warning: %s (%s)", __FUNCTION__, err.message,
- c_address);
- result = JNI_TRUE;
- } else {
- LOGE("%s: D-Bus error %s (%s)", __FUNCTION__, err.name,
- err.message);
- }
- } else {
- result = JNI_TRUE;
- }
-
- env->ReleaseStringUTFChars(address, c_address);
- dbus_error_free(&err);
- if (reply) dbus_message_unref(reply);
- }
-#endif
- return result;
-}
-
-static jobjectArray listBondingsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListBondings",
- DBUS_TYPE_INVALID);
- // return String[]
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listConnectionsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListConnections",
- DBUS_TYPE_INVALID);
- // return String[]
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listRemoteDevicesNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListRemoteDevices",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jstring common_Get(JNIEnv *env, jobject object, const char *func) {
- LOGV("%s:%s", __FUNCTION__, func);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, func,
- DBUS_TYPE_INVALID);
- if (reply) {
- return dbus_returns_string(env, reply);
- } else {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return NULL;
- }
- }
-#endif
- return NULL;
-}
-
-static jstring getAddressNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetAddress");
-}
-
-static jstring getVersionNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetVersion");
-}
-
-static jstring getRevisionNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetRevision");
-}
-
-static jstring getManufacturerNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetManufacturer");
-}
-
-static jstring getCompanyNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetCompany");
-}
-
-static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, obj);
- if (nat) {
- const char *c_name = env->GetStringUTFChars(name, NULL);
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetName",
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(name, c_name);
- if (reply) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- }
-#endif
- return JNI_FALSE;
-}
-
-static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
- jstring address) {
- LOGV("%s:%s", __FUNCTION__, func);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- DBusError err;
- dbus_error_init(&err);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, func,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- return dbus_returns_string(env, reply);
- } else if (!strcmp(func, "GetRemoteName") &&
- dbus_error_has_name(&err, "org.bluez.Error.RequestDeferred")) {
- // This error occurs if we request name during device discovery,
- // its fine
- LOGV("... %s: %s", func, err.message);
- dbus_error_free(&err);
- return NULL;
- } else {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return NULL;
- }
- }
-#endif
- return NULL;
-}
-
-static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteVersion", address);
-}
-
-static jstring getRemoteRevisionNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteRevision", address);
-}
-
-static jstring getRemoteManufacturerNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteManufacturer", address);
-}
-
-static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteCompany", address);
-}
-
-static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteName", address);
-}
-
-static jstring lastSeenNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "LastSeen", address);
-}
-
-static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "LastUsed", address);
-}
-
-static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) {
- jint result = BLUETOOTH_CLASS_ERROR;
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteClass",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply)
- {
- DBusError err;
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_UINT32, &result,
- DBUS_TYPE_INVALID)) {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- }
- dbus_message_unref(reply);
- }
- }
-#endif
- return result;
-}
-
-static jbyteArray getRemoteFeaturesNative(JNIEnv *env, jobject object,
- jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteFeatures",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- /* array of DBUS_TYPE_BYTE_AS_STRING */
- return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object,
- jstring address, jstring match) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- jintArray intArray = NULL;
- const char *c_address = env->GetStringUTFChars(address, NULL);
- const char *c_match = env->GetStringUTFChars(match, NULL);
-
- LOGV("... address = %s match = %s", c_address, c_match);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceHandles",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_match,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- env->ReleaseStringUTFChars(match, c_match);
- if (reply)
- {
- DBusError err;
- jint *list;
- int i, len;
-
- dbus_error_init(&err);
- if (dbus_message_get_args (reply, &err,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
- &list, &len,
- DBUS_TYPE_INVALID)) {
- if (len) {
- intArray = env->NewIntArray(len);
- if (intArray)
- env->SetIntArrayRegion(intArray, 0, len, list);
- }
- } else {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- }
-
- dbus_message_unref(reply);
- }
- return intArray;
- }
-#endif
- return NULL;
-}
-
-static jbyteArray getRemoteServiceRecordNative(JNIEnv *env, jobject object,
- jstring address, jint handle) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceRecord",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object,
- jstring address, jshort uuid16) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
- struct event_loop_native_data_t *eventLoopNat =
- get_EventLoop_native_data(env, eventLoop);
- if (nat && eventLoopNat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
- strlcpy(context_address, c_address, BTADDR_SIZE);
-
- LOGV("... address = %s", c_address);
- LOGV("... uuid16 = %#X", uuid16);
-
- bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms
- onGetRemoteServiceChannelResult, context_address,
- eventLoopNat,
- nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceChannel",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT16, &uuid16,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return ret ? JNI_TRUE : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint enableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_enable();
-#endif
- return -1;
-}
-
-static jint disableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_disable();
-#endif
- return -1;
-}
-
-static jint isEnabledNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_is_enabled();
-#endif
- return -1;
-}
-
-static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
- jstring pin, int nativeData) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *msg = (DBusMessage *)nativeData;
- DBusMessage *reply = dbus_message_new_method_return(msg);
- if (!reply) {
- LOGE("%s: Cannot create message reply to return PIN code to "
- "D-Bus\n", __FUNCTION__);
- dbus_message_unref(msg);
- return JNI_FALSE;
- }
-
- const char *c_pin = env->GetStringUTFChars(pin, NULL);
-
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(msg);
- dbus_message_unref(reply);
- env->ReleaseStringUTFChars(pin, c_pin);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address,
- int nativeData) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *msg = (DBusMessage *)nativeData;
- DBusMessage *reply = dbus_message_new_error(msg,
- "org.bluez.Error.Canceled", "PIN Entry was canceled");
- if (!reply) {
- LOGE("%s: Cannot create message reply to return PIN cancel to "
- "D-BUS\n", __FUNCTION__);
- dbus_message_unref(msg);
- return JNI_FALSE;
- }
-
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(msg);
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
- {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
-
- {"isEnabledNative", "()I", (void *)isEnabledNative},
- {"enableNative", "()I", (void *)enableNative},
- {"disableNative", "()I", (void *)disableNative},
-
- {"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative},
- {"getNameNative", "()Ljava/lang/String;", (void*)getNameNative},
- {"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative},
- {"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative},
- {"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative},
- {"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative},
- {"getCompanyNative", "()Ljava/lang/String;", (void *)getCompanyNative},
-
- {"getModeNative", "()Ljava/lang/String;", (void *)getModeNative},
- {"setModeNative", "(Ljava/lang/String;)Z", (void *)setModeNative},
-
- {"getDiscoverableTimeoutNative", "()I", (void *)getDiscoverableTimeoutNative},
- {"setDiscoverableTimeoutNative", "(I)Z", (void *)setDiscoverableTimeoutNative},
-
- {"startDiscoveryNative", "(Z)Z", (void*)startDiscoveryNative},
- {"cancelDiscoveryNative", "()Z", (void *)cancelDiscoveryNative},
- {"startPeriodicDiscoveryNative", "()Z", (void *)startPeriodicDiscoveryNative},
- {"stopPeriodicDiscoveryNative", "()Z", (void *)stopPeriodicDiscoveryNative},
- {"isPeriodicDiscoveryNative", "()Z", (void *)isPeriodicDiscoveryNative},
- {"listRemoteDevicesNative", "()[Ljava/lang/String;", (void *)listRemoteDevicesNative},
-
- {"listConnectionsNative", "()[Ljava/lang/String;", (void *)listConnectionsNative},
- {"isConnectedNative", "(Ljava/lang/String;)Z", (void *)isConnectedNative},
- {"disconnectRemoteDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectRemoteDeviceNative},
-
- {"createBondingNative", "(Ljava/lang/String;I)Z", (void *)createBondingNative},
- {"cancelBondingProcessNative", "(Ljava/lang/String;)Z", (void *)cancelBondingProcessNative},
- {"listBondingsNative", "()[Ljava/lang/String;", (void *)listBondingsNative},
- {"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative},
-
- {"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative},
- {"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative},
- {"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative},
- {"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative},
- {"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative},
- {"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative},
- {"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative},
- {"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative},
- {"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative},
- {"lastUsedNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastUsedNative},
- {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
- {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative},
-};
-
-int register_android_server_BluetoothDeviceService(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index ad24136..527bf07 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -39,30 +39,21 @@
#ifdef HAVE_BLUETOOTH
static jfieldID field_mNativeData;
-static jmethodID method_onModeChanged;
-static jmethodID method_onNameChanged;
-static jmethodID method_onDiscoveryStarted;
-static jmethodID method_onDiscoveryCompleted;
-static jmethodID method_onRemoteDeviceFound;
-static jmethodID method_onRemoteDeviceDisappeared;
-static jmethodID method_onRemoteClassUpdated;
-static jmethodID method_onRemoteNameUpdated;
-static jmethodID method_onRemoteNameFailed;
-static jmethodID method_onRemoteDeviceConnected;
-static jmethodID method_onRemoteDeviceDisconnectRequested;
-static jmethodID method_onRemoteDeviceDisconnected;
-static jmethodID method_onBondingCreated;
-static jmethodID method_onBondingRemoved;
+static jmethodID method_onPropertyChanged;
+static jmethodID method_onDevicePropertyChanged;
+static jmethodID method_onDeviceFound;
+static jmethodID method_onDeviceDisappeared;
+static jmethodID method_onDeviceCreated;
+static jmethodID method_onDeviceRemoved;
-static jmethodID method_onCreateBondingResult;
-static jmethodID method_onGetRemoteServiceChannelResult;
+static jmethodID method_onCreatePairedDeviceResult;
+static jmethodID method_onGetDeviceServiceChannelResult;
-static jmethodID method_onPasskeyAgentRequest;
-static jmethodID method_onPasskeyAgentCancel;
-static jmethodID method_onAuthAgentAuthorize;
-static jmethodID method_onAuthAgentCancel;
-
-static jmethodID method_onRestartRequired;
+static jmethodID method_onRequestPinCode;
+static jmethodID method_onRequestPasskey;
+static jmethodID method_onRequestConfirmation;
+static jmethodID method_onAgentAuthorize;
+static jmethodID method_onAgentCancel;
typedef event_loop_native_data_t native_data_t;
@@ -80,30 +71,30 @@
LOGV(__FUNCTION__);
#ifdef HAVE_BLUETOOTH
- method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V");
- method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V");
- method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V");
- method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V");
- method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V");
- method_onRemoteDeviceDisappeared = env->GetMethodID(clazz, "onRemoteDeviceDisappeared", "(Ljava/lang/String;)V");
- method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V");
- method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V");
- method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V");
- method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V");
- method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V");
- method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V");
- method_onBondingCreated = env->GetMethodID(clazz, "onBondingCreated", "(Ljava/lang/String;)V");
- method_onBondingRemoved = env->GetMethodID(clazz, "onBondingRemoved", "(Ljava/lang/String;)V");
+ method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
+ "([Ljava/lang/String;)V");
+ method_onDevicePropertyChanged = env->GetMethodID(clazz,
+ "onDevicePropertyChanged",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
+ method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
+ method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
+ "(Ljava/lang/String;)V");
+ method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
+ method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
- method_onCreateBondingResult = env->GetMethodID(clazz, "onCreateBondingResult", "(Ljava/lang/String;I)V");
+ method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
+ "(Ljava/lang/String;I)V");
- method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V");
- method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V");
- method_onAuthAgentAuthorize = env->GetMethodID(clazz, "onAuthAgentAuthorize", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
- method_onAuthAgentCancel = env->GetMethodID(clazz, "onAuthAgentCancel", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
- method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V");
-
- method_onRestartRequired = env->GetMethodID(clazz, "onRestartRequired", "()V");
+ method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
+ "(Ljava/lang/String;Ljava/lang/String;)Z");
+ method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
+ method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
+ "(Ljava/lang/String;I)V");
+ method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
+ "(Ljava/lang/String;I)V");
+ method_onRequestConfirmation = env->GetMethodID(clazz, "onRequestConfirmation",
+ "(Ljava/lang/String;II)V");
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
#endif
@@ -154,9 +145,11 @@
#ifdef HAVE_BLUETOOTH
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
void *data);
-static DBusHandlerResult agent_event_filter(DBusConnection *conn,
- DBusMessage *msg,
- void *data);
+DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+static int register_agent(native_data_t *nat,
+ const char *agent_path, const char *capabilities);
static const DBusObjectPathVTable agent_vtable = {
NULL, agent_event_filter, NULL, NULL, NULL, NULL
@@ -178,11 +171,12 @@
static jboolean setUpEventLoop(native_data_t *nat) {
LOGV(__FUNCTION__);
- dbus_threads_init_default();
- DBusError err;
- dbus_error_init(&err);
if (nat != NULL && nat->conn != NULL) {
+ dbus_threads_init_default();
+ DBusError err;
+ dbus_error_init(&err);
+
// Add a filter for all incoming messages
if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
return JNI_FALSE;
@@ -204,108 +198,143 @@
return JNI_FALSE;
}
dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Manager'",
+ "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
}
dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Device'",
- &err);
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
- dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Sink'",
+ "type='signal',interface='org.bluez.AudioSink'",
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
}
- // Add an object handler for passkey agent method calls
- const char *path = "/android/bluetooth/Agent";
- if (!dbus_connection_register_object_path(nat->conn, path,
- &agent_vtable, nat)) {
- LOGE("%s: Can't register object path %s for agent!",
- __FUNCTION__, path);
+ const char *agent_path = "/android/bluetooth/agent";
+ const char *capabilities = "DisplayYesNo";
+ if (register_agent(nat, agent_path, capabilities) < 0) {
+ dbus_connection_unregister_object_path (nat->conn, agent_path);
return JNI_FALSE;
}
-
- // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
- // trying for 10 seconds.
- int attempt;
- for (attempt = 0; attempt < 1000; attempt++) {
- DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err,
- BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "RegisterDefaultPasskeyAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) {
- // Success
- dbus_message_unref(reply);
- LOGV("Registered agent on attempt %d of 1000\n", attempt);
- break;
- } else if (dbus_error_has_name(&err,
- "org.freedesktop.DBus.Error.ServiceUnknown")) {
- // hcid is still down, retry
- dbus_error_free(&err);
- usleep(10000); // 10 ms
- } else {
- // Some other error we weren't expecting
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
- }
- if (attempt == 1000) {
- LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
- "is hcid running?");
- return JNI_FALSE;
- }
-
- // Now register the Auth agent
- DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err,
- BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "RegisterDefaultAuthorizationAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (!reply) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
-
- dbus_message_unref(reply);
return JNI_TRUE;
}
-
return JNI_FALSE;
}
+
+const char * get_adapter_path(DBusConnection *conn) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ const char *device_path = NULL;
+ msg = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager", "DefaultAdapter");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for GetProperties!",
+ __FUNCTION__);
+ return NULL;
+ }
+ dbus_message_append_args(msg, DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ return NULL;
+ }
+ if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
+ &device_path, DBUS_TYPE_INVALID)
+ || !device_path){
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ return NULL;
+ }
+ return device_path;
+}
+
+static int register_agent(native_data_t *nat,
+ const char * agent_path, const char * capabilities)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+
+ if (!dbus_connection_register_object_path(nat->conn, agent_path,
+ &agent_vtable, nat)) {
+ LOGE("%s: Can't register object path %s for agent!",
+ __FUNCTION__, agent_path);
+ return -1;
+ }
+
+ nat->adapter = get_adapter_path(nat->conn);
+ msg = dbus_message_new_method_call("org.bluez", nat->adapter,
+ "org.bluez.Adapter", "RegisterAgent");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for agent!",
+ __FUNCTION__);
+ return -1;
+ }
+ dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ LOGE("%s: Can't register agent!", __FUNCTION__);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ return -1;
+ }
+
+ dbus_message_unref(reply);
+ dbus_connection_flush(nat->conn);
+
+ return 0;
+}
+
static void tearDownEventLoop(native_data_t *nat) {
LOGV(__FUNCTION__);
if (nat != NULL && nat->conn != NULL) {
+ DBusMessage *msg, *reply;
DBusError err;
dbus_error_init(&err);
+ const char * agent_path = "/android/bluetooth/agent";
- const char *path = "/android/bluetooth/Agent";
- DBusMessage *reply =
- dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) dbus_message_unref(reply);
+ msg = dbus_message_new_method_call("org.bluez",
+ nat->adapter,
+ "org.bluez.Adapter",
+ "UnregisterAgent");
+ if (msg != NULL) {
+ dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_INVALID);
+ reply = dbus_connection_send_with_reply_and_block(nat->conn,
+ msg, -1, &err);
- reply =
- dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "UnregisterDefaultAuthorizationAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) dbus_message_unref(reply);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ dbus_error_free(&err);
+ }
+ } else {
+ dbus_message_unref(reply);
+ }
+ dbus_message_unref(msg);
+ } else {
+ LOGE("%s: Can't create new method call!", __FUNCTION__);
+ }
- dbus_connection_unregister_object_path(nat->conn, path);
+ dbus_connection_flush(nat->conn);
+ dbus_connection_unregister_object_path(nat->conn, agent_path);
dbus_bus_remove_match(nat->conn,
"type='signal',interface='org.bluez.audio.Sink'",
@@ -660,267 +689,132 @@
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
- dbus_message_get_interface(msg), dbus_message_get_member(msg),
- dbus_message_get_path(msg));
+ // STOPSHIP: Change to LOGV
+ LOGE("%s: Received signal %s:%s from %s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg));
if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
- "RemoteDeviceFound")) {
+ "DeviceFound")) {
char *c_address;
- int n_class;
- short n_rssi;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &n_class,
- DBUS_TYPE_INT16, &n_rssi,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s class = %#X rssi = %hd", c_address, n_class,
- n_rssi);
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(msg, &iter)) {
+ dbus_message_iter_get_basic(&iter, &c_address);
+ if (dbus_message_iter_next(&iter))
+ str_array =
+ parse_remote_device_properties(env, &iter);
+ }
+ if (str_array != NULL) {
env->CallVoidMethod(nat->me,
- method_onRemoteDeviceFound,
+ method_onDeviceFound,
env->NewStringUTF(c_address),
- (jint)n_class,
- (jshort)n_rssi);
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ str_array);
+ env->DeleteLocalRef(str_array);
+ } else
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "DiscoveryStarted")) {
- LOGI("DiscoveryStarted signal received");
- env->CallVoidMethod(nat->me, method_onDiscoveryStarted);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "DiscoveryCompleted")) {
- LOGI("DiscoveryCompleted signal received");
- env->CallVoidMethod(nat->me, method_onDiscoveryCompleted);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisappeared")) {
+ "org.bluez.Adapter",
+ "DeviceDisappeared")) {
char *c_address;
if (dbus_message_get_args(msg, &err,
DBUS_TYPE_STRING, &c_address,
DBUS_TYPE_INVALID)) {
LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me, method_onRemoteDeviceDisappeared,
+ 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;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteClassUpdated")) {
- char *c_address;
- int n_class;
+ "org.bluez.Adapter",
+ "DeviceCreated")) {
+ char *c_object_path;
if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me, method_onRemoteClassUpdated,
- env->NewStringUTF(c_address), (jint)n_class);
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteNameUpdated")) {
- char *c_address;
- char *c_name;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s, name = %s", c_address, c_name);
+ LOGV("... address = %s", c_object_path);
env->CallVoidMethod(nat->me,
- method_onRemoteNameUpdated,
- env->NewStringUTF(c_address),
- env->NewStringUTF(c_name));
+ method_onDeviceCreated,
+ env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteNameFailed")) {
- char *c_address;
+ "org.bluez.Adapter",
+ "DeviceRemoved")) {
+ char *c_object_path;
if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteNameFailed,
- env->NewStringUTF(c_address));
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... Object Path = %s", c_object_path);
+ env->CallVoidMethod(nat->me,
+ method_onDeviceRemoved,
+ env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceConnected")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceConnected,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisconnectRequested")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceDisconnectRequested,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisconnected")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceDisconnected,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "BondingCreated")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onBondingCreated,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "BondingRemoved")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onBondingRemoved,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "ModeChanged")) {
- char *c_mode;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_mode,
- DBUS_TYPE_INVALID)) {
- LOGV("... mode = %s", c_mode);
- env->CallVoidMethod(nat->me,
- method_onModeChanged,
- env->NewStringUTF(c_mode));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "NameChanged")) {
- char *c_name;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID)) {
- LOGV("... name = %s", c_name);
- env->CallVoidMethod(nat->me,
- method_onNameChanged,
- env->NewStringUTF(c_name));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.freedesktop.DBus",
- "NameOwnerChanged")) {
- char *c_name;
- char *c_old_owner;
- char *c_new_owner;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_STRING, &c_old_owner,
- DBUS_TYPE_STRING, &c_new_owner,
- DBUS_TYPE_INVALID)) {
- LOGV("... name = %s", c_name);
- LOGV("... old_owner = %s", c_old_owner);
- LOGV("... new_owner = %s", c_new_owner);
- if (!strcmp(c_name, "org.bluez") && c_new_owner[0] != '\0') {
- // New owner of org.bluez. This can only happen when hcid
- // restarts. Need to restart framework BT services to recover.
- LOGE("Looks like hcid restarted");
- env->CallVoidMethod(nat->me, method_onRestartRequired);
- }
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "PropertyChanged")) {
+ jobjectArray str_array = parse_adapter_property_change(env, msg);
+ if (str_array != NULL) {
+ /* Check if bluetoothd has (re)started, if so update the path. */
+ jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
+ const char *c_property = env->GetStringUTFChars(property, NULL);
+ if (!strncmp(c_property, "Powered", strlen("Powered"))) {
+ jstring value =
+ (jstring) env->GetObjectArrayElement(str_array, 1);
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+ if (!strncmp(c_value, "true", strlen("true")))
+ nat->adapter = get_adapter_path(nat->conn);
+ env->ReleaseStringUTFChars(value, c_value);
+ }
+ env->ReleaseStringUTFChars(property, c_property);
+
+ 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;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Device",
+ "PropertyChanged")) {
+ jobjectArray str_array = parse_remote_device_property_change(env, msg);
+ if (str_array != NULL) {
+ const char *remote_device_path = dbus_message_get_path(msg);
+ env->CallVoidMethod(nat->me,
+ 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;
+
+ }
return a2dp_event_filter(msg, env);
}
// Called by dbus during WaitForAndDispatchEventNative()
-static DBusHandlerResult agent_event_filter(DBusConnection *conn,
- DBusMessage *msg, void *data) {
+DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data) {
native_data_t *nat = (native_data_t *)data;
JNIEnv *env;
- nat->vm->GetEnv((void**)&env, nat->envVer);
if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
LOGV("%s: not interested (not a method call).", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("%s: Received method %s:%s", __FUNCTION__,
+ LOGI("%s: Received method %s:%s", __FUNCTION__,
dbus_message_get_interface(msg), dbus_message_get_member(msg));
+ if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
+
+ nat->vm->GetEnv((void**)&env, nat->envVer);
if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Request")) {
+ "org.bluez.Agent", "Cancel")) {
- const char *adapter;
- const char *address;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Request() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- LOGV("... address = %s", address);
-
- dbus_message_ref(msg); // increment refcount because we pass to java
-
- env->CallVoidMethod(nat->me, method_onPasskeyAgentRequest,
- env->NewStringUTF(address), (int)msg);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
- } else if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Cancel")) {
-
- const char *adapter;
- const char *address;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- LOGV("... address = %s", address);
-
- env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
- env->NewStringUTF(address));
+ env->CallVoidMethod(nat->me, method_onAgentCancel);
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
@@ -933,41 +827,23 @@
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Release")) {
- LOGW("We are no longer the passkey agent!");
-
- // 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;
- }
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Authorize")) {
- const char *adapter;
- const char *address;
- const char *service;
+ "org.bluez.Agent", "Authorize")) {
+ char *object_path;
const char *uuid;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("... address = %s", address);
- LOGV("... service = %s", service);
+ LOGV("... object_path = %s", object_path);
LOGV("... uuid = %s", uuid);
- bool auth_granted = env->CallBooleanMethod(nat->me,
- method_onAuthAgentAuthorize, env->NewStringUTF(address),
- env->NewStringUTF(service), env->NewStringUTF(uuid));
+ bool auth_granted =
+ env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
+ env->NewStringUTF(object_path), env->NewStringUTF(uuid));
// reply
if (auth_granted) {
@@ -990,43 +866,54 @@
}
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Cancel")) {
- const char *adapter;
- const char *address;
- const char *service;
- const char *uuid;
+ "org.bluez.Agent", "RequestPinCode")) {
+ char *object_path;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &service,
- DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
+ LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("... address = %s", address);
- LOGV("... service = %s", service);
- LOGV("... uuid = %s", uuid);
-
- env->CallVoidMethod(nat->me,
- method_onAuthAgentCancel, env->NewStringUTF(address),
- env->NewStringUTF(service), env->NewStringUTF(uuid));
-
- // 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;
- }
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(reply);
+ 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;
-
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Release")) {
- LOGW("We are no longer the auth agent!");
+ "org.bluez.Agent", "RequestPasskey")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPasskey,
+ env->NewStringUTF(object_path),
+ int(msg));
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestConfirmation")) {
+ char *object_path;
+ uint32_t passkey;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestConfirmation,
+ env->NewStringUTF(object_path),
+ passkey,
+ int(msg));
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "Release")) {
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
@@ -1037,7 +924,7 @@
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
} else {
- LOGV("... ignored");
+ LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -1055,7 +942,7 @@
#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
-void onCreateBondingResult(DBusMessage *msg, void *user, void *n) {
+void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
native_data_t *nat = (native_data_t *)n;
@@ -1106,7 +993,7 @@
}
env->CallVoidMethod(nat->me,
- method_onCreateBondingResult,
+ method_onCreatePairedDeviceResult,
env->NewStringUTF(address),
result);
done:
@@ -1114,7 +1001,7 @@
free(user);
}
-void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) {
+void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
const char *address = (const char *) user;
@@ -1133,14 +1020,13 @@
!dbus_message_get_args(msg, &err,
DBUS_TYPE_INT32, &channel,
DBUS_TYPE_INVALID)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
dbus_error_free(&err);
}
done:
env->CallVoidMethod(nat->me,
- method_onGetRemoteServiceChannelResult,
+ method_onGetDeviceServiceChannelResult,
env->NewStringUTF(address),
channel);
free(user);
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
new file mode 100644
index 0000000..326052b
--- /dev/null
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -0,0 +1,740 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
+#define LOG_TAG "BluetoothService.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#include <bluedroid/bluetooth.h>
+#endif
+
+#include <cutils/properties.h>
+
+namespace android {
+
+#define BLUETOOTH_CLASS_ERROR 0xFF000000
+
+#ifdef HAVE_BLUETOOTH
+// We initialize these variables when we load class
+// android.server.BluetoothService
+static jfieldID field_mNativeData;
+static jfieldID field_mEventLoop;
+
+typedef struct {
+ JNIEnv *env;
+ DBusConnection *conn;
+ const char *adapter; // dbus object name of the local adapter
+} native_data_t;
+
+extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
+ jobject);
+extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
+
+
+/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
+ * Perform quick sanity check, if there are any problems return NULL
+ */
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ native_data_t *nat =
+ (native_data_t *)(env->GetIntField(object, field_mNativeData));
+ if (nat == NULL || nat->conn == NULL) {
+ LOGE("Uninitialized native data\n");
+ return NULL;
+ }
+ return nat;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mEventLoop = get_field(env, clazz, "mEventLoop",
+ "Landroid/server/BluetoothEventLoop;");
+#endif
+}
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ nat->env = env;
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus: %s", err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+static const char *get_adapter_path(JNIEnv* env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ event_loop_native_data_t *event_nat =
+ get_EventLoop_native_data(env, env->GetObjectField(object,
+ field_mEventLoop));
+ if (event_nat == NULL)
+ return NULL;
+ return event_nat->adapter;
+#else
+ return NULL;
+#endif
+}
+
+// This function is called when the adapter is enabled.
+static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ event_loop_native_data_t *event_nat =
+ get_EventLoop_native_data(env, env->GetObjectField(object,
+ field_mEventLoop));
+ // Register agent for remote devices.
+ const char *device_agent_path = "/android/bluetooth/remote_device_agent";
+ static const DBusObjectPathVTable agent_vtable = {
+ NULL, agent_event_filter, NULL, NULL, NULL, NULL };
+
+ if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
+ &agent_vtable, event_nat)) {
+ LOGE("%s: Can't register object path %s for remote device agent!",
+ __FUNCTION__, device_agent_path);
+ return JNI_FALSE;
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return JNI_TRUE;
+}
+
+static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat != NULL) {
+ const char *device_agent_path =
+ "/android/bluetooth/remote_device_agent";
+ dbus_connection_unregister_object_path (nat->conn, device_agent_path);
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return JNI_TRUE;
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat) {
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+
+static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ return (env->NewStringUTF(get_adapter_path(env, object)));
+ }
+#endif
+ return NULL;
+}
+
+
+static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jboolean ret = JNI_FALSE;
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ dbus_error_init(&err);
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StartDiscovery");
+
+ if (msg == NULL) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ ret = JNI_FALSE;
+ goto done;
+ }
+
+ ret = JNI_TRUE;
+done:
+ if (reply) dbus_message_unref(reply);
+ if (msg) dbus_message_unref(msg);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static void stopDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jstring ret;
+ native_data_t *nat;
+
+ dbus_error_init(&err);
+
+ nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StopDiscovery");
+ if (msg == NULL) {
+ if (dbus_error_is_set(&err))
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
+ strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
+ // hcid sends this if there is no active discovery to cancel
+ LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
+ dbus_error_free(&err);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ }
+
+done:
+ if (msg) dbus_message_unref(msg);
+ if (reply) dbus_message_unref(reply);
+#endif
+}
+
+static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
+ jstring address, jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+
+ if (nat && eventLoopNat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ const char *capabilities = "DisplayYesNo";
+ const char *agent_path = "/android/bluetooth/remote_device_agent";
+
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+ bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
+ onCreatePairedDeviceResult, // callback
+ context_address,
+ eventLoopNat,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "CreatePairedDevice",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
+ jstring path,
+ jstring pattern, jint attr_id) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+ if (nat && eventLoopNat) {
+ const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ LOGV("... pattern = %s", c_pattern);
+ LOGV("... attr_id = %#X", attr_id);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, c_path,
+ DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
+ DBUS_TYPE_STRING, &c_pattern,
+ DBUS_TYPE_UINT16, &attr_id,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(pattern, c_pattern);
+ env->ReleaseStringUTFChars(path, c_path);
+ return reply ? dbus_returns_int32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
+ jstring address) {
+ LOGV(__FUNCTION__);
+ jboolean result = JNI_FALSE;
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ DBusError err;
+ dbus_error_init(&err);
+ LOGV("... address = %s", c_address);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return JNI_FALSE;
+ } else {
+ result = JNI_TRUE;
+ }
+ dbus_message_unref(reply);
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
+ LOGV(__FUNCTION__);
+ jboolean result = JNI_FALSE;
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply =
+ dbus_func_args_error(env, nat->conn, &err,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "RemoveDevice",
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ result = JNI_FALSE;
+ } else {
+ result = JNI_TRUE;
+ }
+ env->ReleaseStringUTFChars(object_path, c_object_path);
+ if (reply) dbus_message_unref(reply);
+ }
+#endif
+ return result;
+}
+
+static jint enableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_enable();
+#endif
+ return -1;
+}
+
+static jint disableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_disable();
+#endif
+ return -1;
+}
+
+static jint isEnabledNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_is_enabled();
+#endif
+ return -1;
+}
+
+static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
+ jstring address, bool confirm,
+ int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply;
+ if (confirm) {
+ reply = dbus_message_new_method_return(msg);
+ } else {
+ reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Rejected", "User rejected confirmation");
+ }
+
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to RequestConfirmation to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
+ int passkey, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return Passkey code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
+ jstring pin, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return PIN code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ const char *c_pin = env->GetStringUTFChars(pin, NULL);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ env->ReleaseStringUTFChars(pin, c_pin);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
+ jstring address, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Canceled", "Pairing User Input was canceled");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return cancelUserInput to"
+ "D-BUS\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
+ jstring path)
+{
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, c_path,
+ DBUS_DEVICE_IFACE, "GetProperties",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ 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);
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "GetProperties",
+ DBUS_TYPE_INVALID);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(reply, &iter))
+ str_array = parse_adapter_properties(env, &iter);
+ dbus_message_unref(reply);
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
+ void *value, jint type) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply, *msg;
+ DBusMessageIter iter;
+ DBusError err;
+ const char *c_key = env->GetStringUTFChars(key, NULL);
+ dbus_error_init(&err);
+
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "SetProperty");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for GetProperties!",
+ __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
+ dbus_message_iter_init_append(msg, &iter);
+ append_variant(&iter, type, value);
+
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ env->ReleaseStringUTFChars(key, c_key);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
+ jstring value) {
+#ifdef HAVE_BLUETOOTH
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+ jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
+ env->ReleaseStringUTFChars(value, (char *)c_value);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
+ {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
+
+ {"isEnabledNative", "()I", (void *)isEnabledNative},
+ {"enableNative", "()I", (void *)enableNative},
+ {"disableNative", "()I", (void *)disableNative},
+
+ {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
+ {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getDevicePropertiesNative},
+ {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
+ (void *)setAdapterPropertyStringNative},
+ {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
+ (void *)setAdapterPropertyBooleanNative},
+ {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
+ (void *)setAdapterPropertyIntegerNative},
+
+ {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
+ {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
+
+ {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
+ {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
+ {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
+ {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
+ (void *)getDeviceServiceChannelNative},
+
+ {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
+ (void *)setPairingConfirmationNative},
+ {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
+ {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
+ {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
+ (void *)cancelPairingUserInputNative},
+};
+
+int register_android_server_BluetoothService(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7325432..f0885fd 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -25,12 +25,12 @@
#include <stdio.h>
#include <utils/Atomic.h>
-#include <utils/IInterface.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <android_runtime/AndroidRuntime.h>
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 16d993d..495e76a 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -15,7 +15,7 @@
** limitations under the License.
*/
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include "jni.h"
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5e5103a..34b7c89 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -51,17 +51,17 @@
size_t len;
size_t capacity;
uint8_t* buf;
-
+
ByteBuf(size_t initSize) {
buf = (uint8_t*)malloc(initSize);
len = 0;
- capacity = initSize;
+ capacity = initSize;
}
-
+
~ByteBuf() {
free(buf);
}
-
+
bool ensureExtraCapacity(size_t extra) {
size_t spaceNeeded = len + extra;
if (spaceNeeded > capacity) {
@@ -77,7 +77,7 @@
return true;
}
}
-
+
void putIntEvent(jint value) {
bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
buf[len++] = EVENT_TYPE_INT;
@@ -162,7 +162,7 @@
* In class android.util.EventLog:
* static native int writeEvent(long tag, long value)
*/
-static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
jint tag, jlong value)
{
return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
@@ -210,6 +210,8 @@
/*
* In class android.util.EventLog:
* static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ * Reads events from the event log, typically /dev/log/events
*/
static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
jintArray tags,
@@ -273,6 +275,80 @@
env->ReleaseIntArrayElements(tags, tagValues, 0);
}
+/*
+ * In class android.util.EventLog:
+ * static native void readEvents(String path, Collection<Event> output)
+ *
+ * Reads events from a file (See Checkin.Aggregation). Events are stored in
+ * native raw format (logger_entry + payload).
+ */
+static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
+ jobject out) {
+ if (path == NULL || out == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const char *pathString = env->GetStringUTFChars(path, 0);
+ int fd = open(pathString, O_RDONLY | O_NONBLOCK);
+ env->ReleaseStringUTFChars(path, pathString);
+
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+ for (;;) {
+ // read log entry structure from file
+ int len = read(fd, buf, sizeof(logger_entry));
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < sizeof(logger_entry)) {
+ jniThrowException(env, "java/io/IOException", "Event header too short");
+ break;
+ }
+
+ // read event payload
+ logger_entry* entry = (logger_entry*) buf;
+ if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Too much data for event payload. Corrupt file?");
+ break;
+ }
+
+ len = read(fd, buf + sizeof(logger_entry), entry->len);
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < entry->len) {
+ jniThrowException(env, "java/io/IOException", "Event payload too short");
+ break;
+ }
+
+ // create EventLog$Event and add it to the collection
+ int buffer_size = sizeof(logger_entry) + entry->len;
+ jbyteArray array = env->NewByteArray(buffer_size);
+ if (array == NULL) break;
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, buf, buffer_size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ jobject event = env->NewObject(gEventClass, gEventInitID, array);
+ if (event == NULL) break;
+
+ env->CallBooleanMethod(out, gCollectionAddID, event);
+ env->DeleteLocalRef(event);
+ env->DeleteLocalRef(array);
+ }
+
+ close(fd);
+}
/*
* JNI registration.
@@ -292,6 +368,10 @@
{ "readEvents",
"([ILjava/util/Collection;)V",
(void*) android_util_EventLog_readEvents
+ },
+ { "readEvents",
+ "(Ljava/lang/String;Ljava/util/Collection;)V",
+ (void*) android_util_EventLog_readEventsFile
}
};
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 98fe0e6..723fd4b 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -18,9 +18,9 @@
#define LOG_TAG "Process"
#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -385,7 +385,7 @@
return *((const jint*)v1) - *((const jint*)v2);
}
-jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
+static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
{
int fd = open("/proc/meminfo", O_RDONLY);
@@ -405,7 +405,7 @@
buffer[len] = 0;
int numFound = 0;
- int mem = 0;
+ jlong mem = 0;
static const char* const sums[] = { "MemFree:", "Cached:", NULL };
static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
@@ -424,7 +424,7 @@
p++;
if (*p == 0) p--;
}
- mem += atoi(num) * 1024;
+ mem += atoll(num) * 1024;
numFound++;
break;
}
@@ -874,7 +874,7 @@
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
- {"getFreeMemory", "()I", (void*)android_os_Process_getFreeMemory},
+ {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
{"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
{"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 076775f..02677f4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -24,6 +24,7 @@
#include <SkCanvas.h>
#include <SkBitmap.h>
+#include <SkRegion.h>
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
@@ -45,6 +46,7 @@
static sso_t sso;
struct so_t {
+ jfieldID surfaceControl;
jfieldID surface;
jfieldID saveCount;
jfieldID canvas;
@@ -121,10 +123,50 @@
// ----------------------------------------------------------------------------
+static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ return sp<SurfaceControl>(p);
+}
+
+static void setSurfaceControl(JNIEnv* env, jobject clazz,
+ const sp<SurfaceControl>& surface)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (surface.get()) {
+ surface->incStrong(clazz);
+ }
+ if (p) {
+ p->decStrong(clazz);
+ }
+ env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
+}
+
static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
{
- Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
- return sp<Surface>(p);
+ sp<Surface> result((Surface*)env->GetIntField(clazz, so.surface));
+ if (result == 0) {
+ /*
+ * if this method is called from the WindowManager's process, it means
+ * the client is is not remote, and therefore is allowed to have
+ * a Surface (data), so we create it here.
+ * If we don't have a SurfaceControl, it means we're in a different
+ * process.
+ */
+
+ SurfaceControl* const control =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (control) {
+ result = control->getSurface();
+ if (result != 0) {
+ result->incStrong(clazz);
+ env->SetIntField(clazz, so.surface, (int)result.get());
+ }
+ }
+ }
+ return result;
}
static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
@@ -153,12 +195,12 @@
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
- sp<Surface> surface(client->createSurface(pid, dpy, w, h, format, flags));
+ sp<SurfaceControl> surface(client->createSurface(pid, dpy, w, h, format, flags));
if (surface == 0) {
doThrow(env, OutOfResourcesException);
return;
}
- setSurface(env, clazz, surface);
+ setSurfaceControl(env, clazz, surface);
}
static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
@@ -168,28 +210,44 @@
doThrow(env, "java/lang/NullPointerException", NULL);
return;
}
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
+ sp<Surface> rhs = new Surface(*parcel);
setSurface(env, clazz, rhs);
}
static void Surface_clear(JNIEnv* env, jobject clazz, uintptr_t *ostack)
{
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (SurfaceControl::isValid(surface)) {
+ surface->clear();
+ }
+ setSurfaceControl(env, clazz, 0);
+ setSurface(env, clazz, 0);
+}
+
+static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
+{
+ setSurfaceControl(env, clazz, 0);
setSurface(env, clazz, 0);
}
static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- return surface->isValid() ? JNI_TRUE : JNI_FALSE;
+ const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
+ if (surfaceControl != 0) {
+ return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
+ }
+ const sp<Surface>& surface(getSurface(env, clazz));
+ return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
}
static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
{
- /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then
+ /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
we can map to SkBitmap::kARGB_8888_Config, and optionally call
bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
*/
switch (format) {
+ case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
@@ -200,8 +258,8 @@
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return 0;
// get dirty region
@@ -212,7 +270,7 @@
dirty.top = env->GetIntField(dirtyRect, ro.t);
dirty.right = env->GetIntField(dirtyRect, ro.r);
dirty.bottom= env->GetIntField(dirtyRect, ro.b);
- if (dirty.left < dirty.right && dirty.top < dirty.bottom) {
+ if (!dirty.isEmpty()) {
dirtyRegion.set(dirty);
}
} else {
@@ -235,7 +293,11 @@
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
SkBitmap bitmap;
- bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
+ if (info.format == PIXEL_FORMAT_RGBX_8888) {
+ bitmap.setIsOpaque(true);
+ }
if (info.w > 0 && info.h > 0) {
bitmap.setPixels(info.bits);
} else {
@@ -243,13 +305,27 @@
bitmap.setPixels(NULL);
}
nativeCanvas->setBitmapDevice(bitmap);
- nativeCanvas->clipRegion(dirtyRegion.toSkRegion());
+
+ SkRegion clipReg;
+ if (dirtyRegion.isRect()) { // very common case
+ const Rect& b(dirtyRegion.getBounds());
+ clipReg.setRect(b.left, b.top, b.right, b.bottom);
+ } else {
+ size_t count;
+ Rect const* r = dirtyRegion.getArray(&count);
+ while (count) {
+ clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
+ r++, count--;
+ }
+ }
+
+ nativeCanvas->clipRegion(clipReg);
int saveCount = nativeCanvas->save();
env->SetIntField(clazz, so.saveCount, saveCount);
if (dirtyRect) {
- Rect bounds(dirtyRegion.bounds());
+ const Rect& bounds(dirtyRegion.getBounds());
env->SetIntField(dirtyRect, ro.l, bounds.left);
env->SetIntField(dirtyRect, ro.t, bounds.top);
env->SetIntField(dirtyRect, ro.r, bounds.right);
@@ -268,8 +344,8 @@
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return;
// detach the canvas from the surface
@@ -289,26 +365,8 @@
static void Surface_unlockCanvas(
JNIEnv* env, jobject clazz, jobject argCanvas)
{
- jobject canvas = env->GetObjectField(clazz, so.canvas);
- if (canvas != argCanvas) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
- return;
-
- status_t err = surface->unlock();
- if (err < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
- int saveCount = env->GetIntField(clazz, so.saveCount);
- nativeCanvas->restoreToCount(saveCount);
- nativeCanvas->setBitmapDevice(SkBitmap());
- env->SetIntField(clazz, so.saveCount, 0);
+ // XXX: this API has been removed
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_openTransaction(
@@ -353,138 +411,140 @@
static void Surface_setLayer(
JNIEnv* env, jobject clazz, jint zorder)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setLayer(zorder) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setLayer(zorder);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setPosition(
JNIEnv* env, jobject clazz, jint x, jint y)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setPosition(x, y) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setPosition(x, y);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setSize(
JNIEnv* env, jobject clazz, jint w, jint h)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setSize(w, h) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setSize(w, h);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_hide(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->hide() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->hide();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_show(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->show() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->show();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_freeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->freeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->freeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_unfreeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->unfreeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->unfreeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFlags(
JNIEnv* env, jobject clazz, jint flags, jint mask)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFlags(flags, mask) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFlags(flags, mask);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setTransparentRegion(
JNIEnv* env, jobject clazz, jobject argRegion)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
- if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
+
+ const SkIRect& b(nativeRegion->getBounds());
+ Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
+ if (nativeRegion->isComplex()) {
+ SkRegion::Iterator it(*nativeRegion);
+ while (!it.done()) {
+ const SkIRect& r(it.rect());
+ reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
+ it.next();
}
}
+
+ status_t err = surface->setTransparentRegionHint(reg);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setAlpha(
JNIEnv* env, jobject clazz, jfloat alpha)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setAlpha(alpha) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setAlpha(alpha);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setMatrix(
JNIEnv* env, jobject clazz,
jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFreezeTint(
JNIEnv* env, jobject clazz,
jint tint)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFreezeTint(tint) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFreezeTint(tint);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
+// ----------------------------------------------------------------------------
+
static void Surface_copyFrom(
JNIEnv* env, jobject clazz, jobject other)
{
@@ -496,16 +556,21 @@
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = getSurface(env, other);
- if (!Surface::isSameSurface(surface, rhs)) {
+ /*
+ * This is used by the WindowManagerService just after constructing
+ * a Surface and is necessary for returning the Surface reference to
+ * the caller. At this point, we should only have a SurfaceControl.
+ */
+
+ const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
+ const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
+ if (!SurfaceControl::isSameSurface(surface, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
- setSurface(env, clazz, rhs->dup());
+ setSurfaceControl(env, clazz, rhs);
}
}
-
static void Surface_readFromParcel(
JNIEnv* env, jobject clazz, jobject argParcel)
{
@@ -515,9 +580,9 @@
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
- if (!Surface::isSameSurface(surface, rhs)) {
+ const sp<Surface>& control(getSurface(env, clazz));
+ sp<Surface> rhs = new Surface(*parcel);
+ if (!Surface::isSameSurface(control, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
setSurface(env, clazz, rhs);
@@ -535,8 +600,8 @@
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- Surface::writeToParcel(surface, parcel);
+ const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
+ SurfaceControl::writeSurfaceToParcel(control, parcel);
}
// ----------------------------------------------------------------------------
@@ -557,7 +622,8 @@
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init },
{"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
- {"clear", "()V", (void*)Surface_clear },
+ {"clear", "()V", (void*)Surface_clear },
+ {"release", "()V", (void*)Surface_release },
{"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
{"isValid", "()Z", (void*)Surface_isValid },
{"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
@@ -586,7 +652,8 @@
void nativeClassInit(JNIEnv* env, jclass clazz)
{
- so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 4452065..974fc0b 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -21,7 +21,6 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
-#include <ui/EGLNativeWindowSurface.h>
#include <ui/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -338,7 +337,7 @@
goto not_valid_surface;
jint* base = beginNativeAttribList(_env, attrib_list);
- EGLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
endNativeAttributeList(_env, attrib_list, base);
return (jint)sur;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4558660..608c1ff 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -25,7 +25,7 @@
<!-- Special broadcasts that only the system can send -->
<!-- ================================================ -->
<eat-comment />
-
+
<protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
<protected-broadcast android:name="android.intent.action.SCREEN_ON" />
<protected-broadcast android:name="android.intent.action.USER_PRESENT" />
@@ -52,12 +52,12 @@
<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" />
-
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
<eat-comment />
-
+
<!-- Used for permissions that can be used to make the user spend money
without their direct involvement. For example, this is the group
for permissions that allow you to directly place phone calls,
@@ -86,7 +86,7 @@
<!-- Permissions for accessing messages -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Used for permissions that allow an application to send messages
on behalf of the user or intercept messages being received by the
user. This is primarily intended for SMS/MMS messaging, such as
@@ -136,7 +136,7 @@
<!-- Permissions for accessing personal info (contacts and calendar) -->
<!-- =============================================================== -->
<eat-comment />
-
+
<!-- Used for permissions that provide access to the user's private data,
such as contacts, calendar events, e-mail messages, etc. This includes
both reading and writing of this data (which should generally be
@@ -190,8 +190,8 @@
android:description="@string/permdesc_writeCalendar" />
<!-- Allows an application to read the user dictionary. This should
- really only be required by an IME, or a dictionary editor like
- the Settings app.
+ really only be required by an IME, or a dictionary editor like
+ the Settings app.
@hide Pending API council approval -->
<permission android:name="android.permission.READ_USER_DICTIONARY"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
@@ -227,7 +227,7 @@
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
<eat-comment />
-
+
<!-- Used for permissions that allow access to the user's current
location. -->
<permission-group android:name="android.permission-group.LOCATION"
@@ -272,7 +272,7 @@
<!-- Permissions for accessing networks -->
<!-- ======================================= -->
<eat-comment />
-
+
<!-- Used for permissions that provide access to networking services. The
main permission here is internet access, but this is also an
appropriate group for accessing or modifying any network configuration
@@ -309,11 +309,19 @@
android:description="@string/permdesc_bluetooth"
android:label="@string/permlab_bluetooth" />
+ <!-- Allows applications to call into AccountAuthenticators. Only
+ the system can get this permission. -->
+ <permission android:name="android.permission.ACCOUNT_MANAGER_SERVICE"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="signature"
+ android:description="@string/permdesc_accountManagerService"
+ android:label="@string/permlab_accountManagerService" />
+
<!-- ================================== -->
<!-- Permissions for accessing accounts -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Permissions for direct access to Google accounts.
Note that while right now this is only used for Google accounts,
we expect in the future to have a more general account management
@@ -330,11 +338,33 @@
android:description="@string/permdesc_getAccounts"
android:label="@string/permlab_getAccounts" />
+ <!-- Allows an application to act as an AccountAuthenticator for
+ the AccountManager -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_authenticateAccounts"
+ android:description="@string/permdesc_authenticateAccounts" />
+
+ <!-- Allows an application to request authtokens from the AccountManager -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_useCredentials"
+ android:description="@string/permdesc_useCredentials" />
+
+ <!-- Allows an application to manage the list of accounts in the AccountManager -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_manageAccounts"
+ android:description="@string/permdesc_manageAccounts" />
+
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Used for permissions that provide direct access to the hardware on
the device. This includes audio, the camera, vibrator, etc. -->
<permission-group android:name="android.permission-group.HARDWARE_CONTROLS"
@@ -387,7 +417,7 @@
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
<eat-comment />
-
+
<!-- Used for permissions that are associated with accessing and modifyign
telephony state: intercepting outgoing calls, reading
and modifying the phone state. Note that
@@ -441,7 +471,7 @@
<!-- Permissions for low-level system interaction -->
<!-- ============================================ -->
<eat-comment />
-
+
<!-- Group of permissions that are related to system APIs. Many
of these are not permissions the user will be expected to understand,
and such permissions should generally be marked as "normal" protection
@@ -665,7 +695,7 @@
android:description="@string/permdesc_writeApnSettings"
android:label="@string/permlab_writeApnSettings" />
- <!-- Allows an application to allow access the subscribed feeds
+ <!-- Allows an application to allow access the subscribed feeds
ContentProvider. -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -677,7 +707,7 @@
android:label="@string/permlab_subscribedFeedsWrite"
android:description="@string/permdesc_subscribedFeedsWrite"
android:protectionLevel="dangerous" />
-
+
<!-- Allows applications to change network connectivity state -->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -728,7 +758,7 @@
<!-- Permissions for special development tools -->
<!-- ========================================= -->
<eat-comment />
-
+
<!-- Group of permissions that are related to development features. These
are not permissions that should appear in normal applications; they
protect APIs that are intended only to be used for development
@@ -864,6 +894,13 @@
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
+ <!-- Must be required by wallpaper services, to ensure that only the
+ system can bind to them. -->
+ <permission android:name="android.permission.BIND_WALLPAPER"
+ android:label="@string/permlab_bindWallpaper"
+ android:description="@string/permdesc_bindWallpaper"
+ android:protectionLevel="signature" />
+
<!-- Allows low-level access to setting the orientation (actually
rotation) of the screen. Not for use by normal applications. -->
<permission android:name="android.permission.SET_ORIENTATION"
@@ -1009,6 +1046,13 @@
android:description="@string/permdesc_backup"
android:protectionLevel="signatureOrSystem" />
+ <!-- Allows an application to participate in the backup and restore process
+ @hide -->
+ <permission android:name="android.permission.BACKUP_DATA"
+ android:label="@string/permlab_backup_data"
+ android:description="@string/permdesc_backup_data"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
picks an AppWidget to go into a particular host, thereby giving that
@@ -1052,12 +1096,18 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature" />
+ <!-- Allows applications to set a live wallpaper.
+ @hide -->
+ <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
android:label="@string/android_system_label"
android:allowClearUserData="false"
- android:backupAgent="com.android.internal.backup.SystemBackupAgent"
+ android:backupAgent="com.android.server.SystemBackupAgent"
android:icon="@drawable/ic_launcher_android">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.Dialog.Alert"
@@ -1090,8 +1140,31 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name="android.accounts.ChooseAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="com.android.server.ShutdownActivity"
+ android:permission="android.permission.SHUTDOWN"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<service android:name="com.android.server.LoadAverageService"
- android:exported="true" />
+ android:exported="true" />
+
+ <service android:name="com.android.internal.service.wallpaper.ImageWallpaper"
+ android:permission="android.permission.BIND_WALLPAPER">
+ </service>
<receiver android:name="com.android.server.BootReceiver" >
<intent-filter>
@@ -1102,7 +1175,7 @@
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR" >
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
diff --git a/core/res/res/drawable/contact_header_bg.9.png b/core/res/res/drawable/contact_header_bg.9.png
new file mode 100644
index 0000000..7f9a5a3
--- /dev/null
+++ b/core/res/res/drawable/contact_header_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable/contact_picture_bg.9.png b/core/res/res/drawable/contact_picture_bg.9.png
new file mode 100644
index 0000000..ae9c709
--- /dev/null
+++ b/core/res/res/drawable/contact_picture_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_2.png b/core/res/res/drawable/ic_contact_picture_2.png
new file mode 100644
index 0000000..8b184af
--- /dev/null
+++ b/core/res/res/drawable/ic_contact_picture_2.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_3.png b/core/res/res/drawable/ic_contact_picture_3.png
new file mode 100644
index 0000000..a2d08b5
--- /dev/null
+++ b/core/res/res/drawable/ic_contact_picture_3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_flightmode.png b/core/res/res/drawable/stat_sys_signal_flightmode.png
old mode 100644
new mode 100755
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
new file mode 100644
index 0000000..20df5c6
--- /dev/null
+++ b/core/res/res/layout-ja/contact_header_name.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<!-- In Japanese-language locales, the "Name" field contains two separate
+ TextViews: the name itself, and also the phonetic ("furigana") field. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content">
+
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/secondary_text_light"
+ />
+
+ <TextView android:id="@+id/phonetic_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textColor="@android:color/secondary_text_light"
+ />
+
+</LinearLayout>
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
new file mode 100644
index 0000000..73e379b
--- /dev/null
+++ b/core/res/res/layout/contact_header.xml
@@ -0,0 +1,65 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/banner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="@drawable/contact_header_bg"
+ 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:scaleType="fitCenter"
+ android:background="@drawable/contact_picture_bg"/>
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <!-- "Name" field is locale-specific. -->
+ <include layout="@layout/contact_header_name"/>
+
+ <TextView android:id="@+id/status"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:maxLines="2"/>
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="3dip"
+ android:paddingRight="6dip"/>
+
+ <CheckBox
+ android:id="@+id/star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?android:attr/starStyle" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/contact_header_name.xml b/core/res/res/layout/contact_header_name.xml
new file mode 100644
index 0000000..9039702
--- /dev/null
+++ b/core/res/res/layout/contact_header_name.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<!-- In the default locale, the "Name" field is a single TextView -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ 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:singleLine="true"
+ android:ellipsize="end"
+ />
diff --git a/core/res/res/layout/grant_credentials_permission.xml b/core/res/res/layout/grant_credentials_permission.xml
new file mode 100644
index 0000000..fe1c22e
--- /dev/null
+++ b/core/res/res/layout/grant_credentials_permission.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/message" />
+ <Button android:id="@+id/allow"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/allow" />
+
+ <Button android:id="@+id/deny"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/deny" />
+
+ <ListView android:id="@+id/packages_list"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_dialog.xml b/core/res/res/layout/preference_dialog.xml
new file mode 100644
index 0000000..5cf0f6e
--- /dev/null
+++ b/core/res/res/layout/preference_dialog.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Layout used by DialogPreference widgets. This is inflated inside
+ android.R.layout.preference. -->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="4dip"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/btn_circle"
+ android:src="@drawable/ic_btn_round_more" />
+
diff --git a/core/res/res/layout/zoom_browser_accessory_buttons.xml b/core/res/res/layout/zoom_browser_accessory_buttons.xml
index 69afca9..4bf2bdf 100644
--- a/core/res/res/layout/zoom_browser_accessory_buttons.xml
+++ b/core/res/res/layout/zoom_browser_accessory_buttons.xml
@@ -18,11 +18,18 @@
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView android:id="@+id/zoom_page_overview"
- android:background="@android:drawable/btn_browser_zoom_page_overview"
+ <ImageView android:id="@+id/zoom_fit_page"
+ android:background="@android:drawable/btn_browser_zoom_fit_page"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_marginLeft="7dip"
/>
+ <ImageView android:id="@+id/zoom_page_overview"
+ android:background="@android:drawable/btn_browser_zoom_page_overview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="7dip"
+ />
</merge>
diff --git a/core/res/res/raw/loaderror.html b/core/res/res/raw/loaderror.html
index 359a1e7..fd3d766 100644
--- a/core/res/res/raw/loaderror.html
+++ b/core/res/res/raw/loaderror.html
@@ -1,5 +1,6 @@
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<title>Web page not available</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw/nodomain.html b/core/res/res/raw/nodomain.html
index 7a107fb..a71dbcd 100644
--- a/core/res/res/raw/nodomain.html
+++ b/core/res/res/raw/nodomain.html
@@ -1,5 +1,6 @@
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<title>Web page not available</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ad52251..0d6137b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<bez názvu>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(žádné telefonní číslo)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Neznámé)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Hlasová schránka"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problém s připojením nebo neplatný kód MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Služba byla zapnuta."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Služba byla zapnuta pro:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Služba byla vypnuta."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrace byla úspěšná."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Smazaní proběhlo úspěšně."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Nesprávné heslo."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Funkce MMI byla dokončena."</string>
- <string name="badPin" msgid="5085454289896032547">"Původní kód PIN byl zadán nesprávně."</string>
- <string name="badPuk" msgid="5702522162746042460">"Kód PUK byl zadán nesprávně."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Zadané kódy PIN se neshodují."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Zadejte kód PIN o délce 4-8 číslic."</string>
- <string name="needPuk" msgid="919668385956251611">"Karta SIM je blokována pomocí kódu PUK. Odblokujete ji zadáním kódu PUK."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Chcete-li odblokovat kartu SIM, zadejte kód PUK2."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Příchozí identifikace volajícího"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Odchozí identifikace volajícího"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Přesměrování hovorů"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Další hovor na lince"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blokování hovorů"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Změna hesla"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Změna kódu PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Volané číslo uvedeno"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Volání čísla omezeno"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Konference tří účastníků"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Odmítnutí nevyžádaných obtěžujících hovorů"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Doručení volaného čísla"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Nerušit"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Omezeno"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Omezeno"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba není zřízena."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Nelze změnit nastavení identifikace volajícího."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omezený přístup byl změněn."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datová služba je zablokována."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tísňová linka je zablokována."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Hlasová služba a služba SMS jsou zablokovány."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Veškeré hlasové služby a služby SMS jsou zablokovány."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Hlas"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Async"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchronizace"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakety"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indikátor roamingu svítí"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indikátor roamingu nesvítí"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indikátor roamingu bliká"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Není v blízkosti"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Mimo budovu"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming – preferovaný systém"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming – dostupný systém"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming – alianční partner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming – prémiový partner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming – úplná funkčnost služby"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming – částečná funkčnost služby"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner roamingu je zapnutý"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner roamingu je vypnutý"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Vyhledávání služby"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Požadavek zadaný pomocí kódu funkce byl úspěšně dokončen."</string>
- <string name="fcError" msgid="3327560126588500777">"Problém s připojením nebo neplatný kód funkce."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Webová stránka obsahuje chybu."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Adresu URL nelze najít."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schéma ověření webu není podporováno."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Ověření nebylo úspěšné."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Ověření pomocí serveru proxy bylo neúspěšné."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Připojení k serveru bylo neúspěšné."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Komunikace se serverem se nezdařila. Opakujte akci později."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Spojení se serverem vypršelo."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stránka obsahuje příliš mnoho přesměrování serveru."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokol není podporován."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Nelze navázat zabezpečené spojení."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Stránku nelze otevřít, protože adresa URL je neplatná."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"K souboru nelze získat přístup."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Požadovaný soubor nebyl nalezen."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Je zpracováváno příliš mnoho požadavků. Opakujte akci později."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronizace"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizace"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Paměť telefonu je plná. Smažte některé soubory a uvolněte místo."</string>
- <string name="me" msgid="6545696007631404292">"Já"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Možnosti telefonu"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tichý režim"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Zapnout bezdrátové připojení"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Vypnout bezdrátové připojení"</string>
- <string name="screen_lock" msgid="799094655496098153">"Zámek obrazovky"</string>
- <string name="power_off" msgid="4266614107412865048">"Vypnout"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Vypínání..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Váš telefon bude vypnut."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Žádné nedávno použité aplikace."</string>
- <string name="global_actions" msgid="2406416831541615258">"Možnosti telefonu"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string>
- <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Zpoplatněné služby"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Umožňuje aplikacím provádět činnosti, které vás mohou stát peníze."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše zprávy"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Čtení a zápis zpráv SMS, e-mailů a dalších zpráv."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vaše osobní informace"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Přímý přístup k vašim kontaktům a kalendáři v telefonu."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Vaše poloha"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Sleduje vaši fyzickou polohu"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Síťová komunikace"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Umožňuje aplikacím získat přístup k různým funkcím sítě."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Vaše účty Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Přístup k dostupným účtům Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Řízení hardwaru"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Přímý přístup k hardwaru telefonu."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonní hovory"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Sledování, záznam a zpracování telefonních hovorů."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systémové nástroje"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Nízkoúrovňový přístup a kontrola nad systémem."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Nástroje pro vývojáře"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funkce pouze pro vývojáře aplikací"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložiště"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Přístup ke kartě SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"zakázání či změny stavového řádku"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"rozbalení a sbalení stavového řádku"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Umožňuje aplikaci rozbalit či sbalit stavový řádek."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"zachycení odchozích hovorů"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Umožňuje aplikaci zpracovat odchozí hovory a změnit číslo, které má být vytočeno. Škodlivé aplikace mohou sledovat či přesměrovat odchozí hovory nebo jim zabránit."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"příjem zpráv SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Umožňuje aplikaci přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"příjem zpráv MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Umožňuje aplikaci přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"odesílat zprávy SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Umožňuje aplikaci odesílat zprávy SMS. Škodlivé aplikace mohou bez vašeho potvrzení odesílat zpoplatněné zprávy."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"čtení zpráv SMS a MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Umožňuje aplikaci číst zprávy SMS uložené ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou načíst vaše soukromé zprávy."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"úprava zpráv SMS a MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Umožňuje aplikaci zapisovat do zpráv SMS uložených ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou smazat vaše zprávy."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"příjem WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Umožňuje aplikaci přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"načtení spuštěných aplikací"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Umožňuje aplikaci načíst informace o aktuálně a nedávno spuštěných úlohách. Toto nastavení může škodlivým aplikacím umožnit odhalení soukromých informací o jiných aplikacích."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"změna uspořádání spuštěných aplikací"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikaci přesouvat úlohy do popředí či pozadí. Škodlivé aplikace mohou vynutit své přesunutí do popředí bez vašeho přičinění."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"povolit ladění aplikací"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikaci povolit ladění jiné aplikace. Škodlivé aplikace mohou pomocí tohoto nastavení ukončit jiné aplikace."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"změny vašeho nastavení uživatelského rozhraní"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Umožňuje aplikaci změnit aktuální konfiguraci, např. národní prostředí či obecnou velikost písma."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"restartování ostatních aplikací"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Umožňuje aplikaci vynutit restartování jiných aplikací."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"vynucení zavření aplikace"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Umožňuje aplikaci vynutit zavření a přesunutí libovolné činnosti v popředí na pozadí. Běžné aplikace by toto nastavení neměly nikdy využívat."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"načtení interního stavu systému"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Umožňuje aplikaci načíst interní stav systému. Škodlivé aplikace mohou načíst řádu soukromých a zabezpečených informací, které by nikdy neměly potřebovat."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"Částečné vypnutí"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvede správce činností do vypnutého stavu. Nedojde však k úplnému vypnutí."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Zabránit přepínání aplikací"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Zabrání uživateli přepnout na jinou aplikaci."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"sledování a řízení spouštění všech aplikací"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Umožňuje aplikaci sledovat a řídit spouštění činností systémem. Škodlivé aplikace mohou zcela ovládnout systém. Toto oprávnění je zapotřebí pouze pro účely vývoje, nikdy pro běžné použití telefonu."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odeslání vysílání o odstranění balíčku"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Umožňuje aplikaci vysílat oznámení o odstranění balíčku aplikace. Škodlivé aplikace mohou pomocí tohoto nastavení ukončit libovolnou další spuštěnou aplikaci."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"odeslání vysílání o přijaté zprávě SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou pomocí tohoto nastavení falšovat příchozí zprávy SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odeslání vysílání typu WAP-PUSH-received"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy WAP PUSH. Škodlivé aplikace mohou pomocí tohoto nastavení zfalšovat výpis o doručení zprávy MMS nebo nepozorovaně nahradit obsah jakékoli webové stránky škodlivým obsahem."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"omezení počtu spuštěných procesů"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Umožňuje aplikaci řídit maximální počet spuštěných procesů. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"zavření všech aplikací na pozadí"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Umožňuje aplikaci ovládat, zda jsou činnosti vždy dokončeny po přesunutí do pozadí. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"změna statistických údajů o baterii"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Umožňuje změnu shromážděných statistických údajů o baterii. Není určeno pro běžné aplikace."</string>
- <string name="permlab_backup" msgid="470013022865453920">"Ovládat zálohování a obnovu systému"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Umožňuje aplikaci ovládat mechanizmus zálohování a obnovy systému. Není určeno k použití v běžných aplikacích."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazení nepovolených oken"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Umožňuje vytvoření oken, která mají být použita interním systémem uživatelského rozhraní. Běžné aplikace toto nastavení nepoužívají."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"zobrazení upozornění systémové úrovně"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Umožňuje aplikaci zobrazit okna s výstrahami systému. Škodlivé aplikace mohou převzít kontrolu nad celou obrazovkou telefonu."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"globální změny rychlosti animace"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Umožňuje aplikaci kdykoli globálně změnit rychlost animace (rychlejší či pomalejší animace)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"správa tokenů aplikací"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Umožňuje aplikaci vytvořit a spravovat své vlastní tokeny a obejít jejich obvyklé řazení typu Z. Toto nastavení by nikdy nemělo být potřeba pro běžné aplikace."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"používání kláves a tlačítek"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Umožňuje aplikaci doručit své vlastní vstupní události (stisknutí tlačítek, apod.) dalším aplikacím. Škodlivé aplikace mohou pomocí tohoto nastavení převzít kontrolu nad telefonem."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"zaznamenání psaného textu a prováděných činností"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Umožňuje aplikacím sledovat, které klávesy používáte, a to i při práci s jinými aplikacemi (například při zadávání hesla). Běžné aplikace by toto nastavení nikdy neměly vyžadovat."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vazba k metodě zadávání dat"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odeslání signálů Linux aplikacím"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spuštění aplikace"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Umožňuje aplikaci učinit své části trvalými, takže je systém nemůže použít pro jiné aplikace."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"smazání aplikací"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Umožňuje aplikaci smazat balíčky systému Android. Škodlivé aplikace mohou pomocí tohoto nastavení smazat důležité aplikace."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"smazání dat ostatních aplikací"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Umožňuje aplikaci smazat data uživatele."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"smazání mezipaměti ostatních aplikací"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Umožňuje aplikaci smazat soubory v mezipaměti."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"výpočet místa pro ukládání aplikací"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Umožňuje aplikaci načtení svého kódu, dat a velikostí mezipaměti"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"přímá instalace aplikací"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Umožňuje aplikaci nainstalovat nové či aktualizované balíčky systému Android. Škodlivé aplikace mohou pomocí tohoto nastavení přidat nové aplikace s libovolnými oprávněními."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"smazání všech dat v mezipaměti aplikace"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"čtení systémových souborů protokolu"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, ale neměly by obsahovat žádné osobní či soukromé informace."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat pouze výrobce či operátor pro diagnostiku hardwaru."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"povolení či zakázání komponent aplikací"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Umožňuje aplikaci změnit, zda je komponenta jiné aplikace povolena nebo ne. Škodlivé aplikace mohou pomocí tohoto nastavení vypnout důležité funkce telefonu. Je třeba postupovat opatrně, protože je možné způsobit nepoužitelnost, nekonzistenci či nestabilitu komponent aplikací."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"nastavení upřednostňovaných aplikací"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Umožňuje aplikaci změnit vaše upřednostňované aplikace. Toto nastavení může škodlivým aplikacím umožnit nepozorovaně změnit spouštěné aplikace a oklamat vaše existující aplikace tak, aby shromažďovaly vaše soukromá data."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"změny globálních nastavení systému"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Umožňuje aplikaci upravit data nastavení systému. Škodlivé aplikace mohou poškodit konfiguraci vašeho systému."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"změny zabezpečených nastavení systému"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Umožňuje aplikaci změnit data zabezpečených nastavení systému. Běžné aplikace toto nastavení nevyužívají."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"změny mapy služeb Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Umožňuje aplikaci změnit mapu služeb Google. Běžné aplikace toto nastavení nevyužívají."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatické spuštění při startu"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Umožňuje aplikaci spuštění ihned po spuštění systému. Toto nastavení může zpomalit spuštění telefonu a umožnit aplikaci celkově zpomalit telefon, protože bude neustále spuštěna."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"odeslání trvalého vysílání"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Umožňuje aplikaci odeslat trvalá vysílání, která přetrvávají i po skončení vysílání. Škodlivé aplikace mohou telefon zpomalit či způsobit jeho nestabilitu, protože bude používat příliš mnoho paměti."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"čtení dat kontaktů"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Umožňuje aplikaci načíst všechna data kontaktů (adresy) uložená ve vašem telefonu. Škodlivé aplikace poté mohou dalším lidem odeslat vaše data."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"zápis dat kontaktů"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Umožňuje aplikaci změnit kontaktní údaje (adresu) uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit kontaktní údaje."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"zápis informací o vlastníkovi"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Umožňuje aplikaci změnit informace o vlastníkovi telefonu uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit informace o vlastníkovi."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"čtení informací o vlastníkovi"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Umožňuje aplikaci číst informace o vlastníkovi telefonu uložená v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení načíst informace o vlastníkovi."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"čtení dat kalendáře"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Umožňuje aplikaci načíst všechny události kalendáře uložené ve vašem telefonu. Škodlivé aplikace poté mohou dalším lidem odeslat události z vašeho kalendáře."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"zápis dat kalendáře"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Umožňuje aplikaci změnit události kalendáře uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit vaše data v kalendáři."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"simulace zdrojů polohy pro účely testování"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Vytváří simulované zdroje polohy pro účely testování. Škodlivé aplikace mohou pomocí tohoto nastavení změnit polohu či stav vrácený zdroji skutečné polohy, jako je např. jednotka GPS či poskytovatelé sítě."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"přístup k dalším příkazům poskytovatele polohy"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Umožňuje získat přístup k dalším příkazům poskytovatele polohy. Škodlivé aplikace mohou pomocí tohoto nastavení narušit funkci GPS či jiných zdrojů polohy."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Oprávnění k instalaci poskytovatele polohy"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Vytvořit simulace zdrojů polohy pro účely testování. Škodlivé aplikace mohou toto nastavení využít k přepsání polohy nebo stavu vráceného zdroji skutečné polohy, například systémem GPS nebo poskytovateli sítí. Mohou také monitorovat polohu a ohlásit ji externímu zdroji."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"upřesnění polohy (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Umožňuje aplikaci přístup ke zdrojům přesné polohy v telefonu, jako je například systém GPS, je-li k dispozici. Škodlivé aplikace mohou pomocí tohoto nastavení zjistit vaši polohu a mohou zvýšit spotřebu baterie."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"přibližná poloha (pomocí sítě)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Umožňuje získat přístup ke zdrojům přibližné polohy, jako je například databáze mobilní sítě, je-li k dispozici, a určit přibližnou pozici telefonu. Škodlivé aplikace takto mohou zjistit, kde se přibližně nacházíte."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"přístup ke službě SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čtení vyrovnávací paměti snímků"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Umožňuje aplikaci načíst obsah vyrovnávací paměti snímků."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"změna vašeho nastavení zvuku"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Umožňuje aplikaci změnit globální nastavení zvuku, například hlasitost či směrování."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrání zvuku"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Umožňuje aplikaci získat přístup k nahrávání zvuku."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"pořizování fotografií"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Umožňuje aplikaci pořizovat fotografie pomocí fotoaparátu. Toto nastavení aplikaci umožní shromažďovat fotografie toho, na co je zrovna fotoaparát namířen."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"trvalé vypnutí telefonu"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Umožňuje aplikaci trvale vypnout celý telefon. Toto je velmi nebezpečné nastavení."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"vynucení restartování telefonu"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Umožňuje aplikaci vynutit restartování telefonu."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"připojení a odpojení souborových systémů"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Umožňuje aplikaci připojit či odpojit souborové systémy ve vyměnitelných úložištích."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formátovat externí úložiště"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Umožňuje aplikaci formátovat vyměnitelná úložiště."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"ovládání vibrací"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikaci ovládat vibrace."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikaci ovládat kontrolku."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testování hardwaru"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Umožňuje aplikaci ovládat různé periferie pro účely testování hardwaru."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Umožňuje aplikaci bez vašeho zásahu volat na telefonní čísla. Škodlivé aplikace mohou na váš telefonní účet připsat neočekávané hovory. Toto nastavení aplikaci neumožňuje volat na tísňové linky."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"přímé volání na libovolná telefonní čísla"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Umožňuje aplikaci bez vašeho zásahu vytočit jakékoli telefonní číslo, včetně čísel tísňového volání. Škodlivé aplikace mohou provádět zbytečná a nezákonná volání na tísňové linky."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládání oznámení o aktualizaci polohy"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Umožňuje povolit či zakázat aktualizace polohy prostřednictvím bezdrátového připojení. Aplikace toto nastavení obvykle nepoužívají."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"přístup k vlastnostem Checkin"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Umožňuje čtení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"zvolit widgety"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Umožňuje aplikaci sdělit systému, které aplikace mohou používat které widgety. Aplikace s tímto oprávněním mohou zpřístupnit osobní údaje jiným aplikacím. Není určeno pro běžné aplikace."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"změny stavu telefonu"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním může přepínat sítě nebo zapnout či vypnout bezdrátové připojení telefonu bez vašeho svolení."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"zabránění přechodu telefonu do režimu spánku"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"zapnutí či vypnutí telefonu"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Umožňuje aplikaci zapnout či vypnout telefon."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"spuštění v režimu továrního testu"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Umožňuje aplikaci spuštění v režimu nízkoúrovňového testu výrobce a povolí přístup k hardwaru telefonu. K dispozici pouze, je-li telefon spuštěn v režimu testování výrobce."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastavení tapety"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Umožňuje aplikaci nastavit tapetu systému."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"nastavení nápovědy pro velikost tapety"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Umožňuje aplikaci nastavit nápovědu pro velikost tapety systému."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"obnovení továrního nastavení systému"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Umožňuje aplikaci kompletně obnovit systém do továrního nastavení a vymazat všechna data, konfiguraci a nainstalované aplikace."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"nastavení časového pásma"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Umožňuje aplikaci změnit časové pásmo telefonu."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"odhalení známých účtů"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Umožňuje aplikaci získat seznam účtů v telefonu."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"zobrazení stavu sítě"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Umožňuje aplikaci zobrazit stav všech sítí."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"plný přístup k Internetu"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Umožňuje aplikaci vytvořit síťové sokety."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"zápis nastavení pro název přístupového bodu (APN)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Umožňuje aplikaci změnit nastavení APN, jako je například proxy či port APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"změna připojení k síti"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Umožňuje aplikaci změnit stav připojení k síti."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"změnit nastavení použití dat na pozadí"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Umožňuje aplikaci změnit nastavení použití dat na pozadí."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"zobrazení stavu WiFi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Umožňuje aplikaci zobrazit informace o stavu připojení WiFi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Změnit stav WiFi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Umožňuje aplikaci připojit se k přístupovým bodům WiFi či se od nich odpojit a provádět změny nakonfigurovaných sítí WiFi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Povolit příjem Wi-Fi Multicast"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Povoluje aplikaci přijímat pakety, které nebyly adresovány přímo vašemu zařízení. Pomocí této možnosti můžete objevit služby nabízené ve vaší blízkosti. Spotřeba energie je vyšší než u režimu bez vícesměrového vysílání (multicast)."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"správa rozhraní Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Umožňuje aplikaci konfigurovat místní telefon s rozhraním Bluetooth a vyhledávat a párovat vzdálená zařízení."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"vytvoření připojení Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Umožňuje aplikaci zobrazit konfiguraci místního telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"vypnutí zámku kláves"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Umožňuje aplikaci vypnout zámek kláves a související zabezpečení heslem. Příkladem oprávněného použití této funkce je vypnutí zámku klávesnice při příchozím hovoru a jeho opětovné zapnutí po skončení hovoru."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čtení nastavení synchronizace"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Umožňuje aplikaci načíst nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"zápis nastavení synchronizace"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Umožňuje aplikaci změnit nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"čtení statistických údajů o synchronizaci"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Umožňuje aplikaci číst statistické informace o synchronizaci, např. historii proběhlých synchronizací."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čtení zdrojů přihlášených k odběru"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zápis odebíraných zdrojů"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"číst slovník definovaný uživatelem"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Umožní aplikaci číst soukromá slova, jména a fráze, která uživatel mohl uložit do svého slovníku."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"zapisovat do slovníku definovaného uživatelem"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Umožní aplikaci zapisovat nová slova do uživatelského slovníku."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"Změnit/smazat obsah karty SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Umožní aplikaci zápis na kartu SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<bez názvu>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(žádné telefonní číslo)"</string>
+ <string name="unknownName">"(Neznámé)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Hlasová schránka"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problém s připojením nebo neplatný kód MMI."</string>
+ <string name="serviceEnabled">"Služba byla zapnuta."</string>
+ <string name="serviceEnabledFor">"Služba byla zapnuta pro:"</string>
+ <string name="serviceDisabled">"Služba byla vypnuta."</string>
+ <string name="serviceRegistered">"Registrace byla úspěšná."</string>
+ <string name="serviceErased">"Smazaní proběhlo úspěšně."</string>
+ <string name="passwordIncorrect">"Nesprávné heslo."</string>
+ <string name="mmiComplete">"Funkce MMI byla dokončena."</string>
+ <string name="badPin">"Původní kód PIN byl zadán nesprávně."</string>
+ <string name="badPuk">"Kód PUK byl zadán nesprávně."</string>
+ <string name="mismatchPin">"Zadané kódy PIN se neshodují."</string>
+ <string name="invalidPin">"Zadejte kód PIN o délce 4-8 číslic."</string>
+ <string name="needPuk">"Karta SIM je blokována pomocí kódu PUK. Odblokujete ji zadáním kódu PUK."</string>
+ <string name="needPuk2">"Chcete-li odblokovat kartu SIM, zadejte kód PUK2."</string>
+ <string name="ClipMmi">"Příchozí identifikace volajícího"</string>
+ <string name="ClirMmi">"Odchozí identifikace volajícího"</string>
+ <string name="CfMmi">"Přesměrování hovorů"</string>
+ <string name="CwMmi">"Další hovor na lince"</string>
+ <string name="BaMmi">"Blokování hovorů"</string>
+ <string name="PwdMmi">"Změna hesla"</string>
+ <string name="PinMmi">"Změna kódu PIN"</string>
+ <string name="CnipMmi">"Volané číslo uvedeno"</string>
+ <string name="CnirMmi">"Volání čísla omezeno"</string>
+ <string name="ThreeWCMmi">"Konference tří účastníků"</string>
+ <string name="RuacMmi">"Odmítnutí nevyžádaných obtěžujících hovorů"</string>
+ <string name="CndMmi">"Doručení volaného čísla"</string>
+ <string name="DndMmi">"Nerušit"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Omezeno"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Omezeno"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
+ <string name="serviceNotProvisioned">"Služba není zřízena."</string>
+ <string name="CLIRPermanent">"Nelze změnit nastavení identifikace volajícího."</string>
+ <string name="RestrictedChangedTitle">"Omezený přístup byl změněn."</string>
+ <string name="RestrictedOnData">"Datová služba je zablokována."</string>
+ <string name="RestrictedOnEmergency">"Tísňová linka je zablokována."</string>
+ <string name="RestrictedOnNormal">"Hlasová služba a služba SMS jsou zablokovány."</string>
+ <string name="RestrictedOnAll">"Veškeré hlasové služby a služby SMS jsou zablokovány."</string>
+ <string name="serviceClassVoice">"Hlas"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Async"</string>
+ <string name="serviceClassDataSync">"Synchronizace"</string>
+ <string name="serviceClassPacket">"Pakety"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indikátor roamingu svítí"</string>
+ <string name="roamingText1">"Indikátor roamingu nesvítí"</string>
+ <string name="roamingText2">"Indikátor roamingu bliká"</string>
+ <string name="roamingText3">"Není v blízkosti"</string>
+ <string name="roamingText4">"Mimo budovu"</string>
+ <string name="roamingText5">"Roaming – preferovaný systém"</string>
+ <string name="roamingText6">"Roaming – dostupný systém"</string>
+ <string name="roamingText7">"Roaming – alianční partner"</string>
+ <string name="roamingText8">"Roaming – prémiový partner"</string>
+ <string name="roamingText9">"Roaming – úplná funkčnost služby"</string>
+ <string name="roamingText10">"Roaming – částečná funkčnost služby"</string>
+ <string name="roamingText11">"Banner roamingu je zapnutý"</string>
+ <string name="roamingText12">"Banner roamingu je vypnutý"</string>
+ <string name="roamingTextSearching">"Vyhledávání služby"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="fcComplete">"Požadavek zadaný pomocí kódu funkce byl úspěšně dokončen."</string>
+ <string name="fcError">"Problém s připojením nebo neplatný kód funkce."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Webová stránka obsahuje chybu."</string>
+ <string name="httpErrorLookup">"Adresu URL nelze najít."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schéma ověření webu není podporováno."</string>
+ <string name="httpErrorAuth">"Ověření nebylo úspěšné."</string>
+ <string name="httpErrorProxyAuth">"Ověření pomocí serveru proxy bylo neúspěšné."</string>
+ <string name="httpErrorConnect">"Připojení k serveru bylo neúspěšné."</string>
+ <string name="httpErrorIO">"Komunikace se serverem se nezdařila. Opakujte akci později."</string>
+ <string name="httpErrorTimeout">"Spojení se serverem vypršelo."</string>
+ <string name="httpErrorRedirectLoop">"Stránka obsahuje příliš mnoho přesměrování serveru."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokol není podporován."</string>
+ <string name="httpErrorFailedSslHandshake">"Nelze navázat zabezpečené spojení."</string>
+ <string name="httpErrorBadUrl">"Stránku nelze otevřít, protože adresa URL je neplatná."</string>
+ <string name="httpErrorFile">"K souboru nelze získat přístup."</string>
+ <string name="httpErrorFileNotFound">"Požadovaný soubor nebyl nalezen."</string>
+ <string name="httpErrorTooManyRequests">"Je zpracováváno příliš mnoho požadavků. Opakujte akci později."</string>
+ <string name="contentServiceSync">"Synchronizace"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronizace"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Paměť telefonu je plná. Smažte některé soubory a uvolněte místo."</string>
+ <string name="me">"Já"</string>
+ <string name="power_dialog">"Možnosti telefonu"</string>
+ <string name="silent_mode">"Tichý režim"</string>
+ <string name="turn_on_radio">"Zapnout bezdrátové připojení"</string>
+ <string name="turn_off_radio">"Vypnout bezdrátové připojení"</string>
+ <string name="screen_lock">"Zámek obrazovky"</string>
+ <string name="power_off">"Vypnout"</string>
+ <string name="shutdown_progress">"Vypínání..."</string>
+ <string name="shutdown_confirm">"Váš telefon bude vypnut."</string>
+ <string name="no_recent_tasks">"Žádné nedávno použité aplikace."</string>
+ <string name="global_actions">"Možnosti telefonu"</string>
+ <string name="global_action_lock">"Zámek obrazovky"</string>
+ <string name="global_action_power_off">"Vypnout"</string>
+ <string name="global_action_toggle_silent_mode">"Tichý režim"</string>
+ <string name="global_action_silent_mode_on_status">"Zvuk je VYPNUTÝ."</string>
+ <string name="global_action_silent_mode_off_status">"Zvuk je zapnutý"</string>
+ <string name="global_actions_toggle_airplane_mode">"Režim V letadle"</string>
+ <string name="global_actions_airplane_mode_on_status">"Režim V letadle je ZAPNUTÝ"</string>
+ <string name="global_actions_airplane_mode_off_status">"Režim V letadle je VYPNUTÝ"</string>
+ <string name="safeMode">"Nouzový režim"</string>
+ <string name="android_system_label">"Systém Android"</string>
+ <string name="permgrouplab_costMoney">"Zpoplatněné služby"</string>
+ <string name="permgroupdesc_costMoney">"Umožňuje aplikacím provádět činnosti, které vás mohou stát peníze."</string>
+ <string name="permgrouplab_messages">"Vaše zprávy"</string>
+ <string name="permgroupdesc_messages">"Čtení a zápis zpráv SMS, e-mailů a dalších zpráv."</string>
+ <string name="permgrouplab_personalInfo">"Vaše osobní informace"</string>
+ <string name="permgroupdesc_personalInfo">"Přímý přístup k vašim kontaktům a kalendáři v telefonu."</string>
+ <string name="permgrouplab_location">"Vaše poloha"</string>
+ <string name="permgroupdesc_location">"Sleduje vaši fyzickou polohu"</string>
+ <string name="permgrouplab_network">"Síťová komunikace"</string>
+ <string name="permgroupdesc_network">"Umožňuje aplikacím získat přístup k různým funkcím sítě."</string>
+ <string name="permgrouplab_accounts">"Vaše účty Google"</string>
+ <string name="permgroupdesc_accounts">"Přístup k dostupným účtům Google."</string>
+ <string name="permgrouplab_hardwareControls">"Řízení hardwaru"</string>
+ <string name="permgroupdesc_hardwareControls">"Přímý přístup k hardwaru telefonu."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonní hovory"</string>
+ <string name="permgroupdesc_phoneCalls">"Sledování, záznam a zpracování telefonních hovorů."</string>
+ <string name="permgrouplab_systemTools">"Systémové nástroje"</string>
+ <string name="permgroupdesc_systemTools">"Nízkoúrovňový přístup a kontrola nad systémem."</string>
+ <string name="permgrouplab_developmentTools">"Nástroje pro vývojáře"</string>
+ <string name="permgroupdesc_developmentTools">"Funkce pouze pro vývojáře aplikací"</string>
+ <string name="permgrouplab_storage">"Úložiště"</string>
+ <string name="permgroupdesc_storage">"Přístup ke kartě SD."</string>
+ <string name="permlab_statusBar">"zakázání či změny stavového řádku"</string>
+ <string name="permdesc_statusBar">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
+ <string name="permlab_expandStatusBar">"rozbalení a sbalení stavového řádku"</string>
+ <string name="permdesc_expandStatusBar">"Umožňuje aplikaci rozbalit či sbalit stavový řádek."</string>
+ <string name="permlab_processOutgoingCalls">"zachycení odchozích hovorů"</string>
+ <string name="permdesc_processOutgoingCalls">"Umožňuje aplikaci zpracovat odchozí hovory a změnit číslo, které má být vytočeno. Škodlivé aplikace mohou sledovat či přesměrovat odchozí hovory nebo jim zabránit."</string>
+ <string name="permlab_receiveSms">"příjem zpráv SMS"</string>
+ <string name="permdesc_receiveSms">"Umožňuje aplikaci přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_receiveMms">"příjem zpráv MMS"</string>
+ <string name="permdesc_receiveMms">"Umožňuje aplikaci přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_sendSms">"odesílat zprávy SMS"</string>
+ <string name="permdesc_sendSms">"Umožňuje aplikaci odesílat zprávy SMS. Škodlivé aplikace mohou bez vašeho potvrzení odesílat zpoplatněné zprávy."</string>
+ <string name="permlab_readSms">"čtení zpráv SMS a MMS"</string>
+ <string name="permdesc_readSms">"Umožňuje aplikaci číst zprávy SMS uložené ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou načíst vaše soukromé zprávy."</string>
+ <string name="permlab_writeSms">"úprava zpráv SMS a MMS"</string>
+ <string name="permdesc_writeSms">"Umožňuje aplikaci zapisovat do zpráv SMS uložených ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou smazat vaše zprávy."</string>
+ <string name="permlab_receiveWapPush">"příjem WAP"</string>
+ <string name="permdesc_receiveWapPush">"Umožňuje aplikaci přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_getTasks">"načtení spuštěných aplikací"</string>
+ <string name="permdesc_getTasks">"Umožňuje aplikaci načíst informace o aktuálně a nedávno spuštěných úlohách. Toto nastavení může škodlivým aplikacím umožnit odhalení soukromých informací o jiných aplikacích."</string>
+ <string name="permlab_reorderTasks">"změna uspořádání spuštěných aplikací"</string>
+ <string name="permdesc_reorderTasks">"Umožňuje aplikaci přesouvat úlohy do popředí či pozadí. Škodlivé aplikace mohou vynutit své přesunutí do popředí bez vašeho přičinění."</string>
+ <string name="permlab_setDebugApp">"povolit ladění aplikací"</string>
+ <string name="permdesc_setDebugApp">"Umožňuje aplikaci povolit ladění jiné aplikace. Škodlivé aplikace mohou pomocí tohoto nastavení ukončit jiné aplikace."</string>
+ <string name="permlab_changeConfiguration">"změny vašeho nastavení uživatelského rozhraní"</string>
+ <string name="permdesc_changeConfiguration">"Umožňuje aplikaci změnit aktuální konfiguraci, např. národní prostředí či obecnou velikost písma."</string>
+ <string name="permlab_restartPackages">"restartování ostatních aplikací"</string>
+ <string name="permdesc_restartPackages">"Umožňuje aplikaci vynutit restartování jiných aplikací."</string>
+ <string name="permlab_forceBack">"vynucení zavření aplikace"</string>
+ <string name="permdesc_forceBack">"Umožňuje aplikaci vynutit zavření a přesunutí libovolné činnosti v popředí na pozadí. Běžné aplikace by toto nastavení neměly nikdy využívat."</string>
+ <string name="permlab_dump">"načtení interního stavu systému"</string>
+ <string name="permdesc_dump">"Umožňuje aplikaci načíst interní stav systému. Škodlivé aplikace mohou načíst řádu soukromých a zabezpečených informací, které by nikdy neměly potřebovat."</string>
+ <string name="permlab_shutdown">"Částečné vypnutí"</string>
+ <string name="permdesc_shutdown">"Uvede správce činností do vypnutého stavu. Nedojde však k úplnému vypnutí."</string>
+ <string name="permlab_stopAppSwitches">"Zabránit přepínání aplikací"</string>
+ <string name="permdesc_stopAppSwitches">"Zabrání uživateli přepnout na jinou aplikaci."</string>
+ <string name="permlab_runSetActivityWatcher">"sledování a řízení spouštění všech aplikací"</string>
+ <string name="permdesc_runSetActivityWatcher">"Umožňuje aplikaci sledovat a řídit spouštění činností systémem. Škodlivé aplikace mohou zcela ovládnout systém. Toto oprávnění je zapotřebí pouze pro účely vývoje, nikdy pro běžné použití telefonu."</string>
+ <string name="permlab_broadcastPackageRemoved">"odeslání vysílání o odstranění balíčku"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Umožňuje aplikaci vysílat oznámení o odstranění balíčku aplikace. Škodlivé aplikace mohou pomocí tohoto nastavení ukončit libovolnou další spuštěnou aplikaci."</string>
+ <string name="permlab_broadcastSmsReceived">"odeslání vysílání o přijaté zprávě SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou pomocí tohoto nastavení falšovat příchozí zprávy SMS."</string>
+ <string name="permlab_broadcastWapPush">"odeslání vysílání typu WAP-PUSH-received"</string>
+ <string name="permdesc_broadcastWapPush">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy WAP PUSH. Škodlivé aplikace mohou pomocí tohoto nastavení zfalšovat výpis o doručení zprávy MMS nebo nepozorovaně nahradit obsah jakékoli webové stránky škodlivým obsahem."</string>
+ <string name="permlab_setProcessLimit">"omezení počtu spuštěných procesů"</string>
+ <string name="permdesc_setProcessLimit">"Umožňuje aplikaci řídit maximální počet spuštěných procesů. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
+ <string name="permlab_setAlwaysFinish">"zavření všech aplikací na pozadí"</string>
+ <string name="permdesc_setAlwaysFinish">"Umožňuje aplikaci ovládat, zda jsou činnosti vždy dokončeny po přesunutí do pozadí. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
+ <string name="permlab_batteryStats">"změna statistických údajů o baterii"</string>
+ <string name="permdesc_batteryStats">"Umožňuje změnu shromážděných statistických údajů o baterii. Není určeno pro běžné aplikace."</string>
+ <string name="permlab_backup">"Ovládat zálohování a obnovu systému"</string>
+ <string name="permdesc_backup">"Umožňuje aplikaci ovládat mechanizmus zálohování a obnovy systému. Není určeno k použití v běžných aplikacích."</string>
+ <string name="permlab_internalSystemWindow">"zobrazení nepovolených oken"</string>
+ <string name="permdesc_internalSystemWindow">"Umožňuje vytvoření oken, která mají být použita interním systémem uživatelského rozhraní. Běžné aplikace toto nastavení nepoužívají."</string>
+ <string name="permlab_systemAlertWindow">"zobrazení upozornění systémové úrovně"</string>
+ <string name="permdesc_systemAlertWindow">"Umožňuje aplikaci zobrazit okna s výstrahami systému. Škodlivé aplikace mohou převzít kontrolu nad celou obrazovkou telefonu."</string>
+ <string name="permlab_setAnimationScale">"globální změny rychlosti animace"</string>
+ <string name="permdesc_setAnimationScale">"Umožňuje aplikaci kdykoli globálně změnit rychlost animace (rychlejší či pomalejší animace)."</string>
+ <string name="permlab_manageAppTokens">"správa tokenů aplikací"</string>
+ <string name="permdesc_manageAppTokens">"Umožňuje aplikaci vytvořit a spravovat své vlastní tokeny a obejít jejich obvyklé řazení typu Z. Toto nastavení by nikdy nemělo být potřeba pro běžné aplikace."</string>
+ <string name="permlab_injectEvents">"používání kláves a tlačítek"</string>
+ <string name="permdesc_injectEvents">"Umožňuje aplikaci doručit své vlastní vstupní události (stisknutí tlačítek, apod.) dalším aplikacím. Škodlivé aplikace mohou pomocí tohoto nastavení převzít kontrolu nad telefonem."</string>
+ <string name="permlab_readInputState">"zaznamenání psaného textu a prováděných činností"</string>
+ <string name="permdesc_readInputState">"Umožňuje aplikacím sledovat, které klávesy používáte, a to i při práci s jinými aplikacemi (například při zadávání hesla). Běžné aplikace by toto nastavení nikdy neměly vyžadovat."</string>
+ <string name="permlab_bindInputMethod">"vazba k metodě zadávání dat"</string>
+ <string name="permdesc_bindInputMethod">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
+ <string name="permlab_setOrientation">"změna orientace obrazovky"</string>
+ <string name="permdesc_setOrientation">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
+ <string name="permlab_signalPersistentProcesses">"odeslání signálů Linux aplikacím"</string>
+ <string name="permdesc_signalPersistentProcesses">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
+ <string name="permlab_persistentActivity">"trvalé spuštění aplikace"</string>
+ <string name="permdesc_persistentActivity">"Umožňuje aplikaci učinit své části trvalými, takže je systém nemůže použít pro jiné aplikace."</string>
+ <string name="permlab_deletePackages">"smazání aplikací"</string>
+ <string name="permdesc_deletePackages">"Umožňuje aplikaci smazat balíčky systému Android. Škodlivé aplikace mohou pomocí tohoto nastavení smazat důležité aplikace."</string>
+ <string name="permlab_clearAppUserData">"smazání dat ostatních aplikací"</string>
+ <string name="permdesc_clearAppUserData">"Umožňuje aplikaci smazat data uživatele."</string>
+ <string name="permlab_deleteCacheFiles">"smazání mezipaměti ostatních aplikací"</string>
+ <string name="permdesc_deleteCacheFiles">"Umožňuje aplikaci smazat soubory v mezipaměti."</string>
+ <string name="permlab_getPackageSize">"výpočet místa pro ukládání aplikací"</string>
+ <string name="permdesc_getPackageSize">"Umožňuje aplikaci načtení svého kódu, dat a velikostí mezipaměti"</string>
+ <string name="permlab_installPackages">"přímá instalace aplikací"</string>
+ <string name="permdesc_installPackages">"Umožňuje aplikaci nainstalovat nové či aktualizované balíčky systému Android. Škodlivé aplikace mohou pomocí tohoto nastavení přidat nové aplikace s libovolnými oprávněními."</string>
+ <string name="permlab_clearAppCache">"smazání všech dat v mezipaměti aplikace"</string>
+ <string name="permdesc_clearAppCache">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string>
+ <string name="permlab_readLogs">"čtení systémových souborů protokolu"</string>
+ <string name="permdesc_readLogs">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, ale neměly by obsahovat žádné osobní či soukromé informace."</string>
+ <string name="permlab_diagnostic">"čtení nebo zápis do prostředků funkce diag"</string>
+ <string name="permdesc_diagnostic">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat pouze výrobce či operátor pro diagnostiku hardwaru."</string>
+ <string name="permlab_changeComponentState">"povolení či zakázání komponent aplikací"</string>
+ <string name="permdesc_changeComponentState">"Umožňuje aplikaci změnit, zda je komponenta jiné aplikace povolena nebo ne. Škodlivé aplikace mohou pomocí tohoto nastavení vypnout důležité funkce telefonu. Je třeba postupovat opatrně, protože je možné způsobit nepoužitelnost, nekonzistenci či nestabilitu komponent aplikací."</string>
+ <string name="permlab_setPreferredApplications">"nastavení upřednostňovaných aplikací"</string>
+ <string name="permdesc_setPreferredApplications">"Umožňuje aplikaci změnit vaše upřednostňované aplikace. Toto nastavení může škodlivým aplikacím umožnit nepozorovaně změnit spouštěné aplikace a oklamat vaše existující aplikace tak, aby shromažďovaly vaše soukromá data."</string>
+ <string name="permlab_writeSettings">"změny globálních nastavení systému"</string>
+ <string name="permdesc_writeSettings">"Umožňuje aplikaci upravit data nastavení systému. Škodlivé aplikace mohou poškodit konfiguraci vašeho systému."</string>
+ <string name="permlab_writeSecureSettings">"změny zabezpečených nastavení systému"</string>
+ <string name="permdesc_writeSecureSettings">"Umožňuje aplikaci změnit data zabezpečených nastavení systému. Běžné aplikace toto nastavení nevyužívají."</string>
+ <string name="permlab_writeGservices">"změny mapy služeb Google"</string>
+ <string name="permdesc_writeGservices">"Umožňuje aplikaci změnit mapu služeb Google. Běžné aplikace toto nastavení nevyužívají."</string>
+ <string name="permlab_receiveBootCompleted">"automatické spuštění při startu"</string>
+ <string name="permdesc_receiveBootCompleted">"Umožňuje aplikaci spuštění ihned po spuštění systému. Toto nastavení může zpomalit spuštění telefonu a umožnit aplikaci celkově zpomalit telefon, protože bude neustále spuštěna."</string>
+ <string name="permlab_broadcastSticky">"odeslání trvalého vysílání"</string>
+ <string name="permdesc_broadcastSticky">"Umožňuje aplikaci odeslat trvalá vysílání, která přetrvávají i po skončení vysílání. Škodlivé aplikace mohou telefon zpomalit či způsobit jeho nestabilitu, protože bude používat příliš mnoho paměti."</string>
+ <string name="permlab_readContacts">"čtení dat kontaktů"</string>
+ <string name="permdesc_readContacts">"Umožňuje aplikaci načíst všechna data kontaktů (adresy) uložená ve vašem telefonu. Škodlivé aplikace poté mohou dalším lidem odeslat vaše data."</string>
+ <string name="permlab_writeContacts">"zápis dat kontaktů"</string>
+ <string name="permdesc_writeContacts">"Umožňuje aplikaci změnit kontaktní údaje (adresu) uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit kontaktní údaje."</string>
+ <string name="permlab_writeOwnerData">"zápis informací o vlastníkovi"</string>
+ <string name="permdesc_writeOwnerData">"Umožňuje aplikaci změnit informace o vlastníkovi telefonu uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit informace o vlastníkovi."</string>
+ <string name="permlab_readOwnerData">"čtení informací o vlastníkovi"</string>
+ <string name="permdesc_readOwnerData">"Umožňuje aplikaci číst informace o vlastníkovi telefonu uložená v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení načíst informace o vlastníkovi."</string>
+ <string name="permlab_readCalendar">"čtení dat kalendáře"</string>
+ <string name="permdesc_readCalendar">"Umožňuje aplikaci načíst všechny události kalendáře uložené ve vašem telefonu. Škodlivé aplikace poté mohou dalším lidem odeslat události z vašeho kalendáře."</string>
+ <string name="permlab_writeCalendar">"zápis dat kalendáře"</string>
+ <string name="permdesc_writeCalendar">"Umožňuje aplikaci změnit události kalendáře uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit vaše data v kalendáři."</string>
+ <string name="permlab_accessMockLocation">"simulace zdrojů polohy pro účely testování"</string>
+ <string name="permdesc_accessMockLocation">"Vytváří simulované zdroje polohy pro účely testování. Škodlivé aplikace mohou pomocí tohoto nastavení změnit polohu či stav vrácený zdroji skutečné polohy, jako je např. jednotka GPS či poskytovatelé sítě."</string>
+ <string name="permlab_accessLocationExtraCommands">"přístup k dalším příkazům poskytovatele polohy"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Umožňuje získat přístup k dalším příkazům poskytovatele polohy. Škodlivé aplikace mohou pomocí tohoto nastavení narušit funkci GPS či jiných zdrojů polohy."</string>
+ <string name="permlab_installLocationProvider">"Oprávnění k instalaci poskytovatele polohy"</string>
+ <string name="permdesc_installLocationProvider">"Vytvořit simulace zdrojů polohy pro účely testování. Škodlivé aplikace mohou toto nastavení využít k přepsání polohy nebo stavu vráceného zdroji skutečné polohy, například systémem GPS nebo poskytovateli sítí. Mohou také monitorovat polohu a ohlásit ji externímu zdroji."</string>
+ <string name="permlab_accessFineLocation">"upřesnění polohy (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Umožňuje aplikaci přístup ke zdrojům přesné polohy v telefonu, jako je například systém GPS, je-li k dispozici. Škodlivé aplikace mohou pomocí tohoto nastavení zjistit vaši polohu a mohou zvýšit spotřebu baterie."</string>
+ <string name="permlab_accessCoarseLocation">"přibližná poloha (pomocí sítě)"</string>
+ <string name="permdesc_accessCoarseLocation">"Umožňuje získat přístup ke zdrojům přibližné polohy, jako je například databáze mobilní sítě, je-li k dispozici, a určit přibližnou pozici telefonu. Škodlivé aplikace takto mohou zjistit, kde se přibližně nacházíte."</string>
+ <string name="permlab_accessSurfaceFlinger">"přístup ke službě SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"čtení vyrovnávací paměti snímků"</string>
+ <string name="permdesc_readFrameBuffer">"Umožňuje aplikaci načíst obsah vyrovnávací paměti snímků."</string>
+ <string name="permlab_modifyAudioSettings">"změna vašeho nastavení zvuku"</string>
+ <string name="permdesc_modifyAudioSettings">"Umožňuje aplikaci změnit globální nastavení zvuku, například hlasitost či směrování."</string>
+ <string name="permlab_recordAudio">"nahrání zvuku"</string>
+ <string name="permdesc_recordAudio">"Umožňuje aplikaci získat přístup k nahrávání zvuku."</string>
+ <string name="permlab_camera">"pořizování fotografií"</string>
+ <string name="permdesc_camera">"Umožňuje aplikaci pořizovat fotografie pomocí fotoaparátu. Toto nastavení aplikaci umožní shromažďovat fotografie toho, na co je zrovna fotoaparát namířen."</string>
+ <string name="permlab_brick">"trvalé vypnutí telefonu"</string>
+ <string name="permdesc_brick">"Umožňuje aplikaci trvale vypnout celý telefon. Toto je velmi nebezpečné nastavení."</string>
+ <string name="permlab_reboot">"vynucení restartování telefonu"</string>
+ <string name="permdesc_reboot">"Umožňuje aplikaci vynutit restartování telefonu."</string>
+ <string name="permlab_mount_unmount_filesystems">"připojení a odpojení souborových systémů"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Umožňuje aplikaci připojit či odpojit souborové systémy ve vyměnitelných úložištích."</string>
+ <string name="permlab_mount_format_filesystems">"formátovat externí úložiště"</string>
+ <string name="permdesc_mount_format_filesystems">"Umožňuje aplikaci formátovat vyměnitelná úložiště."</string>
+ <string name="permlab_vibrate">"ovládání vibrací"</string>
+ <string name="permdesc_vibrate">"Umožňuje aplikaci ovládat vibrace."</string>
+ <string name="permlab_flashlight">"ovládání kontrolky"</string>
+ <string name="permdesc_flashlight">"Umožňuje aplikaci ovládat kontrolku."</string>
+ <string name="permlab_hardware_test">"testování hardwaru"</string>
+ <string name="permdesc_hardware_test">"Umožňuje aplikaci ovládat různé periferie pro účely testování hardwaru."</string>
+ <string name="permlab_callPhone">"přímé volání na telefonní čísla"</string>
+ <string name="permdesc_callPhone">"Umožňuje aplikaci bez vašeho zásahu volat na telefonní čísla. Škodlivé aplikace mohou na váš telefonní účet připsat neočekávané hovory. Toto nastavení aplikaci neumožňuje volat na tísňové linky."</string>
+ <string name="permlab_callPrivileged">"přímé volání na libovolná telefonní čísla"</string>
+ <string name="permdesc_callPrivileged">"Umožňuje aplikaci bez vašeho zásahu vytočit jakékoli telefonní číslo, včetně čísel tísňového volání. Škodlivé aplikace mohou provádět zbytečná a nezákonná volání na tísňové linky."</string>
+ <string name="permlab_locationUpdates">"ovládání oznámení o aktualizaci polohy"</string>
+ <string name="permdesc_locationUpdates">"Umožňuje povolit či zakázat aktualizace polohy prostřednictvím bezdrátového připojení. Aplikace toto nastavení obvykle nepoužívají."</string>
+ <string name="permlab_checkinProperties">"přístup k vlastnostem Checkin"</string>
+ <string name="permdesc_checkinProperties">"Umožňuje čtení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."</string>
+ <string name="permlab_bindGadget">"zvolit widgety"</string>
+ <string name="permdesc_bindGadget">"Umožňuje aplikaci sdělit systému, které aplikace mohou používat které widgety. Aplikace s tímto oprávněním mohou zpřístupnit osobní údaje jiným aplikacím. Není určeno pro běžné aplikace."</string>
+ <string name="permlab_modifyPhoneState">"změny stavu telefonu"</string>
+ <string name="permdesc_modifyPhoneState">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním může přepínat sítě nebo zapnout či vypnout bezdrátové připojení telefonu bez vašeho svolení."</string>
+ <string name="permlab_readPhoneState">"zjistit stav telefonu"</string>
+ <string name="permdesc_readPhoneState">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Aplikace s tímto oprávněním mohou určit telefonní číslo tohoto telefonu, zda zrovna probíhá hovor, spojené telefonní číslo a podobně."</string>
+ <string name="permlab_wakeLock">"zabránění přechodu telefonu do režimu spánku"</string>
+ <string name="permdesc_wakeLock">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
+ <string name="permlab_devicePower">"zapnutí či vypnutí telefonu"</string>
+ <string name="permdesc_devicePower">"Umožňuje aplikaci zapnout či vypnout telefon."</string>
+ <string name="permlab_factoryTest">"spuštění v režimu továrního testu"</string>
+ <string name="permdesc_factoryTest">"Umožňuje aplikaci spuštění v režimu nízkoúrovňového testu výrobce a povolí přístup k hardwaru telefonu. K dispozici pouze, je-li telefon spuštěn v režimu testování výrobce."</string>
+ <string name="permlab_setWallpaper">"nastavení tapety"</string>
+ <string name="permdesc_setWallpaper">"Umožňuje aplikaci nastavit tapetu systému."</string>
+ <string name="permlab_setWallpaperHints">"nastavení nápovědy pro velikost tapety"</string>
+ <string name="permdesc_setWallpaperHints">"Umožňuje aplikaci nastavit nápovědu pro velikost tapety systému."</string>
+ <string name="permlab_masterClear">"obnovení továrního nastavení systému"</string>
+ <string name="permdesc_masterClear">"Umožňuje aplikaci kompletně obnovit systém do továrního nastavení a vymazat všechna data, konfiguraci a nainstalované aplikace."</string>
+ <string name="permlab_setTimeZone">"nastavení časového pásma"</string>
+ <string name="permdesc_setTimeZone">"Umožňuje aplikaci změnit časové pásmo telefonu."</string>
+ <string name="permlab_getAccounts">"odhalení známých účtů"</string>
+ <string name="permdesc_getAccounts">"Umožňuje aplikaci získat seznam účtů v telefonu."</string>
+ <string name="permlab_accessNetworkState">"zobrazení stavu sítě"</string>
+ <string name="permdesc_accessNetworkState">"Umožňuje aplikaci zobrazit stav všech sítí."</string>
+ <string name="permlab_createNetworkSockets">"plný přístup k Internetu"</string>
+ <string name="permdesc_createNetworkSockets">"Umožňuje aplikaci vytvořit síťové sokety."</string>
+ <string name="permlab_writeApnSettings">"zápis nastavení pro název přístupového bodu (APN)"</string>
+ <string name="permdesc_writeApnSettings">"Umožňuje aplikaci změnit nastavení APN, jako je například proxy či port APN."</string>
+ <string name="permlab_changeNetworkState">"změna připojení k síti"</string>
+ <string name="permdesc_changeNetworkState">"Umožňuje aplikaci změnit stav připojení k síti."</string>
+ <string name="permlab_changeBackgroundDataSetting">"změnit nastavení použití dat na pozadí"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Umožňuje aplikaci změnit nastavení použití dat na pozadí."</string>
+ <string name="permlab_accessWifiState">"zobrazení stavu WiFi"</string>
+ <string name="permdesc_accessWifiState">"Umožňuje aplikaci zobrazit informace o stavu připojení WiFi."</string>
+ <string name="permlab_changeWifiState">"Změnit stav WiFi"</string>
+ <string name="permdesc_changeWifiState">"Umožňuje aplikaci připojit se k přístupovým bodům WiFi či se od nich odpojit a provádět změny nakonfigurovaných sítí WiFi."</string>
+ <string name="permlab_changeWifiMulticastState">"Povolit příjem Wi-Fi Multicast"</string>
+ <string name="permdesc_changeWifiMulticastState">"Povoluje aplikaci přijímat pakety, které nebyly adresovány přímo vašemu zařízení. Pomocí této možnosti můžete objevit služby nabízené ve vaší blízkosti. Spotřeba energie je vyšší než u režimu bez vícesměrového vysílání (multicast)."</string>
+ <string name="permlab_bluetoothAdmin">"správa rozhraní Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Umožňuje aplikaci konfigurovat místní telefon s rozhraním Bluetooth a vyhledávat a párovat vzdálená zařízení."</string>
+ <string name="permlab_bluetooth">"vytvoření připojení Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Umožňuje aplikaci zobrazit konfiguraci místního telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
+ <string name="permlab_disableKeyguard">"vypnutí zámku kláves"</string>
+ <string name="permdesc_disableKeyguard">"Umožňuje aplikaci vypnout zámek kláves a související zabezpečení heslem. Příkladem oprávněného použití této funkce je vypnutí zámku klávesnice při příchozím hovoru a jeho opětovné zapnutí po skončení hovoru."</string>
+ <string name="permlab_readSyncSettings">"čtení nastavení synchronizace"</string>
+ <string name="permdesc_readSyncSettings">"Umožňuje aplikaci načíst nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
+ <string name="permlab_writeSyncSettings">"zápis nastavení synchronizace"</string>
+ <string name="permdesc_writeSyncSettings">"Umožňuje aplikaci změnit nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
+ <string name="permlab_readSyncStats">"čtení statistických údajů o synchronizaci"</string>
+ <string name="permdesc_readSyncStats">"Umožňuje aplikaci číst statistické informace o synchronizaci, např. historii proběhlých synchronizací."</string>
+ <string name="permlab_subscribedFeedsRead">"čtení zdrojů přihlášených k odběru"</string>
+ <string name="permdesc_subscribedFeedsRead">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
+ <string name="permlab_subscribedFeedsWrite">"zápis odebíraných zdrojů"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
+ <string name="permlab_readDictionary">"číst slovník definovaný uživatelem"</string>
+ <string name="permdesc_readDictionary">"Umožní aplikaci číst soukromá slova, jména a fráze, která uživatel mohl uložit do svého slovníku."</string>
+ <string name="permlab_writeDictionary">"zapisovat do slovníku definovaného uživatelem"</string>
+ <string name="permdesc_writeDictionary">"Umožní aplikaci zapisovat nová slova do uživatelského slovníku."</string>
+ <string name="permlab_sdcardWrite">"Změnit/smazat obsah karty SD"</string>
+ <string name="permdesc_sdcardWrite">"Umožní aplikaci zápis na kartu SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Domů"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Práce"</item>
- <item msgid="1103601433382158155">"Pracovní fax"</item>
- <item msgid="1735177144948329370">"Fax domů"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Ostatní"</item>
- <item msgid="9192514806975898961">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Mobil"</item>
+ <item>"Práce"</item>
+ <item>"Pracovní fax"</item>
+ <item>"Fax domů"</item>
+ <item>"Pager"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Domů"</item>
- <item msgid="7084237356602625604">"Práce"</item>
- <item msgid="1112044410659011023">"Ostatní"</item>
- <item msgid="2374913952870110618">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobilní"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Domů"</item>
- <item msgid="5629153956045109251">"Práce"</item>
- <item msgid="4966604264500343469">"Ostatní"</item>
- <item msgid="4932682847595299369">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Domů"</item>
- <item msgid="1359644565647383708">"Práce"</item>
- <item msgid="7868549401053615677">"Ostatní"</item>
- <item msgid="3145118944639869809">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Práce"</item>
- <item msgid="4378074129049520373">"Ostatní"</item>
- <item msgid="3455047468583965104">"Vlastní"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo!"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo!"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Zadejte kód PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Nesprávný kód PIN"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Číslo tísňové linky"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Není signál)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Obrazovka uzamčena."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Telefon odemknete stisknutím tlačítka Menu."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Odblokujte pomocí gesta"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Tísňové volání"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Správně!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Zkuste to prosím znovu"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Nabíjení (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Nabito."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Připojte dobíjecí zařízení."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Není vložena SIM karta."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"V telefonu není žádná karta SIM."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Prosím vložte kartu SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Síť je blokována"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Karta SIM je zablokována pomocí kódu PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Další informace naleznete v uživatelské příručce, nebo kontaktujte podporu zákazníků."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM je zablokována."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokování karty SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své bezpečnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení do účtu Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomněli jste gesto?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Gesta: Příliš mnoho pokusů"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Uživatelské jméno (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Heslo"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Přihlásit se"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neplatné uživatelské jméno nebo heslo."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazat"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Nabíjení..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Prosím připojte dobíjecí zařízení"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Baterie je vybitá:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"zbývá méně než <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Proč?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Test továrního nastavení se nezdařil"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Test FACTORY_TEST lze provést pouze u balíčků nainstalovaných ve složce /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nebyl nalezen žádný balíček umožňující test FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Restartovat"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li na stránce zůstat."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Čtení historie a záložek prohlížeče"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umožňuje aplikaci číst všechny navštívené adresy URL a záložky prohlížeče."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Zapisovat historii a záložky prohlížeče"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Umožní aplikaci změnit historii či záložky prohlížeče uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit data prohlížeče."</string>
- <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nikdy"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Nemáte povolení otevřít tuto stránku."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text byl zkopírován do schránky."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Více"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mezerník"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"smazat"</string>
- <string name="search_go" msgid="8298016669822141719">"Hledat"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
+ <string name="keyguard_password_enter_pin_code">"Zadejte kód PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Nesprávný kód PIN"</string>
+ <string name="keyguard_label_text">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Číslo tísňové linky"</string>
+ <string name="lockscreen_carrier_default">"(Není signál)"</string>
+ <string name="lockscreen_screen_locked">"Obrazovka uzamčena."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Telefon odemknete stisknutím tlačítka Menu."</string>
+ <string name="lockscreen_pattern_instructions">"Odblokujte pomocí gesta"</string>
+ <string name="lockscreen_emergency_call">"Tísňové volání"</string>
+ <string name="lockscreen_pattern_correct">"Správně!"</string>
+ <string name="lockscreen_pattern_wrong">"Zkuste to prosím znovu"</string>
+ <string name="lockscreen_plugged_in">"Nabíjení (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Připojte dobíjecí zařízení."</string>
+ <string name="lockscreen_missing_sim_message_short">"Není vložena SIM karta."</string>
+ <string name="lockscreen_missing_sim_message">"V telefonu není žádná karta SIM."</string>
+ <string name="lockscreen_missing_sim_instructions">"Prosím vložte kartu SIM."</string>
+ <string name="lockscreen_network_locked_message">"Síť je blokována"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Karta SIM je zablokována pomocí kódu PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Další informace naleznete v uživatelské příručce, nebo kontaktujte podporu zákazníků."</string>
+ <string name="lockscreen_sim_locked_message">"Karta SIM je zablokována."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Odblokování karty SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své bezpečnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení do účtu Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Zapomněli jste gesto?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Gesta: Příliš mnoho pokusů"</string>
+ <string name="lockscreen_glogin_instructions">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Uživatelské jméno (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Heslo"</string>
+ <string name="lockscreen_glogin_submit_button">"Přihlásit se"</string>
+ <string name="lockscreen_glogin_invalid_input">"Neplatné uživatelské jméno nebo heslo."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Žádná oznámení"</string>
+ <string name="status_bar_ongoing_events_title">"Probíhající"</string>
+ <string name="status_bar_latest_events_title">"Oznámení"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Nabíjení..."</string>
+ <string name="battery_low_title">"Prosím připojte dobíjecí zařízení"</string>
+ <string name="battery_low_subtitle">"Baterie je vybitá:"</string>
+ <string name="battery_low_percent_format">"zbývá méně než <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Proč?"</string>
+ <string name="factorytest_failed">"Test továrního nastavení se nezdařil"</string>
+ <string name="factorytest_not_system">"Test FACTORY_TEST lze provést pouze u balíčků nainstalovaných ve složce /system/app."</string>
+ <string name="factorytest_no_action">"Nebyl nalezen žádný balíček umožňující test FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Restartovat"</string>
+ <string name="js_dialog_title">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li na stránce zůstat."</string>
+ <string name="save_password_label">"Potvrdit"</string>
+ <string name="permlab_readHistoryBookmarks">"Čtení historie a záložek prohlížeče"</string>
+ <string name="permdesc_readHistoryBookmarks">"Umožňuje aplikaci číst všechny navštívené adresy URL a záložky prohlížeče."</string>
+ <string name="permlab_writeHistoryBookmarks">"Zapisovat historii a záložky prohlížeče"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Umožní aplikaci změnit historii či záložky prohlížeče uložené v telefonu. Škodlivé aplikace mohou pomocí tohoto nastavení vymazat či pozměnit data prohlížeče."</string>
+ <string name="save_password_message">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
+ <string name="save_password_notnow">"Nyní ne"</string>
+ <string name="save_password_remember">"Zapamatovat"</string>
+ <string name="save_password_never">"Nikdy"</string>
+ <string name="open_permission_deny">"Nemáte povolení otevřít tuto stránku."</string>
+ <string name="text_copied">"Text byl zkopírován do schránky."</string>
+ <string name="more_item_label">"Více"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"mezerník"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"smazat"</string>
+ <string name="search_go">"Hledat"</string>
+ <string name="oneMonthDurationPast">"před 1 měsícem"</string>
+ <string name="beforeOneMonthDurationPast">"Déle než před 1 měsícem"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
- <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ <item quantity="one">"před 1 sekundou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> sek."</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"před 1 minutou"</item>
- <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"před 1 minutou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"před 1 hodinou"</item>
- <item quantity="other" msgid="2467273239587587569">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"před 1 hodinou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"včera"</item>
- <item quantity="other" msgid="2479586466153314633">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
+ <item quantity="one">"včera"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"za 1 sekundu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"za 1 minutu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"za 1 hodinu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"zítra"</item>
- <item quantity="other" msgid="5109449375100953247">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ <item quantity="one">"zítra"</item>
+ <item quantity="other">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"před 1 s"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"před 1 min."</item>
- <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"před 1 min."</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"před 1 hodinou"</item>
- <item quantity="other" msgid="6889970745748538901">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"před 1 hodinou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"včera"</item>
- <item quantity="other" msgid="3453342639616481191">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
+ <item quantity="one">"včera"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"za 1 s"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"za 1 min."</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"za 1 hodinu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"zítra"</item>
- <item quantity="other" msgid="2973062968038355991">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ <item quantity="one">"zítra"</item>
+ <item quantity="other">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"v roce %s"</string>
- <string name="day" msgid="8144195776058119424">"den"</string>
- <string name="days" msgid="4774547661021344602">"d."</string>
- <string name="hour" msgid="2126771916426189481">"hodina"</string>
- <string name="hours" msgid="894424005266852993">"hod."</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"týden"</string>
- <string name="weeks" msgid="6509623834583944518">"týd."</string>
- <string name="year" msgid="4001118221013892076">"rokem"</string>
- <string name="years" msgid="6881577717993213522">"lety"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Každý pracovní den (Po – Pá)"</string>
- <string name="daily" msgid="5738949095624133403">"Denně"</string>
- <string name="weekly" msgid="983428358394268344">"Každý týden v <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Měsíčně"</string>
- <string name="yearly" msgid="1519577999407493836">"Ročně"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video nelze přehrát"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Omlouváme se, ale toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Toto video bohužel nelze přehrát."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"poledne"</string>
- <string name="Noon" msgid="3342127745230013127">"Poledne"</string>
- <string name="midnight" msgid="7166259508850457595">"půlnoc"</string>
- <string name="Midnight" msgid="5630806906897892201">"Půlnoc"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string>
- <string name="selectText" msgid="3889149123626888637">"Označit text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zastavit označování textu"</string>
- <string name="cut" msgid="3092569408438626261">"Vyjmout"</string>
- <string name="cutAll" msgid="2436383270024931639">"Vyjmout vše"</string>
- <string name="copy" msgid="2681946229533511987">"Kopírovat"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopírovat vše"</string>
- <string name="paste" msgid="5629880836805036433">"Vložit"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopírovat adresu URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Metoda zadávání dat"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Přidat „%s“ do slovníku"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Úpravy textu"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Málo paměti"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"V telefonu zbývá málo místa pro ukládání dat."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Zrušit"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Upozornění"</string>
- <string name="capital_on" msgid="1544682755514494298">"ZAPNUTO"</string>
- <string name="capital_off" msgid="6815870386972805832">"VYPNOUT"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Dokončit akci pomocí aplikace"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto činnost."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymažte výchozí hodnoty v Nastavení plochy > Aplikace > Správa aplikací."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Vyberte akci"</string>
- <string name="noApplications" msgid="1691104391758345586">"Tuto činnost nemohou provádět žádné aplikace."</string>
- <string name="aerr_title" msgid="653922989522758100">"Omlouváme se"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neočekávaně ukončena. Zkuste to znovu."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl neočekávaně ukončen. Opakujte prosím akci."</string>
- <string name="anr_title" msgid="3100070910664756057">"Omlouváme se"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>) neodpovídá."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Služba <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Služba <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovídá."</string>
- <string name="force_close" msgid="3653416315450806396">"Ukončit aplikaci"</string>
- <string name="report" msgid="4060218260984795706">"Nahlásit"</string>
- <string name="wait" msgid="7147118217226317732">"Počkat"</string>
- <string name="debug" msgid="9103374629678531849">"Ladit"</string>
- <string name="sendText" msgid="5132506121645618310">"Vyberte činnost s textem"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitost vyzvánění"</string>
- <string name="volume_music" msgid="5421651157138628171">"Hlasitost médií"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Přehrávání pomocí rozhraní Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Hlasitost hovoru"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Hlasitost upozornění a budíku"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Hlasitost oznámení"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Hlasitost"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Výchozí vyzváněcí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Ticho"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámý vyzváněcí tón"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"v roce %s"</string>
+ <string name="day">"den"</string>
+ <string name="days">"d."</string>
+ <string name="hour">"hodina"</string>
+ <string name="hours">"hod."</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"týden"</string>
+ <string name="weeks">"týd."</string>
+ <string name="year">"rokem"</string>
+ <string name="years">"lety"</string>
+ <string name="every_weekday">"Každý pracovní den (Po – Pá)"</string>
+ <string name="daily">"Denně"</string>
+ <string name="weekly">"Každý týden v <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Měsíčně"</string>
+ <string name="yearly">"Ročně"</string>
+ <string name="VideoView_error_title">"Video nelze přehrát"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Omlouváme se, ale toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
+ <string name="VideoView_error_text_unknown">"Toto video bohužel nelze přehrát."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"poledne"</string>
+ <string name="Noon">"Poledne"</string>
+ <string name="midnight">"půlnoc"</string>
+ <string name="Midnight">"Půlnoc"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Vybrat vše"</string>
+ <string name="selectText">"Označit text"</string>
+ <string name="stopSelectingText">"Zastavit označování textu"</string>
+ <string name="cut">"Vyjmout"</string>
+ <string name="cutAll">"Vyjmout vše"</string>
+ <string name="copy">"Kopírovat"</string>
+ <string name="copyAll">"Kopírovat vše"</string>
+ <string name="paste">"Vložit"</string>
+ <string name="copyUrl">"Kopírovat adresu URL"</string>
+ <string name="inputMethod">"Metoda zadávání dat"</string>
+ <string name="addToDictionary">"Přidat „%s“ do slovníku"</string>
+ <string name="editTextMenuTitle">"Úpravy textu"</string>
+ <string name="low_internal_storage_view_title">"Málo paměti"</string>
+ <string name="low_internal_storage_view_text">"V telefonu zbývá málo místa pro ukládání dat."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Zrušit"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Zrušit"</string>
+ <string name="dialog_alert_title">"Upozornění"</string>
+ <string name="capital_on">"ZAPNUTO"</string>
+ <string name="capital_off">"VYPNOUT"</string>
+ <string name="whichApplication">"Dokončit akci pomocí aplikace"</string>
+ <string name="alwaysUse">"Použít jako výchozí nastavení pro tuto činnost."</string>
+ <string name="clearDefaultHintMsg">"Vymažte výchozí hodnoty v Nastavení plochy > Aplikace > Správa aplikací."</string>
+ <string name="chooseActivity">"Vyberte akci"</string>
+ <string name="noApplications">"Tuto činnost nemohou provádět žádné aplikace."</string>
+ <string name="aerr_title">"Omlouváme se"</string>
+ <string name="aerr_application">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neočekávaně ukončena. Zkuste to znovu."</string>
+ <string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl neočekávaně ukončen. Opakujte prosím akci."</string>
+ <string name="anr_title">"Omlouváme se"</string>
+ <string name="anr_activity_application">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>) neodpovídá."</string>
+ <string name="anr_activity_process">"Služba <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
+ <string name="anr_application_process">"Služba <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovídá."</string>
+ <string name="force_close">"Ukončit aplikaci"</string>
+ <string name="report">"Nahlásit"</string>
+ <string name="wait">"Počkat"</string>
+ <string name="debug">"Ladit"</string>
+ <string name="sendText">"Vyberte činnost s textem"</string>
+ <string name="volume_ringtone">"Hlasitost vyzvánění"</string>
+ <string name="volume_music">"Hlasitost médií"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Přehrávání pomocí rozhraní Bluetooth"</string>
+ <string name="volume_call">"Hlasitost hovoru"</string>
+ <string name="volume_bluetooth_call">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
+ <string name="volume_alarm">"Hlasitost upozornění a budíku"</string>
+ <string name="volume_notification">"Hlasitost oznámení"</string>
+ <string name="volume_unknown">"Hlasitost"</string>
+ <string name="ringtone_default">"Výchozí vyzváněcí tón"</string>
+ <string name="ringtone_default_with_actual">"Výchozí vyzváněcí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Ticho"</string>
+ <string name="ringtone_picker_title">"Vyzváněcí tóny"</string>
+ <string name="ringtone_unknown">"Neznámý vyzváněcí tón"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"K dispozici je síť WiFi."</item>
- <item quantity="other" msgid="4192424489168397386">"Jsou k dispozici sítě WiFi."</item>
+ <item quantity="one">"K dispozici je síť WiFi."</item>
+ <item quantity="other">"Jsou k dispozici sítě WiFi."</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"K dispozici je veřejná síť WiFi"</item>
- <item quantity="other" msgid="7915895323644292768">"Jsou k dispozici veřejné sítě WiFi"</item>
+ <item quantity="one">"K dispozici je veřejná síť WiFi"</item>
+ <item quantity="other">"Jsou k dispozici veřejné sítě WiFi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Neznámá aplikace"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Je odesílán velký počet zpráv SMS. Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li odesílání ukončit."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Zrušit"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Nastavit"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Výchozí"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skrýt"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Zobrazit vše"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Načítání..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB připojeno"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Připojili jste svůj telefon k počítači pomocí USB. Vyberte možnost Připojit, chcete-li zkopírovat soubory mezi vaším počítačem a kartou SD v telefonu."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Připojit"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nepřipojovat"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Při používání vaší karty SD jako úložiště USB došlo k problému."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB připojeno"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Vyberte, chcete-li kopírovat soubory do nebo z počítače."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Vypnout úložiště USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Vyberte, chcete-li vypnout úložiště USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Vypnout úložiště USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Před vypnutím úložiště USB se přesvědčte, zda byl hostitel USB odpojen. Úložiště USB vypnete volbou Vypnout."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Vypnout"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Zrušit"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Při vypínání úložiště USB došlo k problémům. Zkontrolujte, zda byl hostitel USB odpojen, a zkuste to znovu."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formátovat kartu SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Opravdu chcete kartu SD naformátovat? Všechna data na kartě budou ztracena."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formátovat"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes rozhraní USB připojeno"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"K vašemu telefonu je připojen počítač."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Výběr metody zadávání dat"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Příprava karty SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Kontrola chyb."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Prázdná karta SD"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Karta SD je prázdná nebo obsahuje nepodporovaný systém souborů."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Poškozená karta SD"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Karta SD je poškozená. Bude pravděpodobně nutné ji přeformátovat."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Karta SD byla neočekávaně odebrána"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Chcete-li zabránit ztrátě dat, kartu SD před odebráním odpojte."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Kartu SD je možné bezpečně odebrat"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Kartu SD lze bezpečně odebrat."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Karta SD byla odstraněna"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Karta SD byla odebrána. Vložte novou kartu."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nebyly nalezeny žádné odpovídající aktivity."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aktualizovat statistiku použití součástí"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Umožňuje změnu shromážděných statistických údajů o použití součástí. Není určeno pro běžné aplikace."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Poklepáním můžete ovládat přiblížení"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Chyba při spouštění widgetu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Přejít"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Hledat"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Odeslat"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Další"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hotovo"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Spustit"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Vytočit číslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Vytvořit kontakt"\n"pro <xliff:g id="NUMBER">%s</xliff:g>."</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"Zaškrtnuto"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"Nezaškrtnuto"</string>
+ <string name="select_character">"Vkládání znaků"</string>
+ <string name="sms_control_default_app_name">"Neznámá aplikace"</string>
+ <string name="sms_control_title">"Odesílání zpráv SMS"</string>
+ <string name="sms_control_message">"Je odesílán velký počet zpráv SMS. Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li odesílání ukončit."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Zrušit"</string>
+ <string name="date_time_set">"Nastavit"</string>
+ <string name="default_permission_group">"Výchozí"</string>
+ <string name="no_permissions">"Nejsou vyžadována žádná oprávnění"</string>
+ <string name="perms_hide"><b>"Skrýt"</b></string>
+ <string name="perms_show_all"><b>"Zobrazit vše"</b></string>
+ <string name="googlewebcontenthelper_loading">"Načítání..."</string>
+ <string name="usb_storage_title">"USB připojeno"</string>
+ <string name="usb_storage_message">"Připojili jste svůj telefon k počítači pomocí USB. Vyberte možnost Připojit, chcete-li zkopírovat soubory mezi vaším počítačem a kartou SD v telefonu."</string>
+ <string name="usb_storage_button_mount">"Připojit"</string>
+ <string name="usb_storage_button_unmount">"Nepřipojovat"</string>
+ <string name="usb_storage_error_message">"Při používání vaší karty SD jako úložiště USB došlo k problému."</string>
+ <string name="usb_storage_notification_title">"USB připojeno"</string>
+ <string name="usb_storage_notification_message">"Vyberte, chcete-li kopírovat soubory do nebo z počítače."</string>
+ <string name="usb_storage_stop_notification_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_notification_message">"Vyberte, chcete-li vypnout úložiště USB."</string>
+ <string name="usb_storage_stop_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_message">"Před vypnutím úložiště USB se přesvědčte, zda byl hostitel USB odpojen. Úložiště USB vypnete volbou Vypnout."</string>
+ <string name="usb_storage_stop_button_mount">"Vypnout"</string>
+ <string name="usb_storage_stop_button_unmount">"Zrušit"</string>
+ <string name="usb_storage_stop_error_message">"Při vypínání úložiště USB došlo k problémům. Zkontrolujte, zda byl hostitel USB odpojen, a zkuste to znovu."</string>
+ <string name="extmedia_format_title">"Formátovat kartu SD"</string>
+ <string name="extmedia_format_message">"Opravdu chcete kartu SD naformátovat? Všechna data na kartě budou ztracena."</string>
+ <string name="extmedia_format_button_format">"Formátovat"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Výběr metody zadávání dat"</string>
+ <string name="fast_scroll_alphabet">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
+ <string name="candidates_style"><u>"kandidáti"</u></string>
+ <string name="ext_media_checking_notification_title">"Příprava karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Kontrola chyb."</string>
+ <string name="ext_media_nofs_notification_title">"Prázdná karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD je prázdná nebo obsahuje nepodporovaný systém souborů."</string>
+ <string name="ext_media_unmountable_notification_title">"Poškozená karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD je poškozená. Bude pravděpodobně nutné ji přeformátovat."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD byla neočekávaně odebrána"</string>
+ <string name="ext_media_badremoval_notification_message">"Chcete-li zabránit ztrátě dat, kartu SD před odebráním odpojte."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Kartu SD je možné bezpečně odebrat"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Kartu SD lze bezpečně odebrat."</string>
+ <string name="ext_media_nomedia_notification_title">"Karta SD byla odstraněna"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD byla odebrána. Vložte novou kartu."</string>
+ <string name="activity_list_empty">"Nebyly nalezeny žádné odpovídající aktivity."</string>
+ <string name="permlab_pkgUsageStats">"aktualizovat statistiku použití součástí"</string>
+ <string name="permdesc_pkgUsageStats">"Umožňuje změnu shromážděných statistických údajů o použití součástí. Není určeno pro běžné aplikace."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Poklepáním můžete ovládat přiblížení"</string>
+ <string name="gadget_host_error_inflating">"Chyba při spouštění widgetu"</string>
+ <string name="ime_action_go">"Přejít"</string>
+ <string name="ime_action_search">"Hledat"</string>
+ <string name="ime_action_send">"Odeslat"</string>
+ <string name="ime_action_next">"Další"</string>
+ <string name="ime_action_done">"Hotovo"</string>
+ <string name="ime_action_default">"Spustit"</string>
+ <string name="dial_number_using">"Vytočit číslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
+ <string name="create_contact_using">"Vytvořit kontakt"\n"pro <xliff:g id="NUMBER">%s</xliff:g>."</string>
+ <string name="accessibility_compound_button_selected">"Zaškrtnuto"</string>
+ <string name="accessibility_compound_button_unselected">"Nezaškrtnuto"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ef8490b..4add1f8 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Kb"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"Mb"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"Gb"</string>
- <string name="terabyteShort" msgid="231613018159186962">"Tb"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"Pb"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"Kb"</string>
+ <string name="megabyteShort">"Mb"</string>
+ <string name="gigabyteShort">"Gb"</string>
+ <string name="terabyteShort">"Tb"</string>
+ <string name="petabyteShort">"Pb"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<uden navn>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Intet telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Ukendt)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Forbindelsesproblemer eller ugyldigt MMI-nummer."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjenesten blev aktiveret."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjenesten blev aktiveret for:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjenesten er deaktiveret."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen er afsluttet."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Sletning afsluttet."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Forkert adgangskode."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI-nummer afsluttet."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamle PIN-kode, du indtastede, er ikke korrekt."</string>
- <string name="badPuk" msgid="5702522162746042460">"Den indtastede PUK-kode er ikke korrekt."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"De indtastede PIN-koder stemmer ikke overens."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
- <string name="needPuk" msgid="919668385956251611">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Indgående opkalds-id"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Udgående opkalds-id"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Viderestilling af opkald"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Ventende opkald"</string>
- <string name="BaMmi" msgid="455193067926770581">"Opkaldsspærring"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Ændring af adgangskode"</string>
- <string name="PinMmi" msgid="3113117780361190304">"ændring af PIN-kode"</string>
+ <string name="untitled">"<uden navn>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Intet telefonnummer)"</string>
+ <string name="unknownName">"(Ukendt)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Forbindelsesproblemer eller ugyldigt MMI-nummer."</string>
+ <string name="serviceEnabled">"Tjenesten blev aktiveret."</string>
+ <string name="serviceEnabledFor">"Tjenesten blev aktiveret for:"</string>
+ <string name="serviceDisabled">"Tjenesten er deaktiveret."</string>
+ <string name="serviceRegistered">"Registreringen er afsluttet."</string>
+ <string name="serviceErased">"Sletning afsluttet."</string>
+ <string name="passwordIncorrect">"Forkert adgangskode."</string>
+ <string name="mmiComplete">"MMI-nummer afsluttet."</string>
+ <string name="badPin">"Den gamle PIN-kode, du indtastede, er ikke korrekt."</string>
+ <string name="badPuk">"Den indtastede PUK-kode er ikke korrekt."</string>
+ <string name="mismatchPin">"De indtastede PIN-koder stemmer ikke overens."</string>
+ <string name="invalidPin">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
+ <string name="needPuk">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
+ <string name="needPuk2">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
+ <string name="ClipMmi">"Indgående opkalds-id"</string>
+ <string name="ClirMmi">"Udgående opkalds-id"</string>
+ <string name="CfMmi">"Viderestilling af opkald"</string>
+ <string name="CwMmi">"Ventende opkald"</string>
+ <string name="BaMmi">"Opkaldsspærring"</string>
+ <string name="PwdMmi">"Ændring af adgangskode"</string>
+ <string name="PinMmi">"ændring af PIN-kode"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Begrænset"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjenesten leveres ikke!"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Indstillingen for opkalds-id kan ikke ændres."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begrænset adgang ændret"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjeneste er blokeret."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjeneste er blokeret."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Stemme-/SMS-tjeneste er blokeret."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle stemme-/SMS-tjenester er blokerede."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Stemme"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkroniser"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkroniser"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakke"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Begrænset"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
+ <string name="serviceNotProvisioned">"Tjenesten leveres ikke!"</string>
+ <string name="CLIRPermanent">"Indstillingen for opkalds-id kan ikke ændres."</string>
+ <string name="RestrictedChangedTitle">"Begrænset adgang ændret"</string>
+ <string name="RestrictedOnData">"Datatjeneste er blokeret."</string>
+ <string name="RestrictedOnEmergency">"Nødtjeneste er blokeret."</string>
+ <string name="RestrictedOnNormal">"Stemme-/SMS-tjeneste er blokeret."</string>
+ <string name="RestrictedOnAll">"Alle stemme-/SMS-tjenester er blokerede."</string>
+ <string name="serviceClassVoice">"Stemme"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkroniser"</string>
+ <string name="serviceClassDataSync">"Synkroniser"</string>
+ <string name="serviceClassPacket">"Pakke"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Websiden indeholder en fejl."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Webadressen kunne ikke findes."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Planen for webstedsgodkendelse er ikke understøttet."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Godkendelse mislykkedes."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Godkendelse via proxyserveren mislykkedes."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Der kunne ikke oprettes forbindelse til serveren."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Serveren kunne ikke kommunikere. Prøv igen senere."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Der opstod timeout for forbindelsen til serveren."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Siden indeholder for mange serveromdirigeringer."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollen understøttes ikke."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Der kunne ikke etableres en sikker forbindelse."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Der kunne ikke oprettes adgang til filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Den anmodede fil blev ikke fundet."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Der behandles for mange anmodninger. Prøv igen senere."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkroniser"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkroniser"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagerplads er fuld. Slet nogle filer for at frigøre plads."</string>
- <string name="me" msgid="6545696007631404292">"Mig"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonvalgmuligheder"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Lydløs"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Slå trådløs til"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Slå trådløs fra"</string>
- <string name="screen_lock" msgid="799094655496098153">"Skærmlås"</string>
- <string name="power_off" msgid="4266614107412865048">"Sluk"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned ..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Din telefon lukkes ned."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Der er ingen nye programmer."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonvalgmuligheder"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er FRA"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er FRA"</string>
- <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Tillader et program at gøre ting, som kan koste penge."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Læs og skriv dine SMS-, e-mail- og andre beskeder."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Dine personlige oplysninger"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Få direkte adgang til dine kontakter og din kalender, der er gemt på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Din placering"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Overvåg din fysiske placering"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netværkskommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Tillader programmer at få adgang til forskellige netværksfunktioner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Dine Google-konti"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Få adgang til tilgængelige Google-konti."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardwarekontroller"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkte adgang til hardware på håndsættet."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonopkald"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Overvåg, registrer og behandl telefonopkald."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemværktøjer"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Adgang og kontrol til systemet på lavere niveau."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Udviklingsværktøjer"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktioner kun til programudviklere."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Websiden indeholder en fejl."</string>
+ <string name="httpErrorLookup">"Webadressen kunne ikke findes."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Planen for webstedsgodkendelse er ikke understøttet."</string>
+ <string name="httpErrorAuth">"Godkendelse mislykkedes."</string>
+ <string name="httpErrorProxyAuth">"Godkendelse via proxyserveren mislykkedes."</string>
+ <string name="httpErrorConnect">"Der kunne ikke oprettes forbindelse til serveren."</string>
+ <string name="httpErrorIO">"Serveren kunne ikke kommunikere. Prøv igen senere."</string>
+ <string name="httpErrorTimeout">"Der opstod timeout for forbindelsen til serveren."</string>
+ <string name="httpErrorRedirectLoop">"Siden indeholder for mange serveromdirigeringer."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollen understøttes ikke."</string>
+ <string name="httpErrorFailedSslHandshake">"Der kunne ikke etableres en sikker forbindelse."</string>
+ <string name="httpErrorBadUrl">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
+ <string name="httpErrorFile">"Der kunne ikke oprettes adgang til filen."</string>
+ <string name="httpErrorFileNotFound">"Den anmodede fil blev ikke fundet."</string>
+ <string name="httpErrorTooManyRequests">"Der behandles for mange anmodninger. Prøv igen senere."</string>
+ <string name="contentServiceSync">"Synkroniser"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkroniser"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
+ <string name="low_memory">"Telefonens lagerplads er fuld. Slet nogle filer for at frigøre plads."</string>
+ <string name="me">"Mig"</string>
+ <string name="power_dialog">"Telefonvalgmuligheder"</string>
+ <string name="silent_mode">"Lydløs"</string>
+ <string name="turn_on_radio">"Slå trådløs til"</string>
+ <string name="turn_off_radio">"Slå trådløs fra"</string>
+ <string name="screen_lock">"Skærmlås"</string>
+ <string name="power_off">"Sluk"</string>
+ <string name="shutdown_progress">"Lukker ned ..."</string>
+ <string name="shutdown_confirm">"Din telefon lukkes ned."</string>
+ <string name="no_recent_tasks">"Der er ingen nye programmer."</string>
+ <string name="global_actions">"Telefonvalgmuligheder"</string>
+ <string name="global_action_lock">"Skærmlås"</string>
+ <string name="global_action_power_off">"Sluk"</string>
+ <string name="global_action_toggle_silent_mode">"Lydløs"</string>
+ <string name="global_action_silent_mode_on_status">"Lyden er FRA"</string>
+ <string name="global_action_silent_mode_off_status">"Lyden er TIL"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flytilstand"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flytilstand er TIL"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flytilstand er FRA"</string>
+ <string name="safeMode">"Sikker tilstand"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Tjenester, der koster dig penge"</string>
+ <string name="permgroupdesc_costMoney">"Tillader et program at gøre ting, som kan koste penge."</string>
+ <string name="permgrouplab_messages">"Dine beskeder"</string>
+ <string name="permgroupdesc_messages">"Læs og skriv dine SMS-, e-mail- og andre beskeder."</string>
+ <string name="permgrouplab_personalInfo">"Dine personlige oplysninger"</string>
+ <string name="permgroupdesc_personalInfo">"Få direkte adgang til dine kontaktpersoner og din kalender, der er gemt på telefonen."</string>
+ <string name="permgrouplab_location">"Din placering"</string>
+ <string name="permgroupdesc_location">"Overvåg din fysiske placering"</string>
+ <string name="permgrouplab_network">"Netværkskommunikation"</string>
+ <string name="permgroupdesc_network">"Tillader programmer at få adgang til forskellige netværksfunktioner."</string>
+ <string name="permgrouplab_accounts">"Dine Google-konti"</string>
+ <string name="permgroupdesc_accounts">"Få adgang til tilgængelige Google-konti."</string>
+ <string name="permgrouplab_hardwareControls">"Hardwarekontroller"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkte adgang til hardware på håndsættet."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonopkald"</string>
+ <string name="permgroupdesc_phoneCalls">"Overvåg, registrer og behandl telefonopkald."</string>
+ <string name="permgrouplab_systemTools">"Systemværktøjer"</string>
+ <string name="permgroupdesc_systemTools">"Adgang og kontrol til systemet på lavere niveau."</string>
+ <string name="permgrouplab_developmentTools">"Udviklingsværktøjer"</string>
+ <string name="permgroupdesc_developmentTools">"Funktioner kun til programudviklere."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Tillader et program at deaktivere statuslinjen eller tilføje eller fjerne systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"udvid/skjul statuslinje"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Tillader et program at udvide eller skjule statuslinjen."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"opfang udgående opkald"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Tillader et program at behandle udgående opkald og ændre nummeret, der skal ringes til. Ondsindede programmer kan overvåge, omdirigere eller forhindre udgående opkald."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"modtag SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Tillader et program at modtage og behandle SMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"modtag MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Tillader et program at modtage og behandle MMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"send SMS-beskeder"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Tillader et program at sende SMS-beskeder. Ondsindede programmer kan eventuelt koste dig penge ved at sende beskeder uden din bekræftelse."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"læs SMS eller MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Tillader et program at læse SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt læse dine fortrolige beskeder."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"rediger SMS eller MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Tillader et program at skrive til SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt slette dine beskeder."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"modtag WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillader et program at modtage og behandle WAP-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"hent kørende programmer"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillader et program at hente oplysninger om nuværende og for nyligt kørende opgaver. Tillader eventuelt ondsindede programmer at finde private oplysninger om andre programmer."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"omorganiser kørende programmer"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillader et program at flytte opgaver til forgrunden og baggrunden. Ondsindede programmer kan tvinge dem selv til forgrunden uden din kontrol."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver programfejlretning"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillader et program at slå fejlretning af andet program til. Ondsindede programmer kan bruge dette til at standse andre programmer."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift dine UI-indstillinger"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillader et program at ændre den nuværende konfiguration, som f.eks. den lokale eller overordnede skrifttypestørrelse."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"genstart andre programmer"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Tillader et program at tvangsgenstarte andre programmer."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tving programmet til at lukke"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Tillader et program at tvinge alle programmer, der er i forgrunden, til at lukke og gå tilbage. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hent intern systemtilstand"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Tillader et program at hente systemets interne tilstand. Ondsindede programmer kan hente en række private og sikre oplysninger, som de normalt aldrig bør have brug for."</string>
+ <string name="permlab_statusBar">"deaktiver eller rediger statuslinje"</string>
+ <string name="permdesc_statusBar">"Tillader et program at deaktivere statuslinjen eller tilføje eller fjerne systemikoner."</string>
+ <string name="permlab_expandStatusBar">"udvid/skjul statuslinje"</string>
+ <string name="permdesc_expandStatusBar">"Tillader et program at udvide eller skjule statuslinjen."</string>
+ <string name="permlab_processOutgoingCalls">"opfang udgående opkald"</string>
+ <string name="permdesc_processOutgoingCalls">"Tillader et program at behandle udgående opkald og ændre nummeret, der skal ringes til. Ondsindede programmer kan overvåge, omdirigere eller forhindre udgående opkald."</string>
+ <string name="permlab_receiveSms">"modtag SMS"</string>
+ <string name="permdesc_receiveSms">"Tillader et program at modtage og behandle SMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_receiveMms">"modtag MMS"</string>
+ <string name="permdesc_receiveMms">"Tillader et program at modtage og behandle MMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_sendSms">"send SMS-beskeder"</string>
+ <string name="permdesc_sendSms">"Tillader et program at sende SMS-beskeder. Ondsindede programmer kan eventuelt koste dig penge ved at sende beskeder uden din bekræftelse."</string>
+ <string name="permlab_readSms">"læs SMS eller MMS"</string>
+ <string name="permdesc_readSms">"Tillader et program at læse SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt læse dine fortrolige beskeder."</string>
+ <string name="permlab_writeSms">"rediger SMS eller MMS"</string>
+ <string name="permdesc_writeSms">"Tillader et program at skrive til SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt slette dine beskeder."</string>
+ <string name="permlab_receiveWapPush">"modtag WAP"</string>
+ <string name="permdesc_receiveWapPush">"Tillader et program at modtage og behandle WAP-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_getTasks">"hent kørende programmer"</string>
+ <string name="permdesc_getTasks">"Tillader et program at hente oplysninger om nuværende og for nyligt kørende opgaver. Tillader eventuelt ondsindede programmer at finde private oplysninger om andre programmer."</string>
+ <string name="permlab_reorderTasks">"omorganiser kørende programmer"</string>
+ <string name="permdesc_reorderTasks">"Tillader et program at flytte opgaver til forgrunden og baggrunden. Ondsindede programmer kan tvinge dem selv til forgrunden uden din kontrol."</string>
+ <string name="permlab_setDebugApp">"aktiver programfejlretning"</string>
+ <string name="permdesc_setDebugApp">"Tillader et program at slå fejlretning af andet program til. Ondsindede programmer kan bruge dette til at standse andre programmer."</string>
+ <string name="permlab_changeConfiguration">"skift dine UI-indstillinger"</string>
+ <string name="permdesc_changeConfiguration">"Tillader et program at ændre den nuværende konfiguration, som f.eks. den lokale eller overordnede skrifttypestørrelse."</string>
+ <string name="permlab_restartPackages">"genstart andre programmer"</string>
+ <string name="permdesc_restartPackages">"Tillader et program at tvangsgenstarte andre programmer."</string>
+ <string name="permlab_forceBack">"tving programmet til at lukke"</string>
+ <string name="permdesc_forceBack">"Tillader et program at tvinge alle programmer, der er i forgrunden, til at lukke og gå tilbage. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_dump">"hent intern systemtilstand"</string>
+ <string name="permdesc_dump">"Tillader et program at hente systemets interne tilstand. Ondsindede programmer kan hente en række private og sikre oplysninger, som de normalt aldrig bør have brug for."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"overvåg og kontroller start af alle programmer"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Tillader et program at overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede programmer kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal telefonbrug."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send udsendelse om fjernet pakke"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillader et program at udsende en meddelelse om, at en programpakke er fjernet. Ondsindede programmer kan bruge dette til at afslutte et andet kørende program."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"send SMS-modtaget udsendelse"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Tillader et program at udsende en meddelelse om, at der er modtaget en SMS-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske indgående SMS-beskeder."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-modtaget udsendelse"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Tillader et program at udsende en meddelelse om, at der er modtaget en WAP PUSH-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske modtagelse af MMS-besked eller i det skjulte erstatte indholdet på alle websider med ondsindede varianter."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begræns antallet af kørende processer"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Tillader et program at kontrollere det maksimale antal processer, der kan køre. Er aldrig nødvendigt til normale programmer."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"få alle baggrundsprogrammer til at lukke"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Tillader et program at kontrollere, om aktiviteter altid afsluttes, så snart de går i baggrunden. Aldrig nødvendigt til normale programmer."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"rediger batteristatistikker"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillader ændring af indsamlede batteristatistikker. Ikke til brug for normale programmer."</string>
+ <string name="permlab_runSetActivityWatcher">"overvåg og kontroller start af alle programmer"</string>
+ <string name="permdesc_runSetActivityWatcher">"Tillader et program at overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede programmer kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal telefonbrug."</string>
+ <string name="permlab_broadcastPackageRemoved">"send udsendelse om fjernet pakke"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Tillader et program at udsende en meddelelse om, at en programpakke er fjernet. Ondsindede programmer kan bruge dette til at afslutte et andet kørende program."</string>
+ <string name="permlab_broadcastSmsReceived">"send SMS-modtaget udsendelse"</string>
+ <string name="permdesc_broadcastSmsReceived">"Tillader et program at udsende en meddelelse om, at der er modtaget en SMS-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske indgående SMS-beskeder."</string>
+ <string name="permlab_broadcastWapPush">"send WAP-PUSH-modtaget udsendelse"</string>
+ <string name="permdesc_broadcastWapPush">"Tillader et program at udsende en meddelelse om, at der er modtaget en WAP PUSH-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske modtagelse af MMS-besked eller i det skjulte erstatte indholdet på alle websider med ondsindede varianter."</string>
+ <string name="permlab_setProcessLimit">"begræns antallet af kørende processer"</string>
+ <string name="permdesc_setProcessLimit">"Tillader et program at kontrollere det maksimale antal processer, der kan køre. Er aldrig nødvendigt til normale programmer."</string>
+ <string name="permlab_setAlwaysFinish">"få alle baggrundsprogrammer til at lukke"</string>
+ <string name="permdesc_setAlwaysFinish">"Tillader et program at kontrollere, om aktiviteter altid afsluttes, så snart de går i baggrunden. Aldrig nødvendigt til normale programmer."</string>
+ <string name="permlab_batteryStats">"rediger batteristatistikker"</string>
+ <string name="permdesc_batteryStats">"Tillader ændring af indsamlede batteristatistikker. Ikke til brug for normale programmer."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserede vinduer"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillader oprettelse af vinduer, der er beregnet til at blive brugt af den interne systembrugergrænseflade. Ikke til brug for normale programmer."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vis underretninger på systemniveau"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Tillader et program at vise systemunderretningsvinduer. Ondsindede programmer kan overtage hele telefonens skærm."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"rediger global animationshastighed"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Tillader et program at ændre den globale animationshastighed (hurtigere eller langsommere animationer) når som helst."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrer programtokens"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Tillader programmet at oprette og administrere deres egen tokens og gå uden om deres normale Z-rækkefølge. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"tryk på taster og kontrolknapper"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Tillader et program at levere sine egne inputbegivenheder (tastetryk osv.) til andre programmer. Ondsindede programmer kan bruge dette til at overtage telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrerer, hvad du indtaster, og hvilke handlinger du foretager dig"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Tillader et program at holde øje med de taster, du trykker på, selv når du interagerer med andre programmer (som f.eks. indtastning af adgangskode). Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"forpligt til en inputmetode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Tillader brugeren at forpligte sig på en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendig til normale programmer."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillader et program at ændre rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux-signaler til programmer"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillader program at anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"lad altid programmet køre"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Tillader et program at gøre dele af sig selv vedholdende, så systemet ikke kan bruge det til andre programmer."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"slet programmer"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Tillader et program at slette Android-pakker. Ondsindede programmer kan bruge dette til at slette vigtige programmer."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"slet andre programmers data"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Lader et program rydde brugerdata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"slet andre programmers cacher"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillader et program at slette cachefiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"måler programmets lagerplads"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillader et program at hente dets kode, data og cachestørrelser"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installer programmer direkte"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Tillader et program at installere nye eller opdaterede Android-pakker. Ondsindede programmer kan bruge dette til at tilføje nye programmer med vilkårlige, effektive tilladelser."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"slet alle cachedata for programmet"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillader et program at frigøre plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"læs systemlogfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillader et program at læse fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, opdages, men logfilerne skulle ikke indeholde personlige eller private oplysninger."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillader et program at læse og skrive til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktiver eller deaktiver programkomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Tillader et program at ændre, om en komponent fra et andet program er aktiveret eller ej. Ondsindede programmer kan bruge dette til at deaktivere vigtige telefonfunktioner. Denne tilladelse skal anvendes med forsigtighed, da det kan forårsage ubrugelige, inkonsekvente eller ustabile programkomponenter."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"indstil foretrukne programmer"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillader et program at ændre dine foretrukne programmer. Dette kan tillade, at ondsindede programmer ændrer kørende programmer i det skjulte og narrer dine eksisterende programmer til at indsamle personlige data fra dig."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"rediger globale systemindstillinger"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Tillader et program at ændre systemets indstillingsdata. Ondsindede programmer kan skade systemets konfiguration."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"rediger sikre systemindstillinger"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Tillader et program at ændre systemernes sikre indstillingsdata. Ikke til brug til almindelige programmer."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"rediger kortet over Google-tjenester"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Tillader et program at ændre kortet over Google-tjenester. Ikke til brug til normale programmer."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"start automatisk ved opstart"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Tillader et program at starte selv, når systemet er færdig med at starte. Dette kan gøre start af telefonen langsommere og generelt gøre telefonen langsommere ved altid at lade programmet køre."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"send klæbende udsendelse"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Tillader et program at sende klæbende udsendelser, der bliver tilbage, efter udsendelsen er slut. Ondsindede programmer kan gøre telefonen langsom eller ustabil ved at få den til at bruge for meget hukommelse."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"læs kontaktdata"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Tillader et program at læse alle kontaktdata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine data til andre mennesker."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skriv kontaktdata"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Tillader et program at ændre telefonens kontaktdata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kontaktdata."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skriv ejerdata"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Tillader et program at ændre telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre ejerdata."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"læs ejerdata"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Tillader et program at læse telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at læse ejerdata."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"læs kalenderdata"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Tillader et program at læse alle kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine kalenderbegivenheder til andre mennesker."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skriv kalenderdata"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Tillader et program at ændre telefonens kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kalenderdata."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"imiterede placeringskilder til test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Opret imiterede placeringskilder til testning. Ondsindede programmer kan bruge dette til at tilsidesætte den returnerede placering og/eller status fra rigtige placeringskilder som f.eks. GPS eller netværksudbydere."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få adgang til ekstra kommandoer for placeringsudbyder"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Få adgang til ekstra kommandoer fra placeringsudbyder. Ondsindede programmer kan bruge dette til at gribe ind i driften af GPS\'en eller andre placeringskilder."</string>
+ <string name="permlab_internalSystemWindow">"vis uautoriserede vinduer"</string>
+ <string name="permdesc_internalSystemWindow">"Tillader oprettelse af vinduer, der er beregnet til at blive brugt af den interne systembrugergrænseflade. Ikke til brug for normale programmer."</string>
+ <string name="permlab_systemAlertWindow">"vis underretninger på systemniveau"</string>
+ <string name="permdesc_systemAlertWindow">"Tillader et program at vise systemunderretningsvinduer. Ondsindede programmer kan overtage hele telefonens skærm."</string>
+ <string name="permlab_setAnimationScale">"rediger global animationshastighed"</string>
+ <string name="permdesc_setAnimationScale">"Tillader et program at ændre den globale animationshastighed (hurtigere eller langsommere animationer) når som helst."</string>
+ <string name="permlab_manageAppTokens">"administrer programtokens"</string>
+ <string name="permdesc_manageAppTokens">"Tillader programmet at oprette og administrere deres egen tokens og gå uden om deres normale Z-rækkefølge. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_injectEvents">"tryk på taster og kontrolknapper"</string>
+ <string name="permdesc_injectEvents">"Tillader et program at levere sine egne inputbegivenheder (tastetryk osv.) til andre programmer. Ondsindede programmer kan bruge dette til at overtage telefonen."</string>
+ <string name="permlab_readInputState">"registrerer, hvad du indtaster, og hvilke handlinger du foretager dig"</string>
+ <string name="permdesc_readInputState">"Tillader et program at holde øje med de taster, du trykker på, selv når du interagerer med andre programmer (som f.eks. indtastning af adgangskode). Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_bindInputMethod">"forpligt til en inputmetode"</string>
+ <string name="permdesc_bindInputMethod">"Tillader brugeren at forpligte sig på en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendig til normale programmer."</string>
+ <string name="permlab_setOrientation">"skift skærmretning"</string>
+ <string name="permdesc_setOrientation">"Tillader et program at ændre rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_signalPersistentProcesses">"send Linux-signaler til programmer"</string>
+ <string name="permdesc_signalPersistentProcesses">"Tillader program at anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
+ <string name="permlab_persistentActivity">"lad altid programmet køre"</string>
+ <string name="permdesc_persistentActivity">"Tillader et program at gøre dele af sig selv vedholdende, så systemet ikke kan bruge det til andre programmer."</string>
+ <string name="permlab_deletePackages">"slet programmer"</string>
+ <string name="permdesc_deletePackages">"Tillader et program at slette Android-pakker. Ondsindede programmer kan bruge dette til at slette vigtige programmer."</string>
+ <string name="permlab_clearAppUserData">"slet andre programmers data"</string>
+ <string name="permdesc_clearAppUserData">"Lader et program rydde brugerdata."</string>
+ <string name="permlab_deleteCacheFiles">"slet andre programmers cacher"</string>
+ <string name="permdesc_deleteCacheFiles">"Tillader et program at slette cachefiler."</string>
+ <string name="permlab_getPackageSize">"måler programmets lagerplads"</string>
+ <string name="permdesc_getPackageSize">"Tillader et program at hente dets kode, data og cachestørrelser"</string>
+ <string name="permlab_installPackages">"installer programmer direkte"</string>
+ <string name="permdesc_installPackages">"Tillader et program at installere nye eller opdaterede Android-pakker. Ondsindede programmer kan bruge dette til at tilføje nye programmer med vilkårlige, effektive tilladelser."</string>
+ <string name="permlab_clearAppCache">"slet alle cachedata for programmet"</string>
+ <string name="permdesc_clearAppCache">"Tillader et program at frigøre plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string>
+ <string name="permlab_readLogs">"læs systemlogfiler"</string>
+ <string name="permdesc_readLogs">"Tillader et program at læse fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, opdages, men logfilerne skulle ikke indeholde personlige eller private oplysninger."</string>
+ <string name="permlab_diagnostic">"læs/skriv til ressourcer ejet af diag"</string>
+ <string name="permdesc_diagnostic">"Tillader et program at læse og skrive til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string>
+ <string name="permlab_changeComponentState">"aktiver eller deaktiver programkomponenter"</string>
+ <string name="permdesc_changeComponentState">"Tillader et program at ændre, om en komponent fra et andet program er aktiveret eller ej. Ondsindede programmer kan bruge dette til at deaktivere vigtige telefonfunktioner. Denne tilladelse skal anvendes med forsigtighed, da det kan forårsage ubrugelige, inkonsekvente eller ustabile programkomponenter."</string>
+ <string name="permlab_setPreferredApplications">"indstil foretrukne programmer"</string>
+ <string name="permdesc_setPreferredApplications">"Tillader et program at ændre dine foretrukne programmer. Dette kan tillade, at ondsindede programmer ændrer kørende programmer i det skjulte og narrer dine eksisterende programmer til at indsamle personlige data fra dig."</string>
+ <string name="permlab_writeSettings">"rediger globale systemindstillinger"</string>
+ <string name="permdesc_writeSettings">"Tillader et program at ændre systemets indstillingsdata. Ondsindede programmer kan skade systemets konfiguration."</string>
+ <string name="permlab_writeSecureSettings">"rediger sikre systemindstillinger"</string>
+ <string name="permdesc_writeSecureSettings">"Tillader et program at ændre systemernes sikre indstillingsdata. Ikke til brug til almindelige programmer."</string>
+ <string name="permlab_writeGservices">"rediger kortet over Google-tjenester"</string>
+ <string name="permdesc_writeGservices">"Tillader et program at ændre kortet over Google-tjenester. Ikke til brug til normale programmer."</string>
+ <string name="permlab_receiveBootCompleted">"start automatisk ved opstart"</string>
+ <string name="permdesc_receiveBootCompleted">"Tillader et program at starte selv, når systemet er færdig med at starte. Dette kan gøre start af telefonen langsommere og generelt gøre telefonen langsommere ved altid at lade programmet køre."</string>
+ <string name="permlab_broadcastSticky">"send klæbende udsendelse"</string>
+ <string name="permdesc_broadcastSticky">"Tillader et program at sende klæbende udsendelser, der bliver tilbage, efter udsendelsen er slut. Ondsindede programmer kan gøre telefonen langsom eller ustabil ved at få den til at bruge for meget hukommelse."</string>
+ <string name="permlab_readContacts">"læs kontaktpersondata"</string>
+ <string name="permdesc_readContacts">"Tillader et program at læse alle kontaktpersondata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine data til andre mennesker."</string>
+ <string name="permlab_writeContacts">"skriv kontaktpersondata"</string>
+ <string name="permdesc_writeContacts">"Tillader et program at ændre telefonens kontaktpersondata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kontaktpersondata."</string>
+ <string name="permlab_writeOwnerData">"skriv ejerdata"</string>
+ <string name="permdesc_writeOwnerData">"Tillader et program at ændre telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre ejerdata."</string>
+ <string name="permlab_readOwnerData">"læs ejerdata"</string>
+ <string name="permdesc_readOwnerData">"Tillader et program at læse telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at læse ejerdata."</string>
+ <string name="permlab_readCalendar">"læs kalenderdata"</string>
+ <string name="permdesc_readCalendar">"Tillader et program at læse alle kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine kalenderbegivenheder til andre mennesker."</string>
+ <string name="permlab_writeCalendar">"skriv kalenderdata"</string>
+ <string name="permdesc_writeCalendar">"Tillader et program at ændre telefonens kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kalenderdata."</string>
+ <string name="permlab_accessMockLocation">"imiterede placeringskilder til test"</string>
+ <string name="permdesc_accessMockLocation">"Opret imiterede placeringskilder til testning. Ondsindede programmer kan bruge dette til at tilsidesætte den returnerede placering og/eller status fra rigtige placeringskilder som f.eks. GPS eller netværksudbydere."</string>
+ <string name="permlab_accessLocationExtraCommands">"få adgang til ekstra kommandoer for placeringsudbyder"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få adgang til ekstra kommandoer fra placeringsudbyder. Ondsindede programmer kan bruge dette til at gribe ind i driften af GPS\'en eller andre placeringskilder."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"fin (GPS) placering"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få adgang til gode placeringskilder, som f.eks. Global Positioning System på telefonen, når det er tilgængeligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du er og kan eventuelt bruge yderligere batterikapacitet."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (netværksbaseret) placering"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få adgang til grove placeringskilder som f.eks. den mobile netværksdatabase for at finde en omtrentlig placering for telefonen, hvor det er muligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du omtrent er."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få adgang til SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Tillader et program at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"læs rammebuffer"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Tillader et program at læse/bruge indholdet fra rammebufferen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"skift dine lydindstillinger"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Tillader et program at ændre globale lydindstillinger som f.eks. lydstyrke og kanalisering."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"optag lyd"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Tillader et program at få adgang til lydregistreringsstien."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tag billeder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Tillader programmet at tage billeder med kameraet. Dette tillader programmet til hver en tid at indsamle de billeder, kameraet ser."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"deaktiver telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Tillader programmet at deaktivere hele telefonen permanent. Dette er meget farligt."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tving telefon til at genstarte"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Tillader programmet at tvinge telefonen til at genstarte."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"monter eller demonter filsystemer"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Tillader programmet at montere eller demontere filsystemer til flytbar lagring."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formater ekstern lagring"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Tillader et program at formatere flytbar lagring."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontroller vibrator"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Lader programmet kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillader programmet at kontrollere lommelygten."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillader et program at kontrollere forskellige perifere enheder med det formål at teste hardwaren."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ring direkte op til telefonnumre"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Tillader programmet at ringe til telefonnumre uden din indgriben. Ondsindede programmer kan forårsage uventede opkald på din telefonregning. Vær opmærksom på, at det ikke tillader programmet at ringe til nødnumre."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ring direkte op til alle telefonnumre"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Tillader programmet at ringe til alle telefonnumre inklusive nødnumre uden din indgriben. Ondsindede programmer kan eventuelt foretage unødvendige og ulovlige opkald til nødtjenester."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontroller meddelelser om placeringsopdatering"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Tillader aktivering/deaktivering af placeringsdata fra radioen. Ikke til brug til normale programmer."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"egenskaber for adgangskontrol"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Tillader læse/skrive-adgang til egenskaber, der er uploadet af kontroltjenesten. Ikke til brug til normale programmer."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"vælg widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Tillader programmet at fortælle systemet, hvilke widgets der kan bruges af hvilke programmer. Med denne tilladelse kan programmer give adgang til personlige data til andre programmer. Ikke til brug til normale programmer."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"rediger telefontilstand"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Tillader programmet at kontrollere enhedens telefonfunktioner. Et program med denne tilladelse kan skifte netværk, slå telefonens radio til og fra og lignende uden nogensinde at underrette dig."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"afhold telefonen fra at gå i dvale"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Tillader et program at forhindre telefonen i at gå i dvale."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Tænd eller sluk for telefonen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Tillader programmet at slå telefonen til eller fra."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kør i fabriksindstillet testtilstand"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"angiv tapet"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Tillader programmet at opsætte systemets tapet."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"opsæt tip til tapetstørrelse"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Tillader programmet at opsætte størrelsestip for systemets tapet."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"nulstil system til fabriksstandarder"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Tillader et program fuldstændig at nulstille systemet til fabriksindstillingerne, slette alle data, konfigurationen og installerede programmer."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"indstil tidszone"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Tillader et program at ændre telefonens tidszone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"opdag kendte konti"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Tillader et program at hente listen over konti, der er kendt af telefonen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"vis netværkstilstand"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Tillader et program at vise tilstanden for alle netværk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Fuld internetadgang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Tillader et program at oprette netværks-sockets."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skriv indstillinger for adgangspunktnavn"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Tillader et program at ændre APN-indstillingerne, som f.eks. enhver APNs Proxy og Port."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"skift netværksforbindelse"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Tillader et program at ændre netværksforbindelsens tilstand."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"skift brugerindstilling for baggrundsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Tillader et program at ændre brugerindstillingerne for baggrundsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"vis Wi-Fi-tilstand"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Tillader et program at vise oplysninger om Wi-Fi-tilstanden."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"skift Wi-Fi-tilstand"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillader et program at oprette og afbryde forbindelse fra Wi-Fi-adgangspunkter og foretage ændringer til konfigurerede Wi-Fi-netværk."</string>
+ <string name="permlab_accessFineLocation">"fin (GPS) placering"</string>
+ <string name="permdesc_accessFineLocation">"Få adgang til gode placeringskilder, som f.eks. Global Positioning System på telefonen, når det er tilgængeligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du er og kan eventuelt bruge yderligere batterikapacitet."</string>
+ <string name="permlab_accessCoarseLocation">"grov (netværksbaseret) placering"</string>
+ <string name="permdesc_accessCoarseLocation">"Få adgang til grove placeringskilder som f.eks. den mobile netværksdatabase for at finde en omtrentlig placering for telefonen, hvor det er muligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du omtrent er."</string>
+ <string name="permlab_accessSurfaceFlinger">"få adgang til SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Tillader et program at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
+ <string name="permlab_readFrameBuffer">"læs rammebuffer"</string>
+ <string name="permdesc_readFrameBuffer">"Tillader et program at læse/bruge indholdet fra rammebufferen."</string>
+ <string name="permlab_modifyAudioSettings">"skift dine lydindstillinger"</string>
+ <string name="permdesc_modifyAudioSettings">"Tillader et program at ændre globale lydindstillinger som f.eks. lydstyrke og kanalisering."</string>
+ <string name="permlab_recordAudio">"optag lyd"</string>
+ <string name="permdesc_recordAudio">"Tillader et program at få adgang til lydregistreringsstien."</string>
+ <string name="permlab_camera">"tag billeder"</string>
+ <string name="permdesc_camera">"Tillader programmet at tage billeder med kameraet. Dette tillader programmet til hver en tid at indsamle de billeder, kameraet ser."</string>
+ <string name="permlab_brick">"deaktiver telefonen permanent"</string>
+ <string name="permdesc_brick">"Tillader programmet at deaktivere hele telefonen permanent. Dette er meget farligt."</string>
+ <string name="permlab_reboot">"tving telefon til at genstarte"</string>
+ <string name="permdesc_reboot">"Tillader programmet at tvinge telefonen til at genstarte."</string>
+ <string name="permlab_mount_unmount_filesystems">"monter eller demonter filsystemer"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Tillader programmet at montere eller demontere filsystemer til flytbar lagring."</string>
+ <string name="permlab_mount_format_filesystems">"formater ekstern lagring"</string>
+ <string name="permdesc_mount_format_filesystems">"Tillader et program at formatere flytbar lagring."</string>
+ <string name="permlab_vibrate">"kontroller vibrator"</string>
+ <string name="permdesc_vibrate">"Lader programmet kontrollere vibratoren."</string>
+ <string name="permlab_flashlight">"kontroller lommelygte"</string>
+ <string name="permdesc_flashlight">"Tillader programmet at kontrollere lommelygten."</string>
+ <string name="permlab_hardware_test">"test hardware"</string>
+ <string name="permdesc_hardware_test">"Tillader et program at kontrollere forskellige perifere enheder med det formål at teste hardwaren."</string>
+ <string name="permlab_callPhone">"ring direkte op til telefonnumre"</string>
+ <string name="permdesc_callPhone">"Tillader programmet at ringe til telefonnumre uden din indgriben. Ondsindede programmer kan forårsage uventede opkald på din telefonregning. Vær opmærksom på, at det ikke tillader programmet at ringe til nødnumre."</string>
+ <string name="permlab_callPrivileged">"ring direkte op til alle telefonnumre"</string>
+ <string name="permdesc_callPrivileged">"Tillader programmet at ringe til alle telefonnumre inklusive nødnumre uden din indgriben. Ondsindede programmer kan eventuelt foretage unødvendige og ulovlige opkald til nødtjenester."</string>
+ <string name="permlab_locationUpdates">"kontroller meddelelser om placeringsopdatering"</string>
+ <string name="permdesc_locationUpdates">"Tillader aktivering/deaktivering af placeringsdata fra radioen. Ikke til brug til normale programmer."</string>
+ <string name="permlab_checkinProperties">"egenskaber for adgangskontrol"</string>
+ <string name="permdesc_checkinProperties">"Tillader læse/skrive-adgang til egenskaber, der er uploadet af kontroltjenesten. Ikke til brug til normale programmer."</string>
+ <string name="permlab_bindGadget">"vælg widgets"</string>
+ <string name="permdesc_bindGadget">"Tillader programmet at fortælle systemet, hvilke widgets der kan bruges af hvilke programmer. Med denne tilladelse kan programmer give adgang til personlige data til andre programmer. Ikke til brug til normale programmer."</string>
+ <string name="permlab_modifyPhoneState">"rediger telefontilstand"</string>
+ <string name="permdesc_modifyPhoneState">"Tillader programmet at kontrollere enhedens telefonfunktioner. Et program med denne tilladelse kan skifte netværk, slå telefonens radio til og fra og lignende uden nogensinde at underrette dig."</string>
+ <string name="permlab_readPhoneState">"læs telefontilstand"</string>
+ <string name="permdesc_readPhoneState">"Tillader programmet at få adgang til enhedens telefonfunktioner. Et program med denne tilladelse kan afgøre denne telefons nummer, om et opkald er aktivt, nummeret som opkaldet er forbundet til osv."</string>
+ <string name="permlab_wakeLock">"afhold telefonen fra at gå i dvale"</string>
+ <string name="permdesc_wakeLock">"Tillader et program at forhindre telefonen i at gå i dvale."</string>
+ <string name="permlab_devicePower">"Tænd eller sluk for telefonen"</string>
+ <string name="permdesc_devicePower">"Tillader programmet at slå telefonen til eller fra."</string>
+ <string name="permlab_factoryTest">"kør i fabriksindstillet testtilstand"</string>
+ <string name="permdesc_factoryTest">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
+ <string name="permlab_setWallpaper">"angiv tapet"</string>
+ <string name="permdesc_setWallpaper">"Tillader programmet at opsætte systemets tapet."</string>
+ <string name="permlab_setWallpaperHints">"opsæt tip til tapetstørrelse"</string>
+ <string name="permdesc_setWallpaperHints">"Tillader programmet at opsætte størrelsestip for systemets tapet."</string>
+ <string name="permlab_masterClear">"nulstil system til fabriksstandarder"</string>
+ <string name="permdesc_masterClear">"Tillader et program fuldstændig at nulstille systemet til fabriksindstillingerne, slette alle data, konfigurationen og installerede programmer."</string>
+ <string name="permlab_setTimeZone">"indstil tidszone"</string>
+ <string name="permdesc_setTimeZone">"Tillader et program at ændre telefonens tidszone."</string>
+ <string name="permlab_getAccounts">"opdag kendte konti"</string>
+ <string name="permdesc_getAccounts">"Tillader et program at hente listen over konti, der er kendt af telefonen."</string>
+ <string name="permlab_accessNetworkState">"vis netværkstilstand"</string>
+ <string name="permdesc_accessNetworkState">"Tillader et program at vise tilstanden for alle netværk."</string>
+ <string name="permlab_createNetworkSockets">"Fuld internetadgang"</string>
+ <string name="permdesc_createNetworkSockets">"Tillader et program at oprette netværks-sockets."</string>
+ <string name="permlab_writeApnSettings">"skriv indstillinger for adgangspunktnavn"</string>
+ <string name="permdesc_writeApnSettings">"Tillader et program at ændre APN-indstillingerne, som f.eks. enhver APNs Proxy og Port."</string>
+ <string name="permlab_changeNetworkState">"skift netværksforbindelse"</string>
+ <string name="permdesc_changeNetworkState">"Tillader et program at ændre netværksforbindelsens tilstand."</string>
+ <string name="permlab_changeBackgroundDataSetting">"skift brugerindstilling for baggrundsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Tillader et program at ændre brugerindstillingerne for baggrundsdata."</string>
+ <string name="permlab_accessWifiState">"vis Wi-Fi-tilstand"</string>
+ <string name="permdesc_accessWifiState">"Tillader et program at vise oplysninger om Wi-Fi-tilstanden."</string>
+ <string name="permlab_changeWifiState">"skift Wi-Fi-tilstand"</string>
+ <string name="permdesc_changeWifiState">"Tillader et program at oprette og afbryde forbindelse fra Wi-Fi-adgangspunkter og foretage ændringer til konfigurerede Wi-Fi-netværk."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-administration"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillader et program at konfigurere den lokale Bluetooth-telefon samt at opdage og parre med fjerne enheder."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"opret Bluetooth-forbindelser"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Tillader et program at vise konfigurationen af den lokale Bluetooth-telefon samt at oprette og acceptere forbindelse med parrede enheder."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"deaktiver tastaturlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillader et program at deaktivere tastaturlåsen og al associeret adgangskodesikkerhed. Et legitimt eksempel på dette er, at telefonen deaktiverer tastaturlåsen, når der modtages et indgående telefonopkald, og genaktiverer tastaturlåsen, når opkaldet er afsluttet."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"læs synkroniseringsindstillinger"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Tillader et program at læse synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontakter."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skriv synkroniseringsindstillinger"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Tillader et program at ændre synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontakter."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"læs synkroniseringsstatistikker"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Tillader et program at læse synkroniseringsstatistikkerne, som f.eks. oversigt over forekomne synkroniseringer."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"læs abonnerede feeds"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Lader et program få detaljer om de aktuelt synkroniserede feeds."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skriv abonnerede feeds"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Tillader et program at ændre dine aktuelle synkroniserede feeds. Dette kan muligvis lade et ondsindet program ændre dine synkroniserede feeds."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"læs brugerdefineret ordbog"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Tillader et program at læse alle private ord, navne og sætninger, som brugeren eventuelt har gemt i brugerordbogen."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skriv til den brugerdefinerede mappe"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Tillader et program at skrive nye ord i brugermappen."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth-administration"</string>
+ <string name="permdesc_bluetoothAdmin">"Tillader et program at konfigurere den lokale Bluetooth-telefon samt at opdage og parre med fjerne enheder."</string>
+ <string name="permlab_bluetooth">"opret Bluetooth-forbindelser"</string>
+ <string name="permdesc_bluetooth">"Tillader et program at vise konfigurationen af den lokale Bluetooth-telefon samt at oprette og acceptere forbindelse med parrede enheder."</string>
+ <string name="permlab_disableKeyguard">"deaktiver tastaturlås"</string>
+ <string name="permdesc_disableKeyguard">"Tillader et program at deaktivere tastaturlåsen og al associeret adgangskodesikkerhed. Et legitimt eksempel på dette er, at telefonen deaktiverer tastaturlåsen, når der modtages et indgående telefonopkald, og genaktiverer tastaturlåsen, når opkaldet er afsluttet."</string>
+ <string name="permlab_readSyncSettings">"læs synkroniseringsindstillinger"</string>
+ <string name="permdesc_readSyncSettings">"Tillader et program at læse synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontaktpersoner."</string>
+ <string name="permlab_writeSyncSettings">"skriv synkroniseringsindstillinger"</string>
+ <string name="permdesc_writeSyncSettings">"Tillader et program at ændre synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontaktpersoner."</string>
+ <string name="permlab_readSyncStats">"læs synkroniseringsstatistikker"</string>
+ <string name="permdesc_readSyncStats">"Tillader et program at læse synkroniseringsstatistikkerne, som f.eks. oversigt over forekomne synkroniseringer."</string>
+ <string name="permlab_subscribedFeedsRead">"læs abonnerede feeds"</string>
+ <string name="permdesc_subscribedFeedsRead">"Lader et program få detaljer om de aktuelt synkroniserede feeds."</string>
+ <string name="permlab_subscribedFeedsWrite">"skriv abonnerede feeds"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Tillader et program at ændre dine aktuelle synkroniserede feeds. Dette kan muligvis lade et ondsindet program ændre dine synkroniserede feeds."</string>
+ <string name="permlab_readDictionary">"læs brugerdefineret ordbog"</string>
+ <string name="permdesc_readDictionary">"Tillader et program at læse alle private ord, navne og sætninger, som brugeren eventuelt har gemt i brugerordbogen."</string>
+ <string name="permlab_writeDictionary">"skriv til den brugerdefinerede mappe"</string>
+ <string name="permdesc_writeDictionary">"Tillader et program at skrive nye ord i brugermappen."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Start"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbejde"</item>
- <item msgid="1103601433382158155">"Arbejdsfax"</item>
- <item msgid="1735177144948329370">"Hjemmefax"</item>
- <item msgid="603878674477207394">"Personsøger"</item>
- <item msgid="1650824275177931637">"Andet"</item>
- <item msgid="9192514806975898961">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Mobil"</item>
+ <item>"Arbejde"</item>
+ <item>"Arbejdsfax"</item>
+ <item>"Hjemmefax"</item>
+ <item>"Personsøger"</item>
+ <item>"Andet"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Start"</item>
- <item msgid="7084237356602625604">"Arbejde"</item>
- <item msgid="1112044410659011023">"Andre"</item>
- <item msgid="2374913952870110618">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Start"</item>
- <item msgid="5629153956045109251">"Arbejde"</item>
- <item msgid="4966604264500343469">"Andre"</item>
- <item msgid="4932682847595299369">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Start"</item>
- <item msgid="1359644565647383708">"Arbejde"</item>
- <item msgid="7868549401053615677">"Anden"</item>
- <item msgid="3145118944639869809">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbejde"</item>
- <item msgid="4378074129049520373">"Andre"</item>
- <item msgid="3455047468583965104">"Tilpasset"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Indtast PIN-kode"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Forkert PIN-kode!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Tryk på Menu og dernæst på 0 for at låse op."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen tjeneste)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skærmen er låst."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryk på Menu for at låse op."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Tegn mønster til at låse op"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nødopkald"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Rigtigt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Beklager! Prøv igen"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Oplader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Indtast PIN-kode"</string>
+ <string name="keyguard_password_wrong_pin_code">"Forkert PIN-kode!"</string>
+ <string name="keyguard_label_text">"Tryk på Menu og dernæst på 0 for at låse op."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nødnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen tjeneste)"</string>
+ <string name="lockscreen_screen_locked">"Skærmen er låst."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Tryk på Menu for at låse op."</string>
+ <string name="lockscreen_pattern_instructions">"Tegn mønster til at låse op"</string>
+ <string name="lockscreen_emergency_call">"Nødopkald"</string>
+ <string name="lockscreen_pattern_correct">"Rigtigt!"</string>
+ <string name="lockscreen_pattern_wrong">"Beklager! Prøv igen"</string>
+ <string name="lockscreen_plugged_in">"Oplader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Tilslut din oplader."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Der er ikke noget SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Der er ikke noget SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Indsæt et SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netværket er låst"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kort er låst med PUK-koden."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se brugervejledningen, eller kontakt kundeservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser SIM-kortet op ..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Har du glemt mønster?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"For mange mønsterforsøg!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"For at låse op skal du logge ind med din Google-konto"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Brugernavn (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Adgangskode"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Log ind"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Tilslut din oplader."</string>
+ <string name="lockscreen_missing_sim_message_short">"Der er ikke noget SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Der er ikke noget SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Indsæt et SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Netværket er låst"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kort er låst med PUK-koden."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se brugervejledningen, eller kontakt kundeservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet er låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser SIM-kortet op ..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Har du glemt mønster?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"For mange mønsterforsøg!"</string>
+ <string name="lockscreen_glogin_instructions">"For at låse op skal du logge ind med din Google-konto"</string>
+ <string name="lockscreen_glogin_username_hint">"Brugernavn (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Adgangskode"</string>
+ <string name="lockscreen_glogin_submit_button">"Log ind"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen meddelelser"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Løbende"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelelser"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Oplader ..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Forbind oplader"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er ved at blive tomt:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"mindre end <xliff:g id="NUMBER">%d%%</xliff:g> tilbage."</string>
+ <string name="status_bar_no_notifications_title">"Ingen meddelelser"</string>
+ <string name="status_bar_ongoing_events_title">"Løbende"</string>
+ <string name="status_bar_latest_events_title">"Meddelelser"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Oplader ..."</string>
+ <string name="battery_low_title">"Forbind oplader"</string>
+ <string name="battery_low_subtitle">"Batteriet er ved at blive tomt:"</string>
+ <string name="battery_low_percent_format">"mindre end <xliff:g id="NUMBER">%d%%</xliff:g> tilbage."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabrikstest mislykkedes"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Handlingen FACTORY_TEST understøttes kun af pakker installeret i /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Der blev ikke fundet nogen pakke, som leverer handlingen FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Genstart"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Siden på \'<xliff:g id="TITLE">%s</xliff:g>\' siger:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Naviger væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Vælg OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
+ <string name="factorytest_failed">"Fabrikstest mislykkedes"</string>
+ <string name="factorytest_not_system">"Handlingen FACTORY_TEST understøttes kun af pakker installeret i /system/app."</string>
+ <string name="factorytest_no_action">"Der blev ikke fundet nogen pakke, som leverer handlingen FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Genstart"</string>
+ <string name="js_dialog_title">"Siden på \'<xliff:g id="TITLE">%s</xliff:g>\' siger:"</string>
+ <string name="js_dialog_title_default">"Javascript"</string>
+ <string name="js_dialog_before_unload">"Naviger væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Vælg OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
+ <string name="save_password_label">"Bekræft"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldrig"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har ikke tilladelse til at åbne denne side."</string>
- <string name="text_copied" msgid="4985729524670131385">"Teksten er kopieret til udklipsholderen."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Flere"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"plads"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"indtast"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"slet"</string>
- <string name="search_go" msgid="8298016669822141719">"Søg"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"For 1 måned siden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
+ <string name="save_password_message">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
+ <string name="save_password_notnow">"Ikke nu"</string>
+ <string name="save_password_remember">"Husk"</string>
+ <string name="save_password_never">"Aldrig"</string>
+ <string name="open_permission_deny">"Du har ikke tilladelse til at åbne denne side."</string>
+ <string name="text_copied">"Teksten er kopieret til udklipsholderen."</string>
+ <string name="more_item_label">"Flere"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"plads"</string>
+ <string name="menu_enter_shortcut_label">"indtast"</string>
+ <string name="menu_delete_shortcut_label">"slet"</string>
+ <string name="search_go">"Søg"</string>
+ <string name="oneMonthDurationPast">"For 1 måned siden"</string>
+ <string name="beforeOneMonthDurationPast">"Før for 1 måned siden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"For 1 sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"For <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
+ <item quantity="one">"For 1 sekund siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"For 1 minut siden"</item>
- <item quantity="other" msgid="2176942008915455116">"For <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
+ <item quantity="one">"For 1 minut siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"For 1 time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"For 1 time siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 time"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om 1 time"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"For 1 sek. siden"</item>
- <item quantity="other" msgid="3699169366650930415">"For <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
+ <item quantity="one">"For 1 sek. siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"For 1 min. siden"</item>
- <item quantity="other" msgid="851164968597150710">"For <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
+ <item quantity="one">"For 1 min. siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"For 1 time siden"</item>
- <item quantity="other" msgid="6889970745748538901">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"For 1 time siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek."</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sek."</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"om 1 min."</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 time"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om 1 time"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"den %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"kl. %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"i %s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dage"</string>
- <string name="hour" msgid="2126771916426189481">"time"</string>
- <string name="hours" msgid="894424005266852993">"timer"</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"sek."</string>
- <string name="seconds" msgid="3161515347216589235">"sek."</string>
- <string name="week" msgid="5617961537173061583">"uge"</string>
- <string name="weeks" msgid="6509623834583944518">"uger"</string>
- <string name="year" msgid="4001118221013892076">"år"</string>
- <string name="years" msgid="6881577717993213522">"år"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hver ugedag (man.-fre.)"</string>
- <string name="daily" msgid="5738949095624133403">"Dagligt"</string>
- <string name="weekly" msgid="983428358394268344">"Ugentlig hver <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Månedligt"</string>
- <string name="yearly" msgid="1519577999407493836">"Årligt"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kan ikke afspilles"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Beklager! Denne video er ikke gyldig til streaming på denne enhed."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Beklager! Denne video kan ikke afspilles."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"middag"</string>
- <string name="Noon" msgid="3342127745230013127">"Middag"</string>
- <string name="midnight" msgid="7166259508850457595">"midnat"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnat"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string>
- <string name="selectText" msgid="3889149123626888637">"Vælg tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Stands med at vælge tekst"</string>
- <string name="cut" msgid="3092569408438626261">"Klip"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klip alle"</string>
- <string name="copy" msgid="2681946229533511987">"Kopier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopier alle"</string>
- <string name="paste" msgid="5629880836805036433">"Indsæt"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Inputmetode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Føj \"%s\" til ordbog"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Rediger tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Der er ikke så meget plads tilbage"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Der er næsten ikke mere plads på telefonen."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuller"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Bemærk"</string>
- <string name="capital_on" msgid="1544682755514494298">"TIL"</string>
- <string name="capital_off" msgid="6815870386972805832">"FRA"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Afslut handling ved hjælp af"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ryd standard i Startindstillinger > Programmer > Administrer programmer."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Vælg en handling"</string>
- <string name="noApplications" msgid="1691104391758345586">"Der er ingen programmer, der kan foretage denne handling."</string>
- <string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> er standset uventet. Prøv igen."</string>
- <string name="anr_title" msgid="3100070910664756057">"Beklager!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."</string>
- <string name="force_close" msgid="3653416315450806396">"Tving til at lukke"</string>
+ <string name="preposition_for_date">"den %s"</string>
+ <string name="preposition_for_time">"kl. %s"</string>
+ <string name="preposition_for_year">"i %s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dage"</string>
+ <string name="hour">"time"</string>
+ <string name="hours">"timer"</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"sek."</string>
+ <string name="seconds">"sek."</string>
+ <string name="week">"uge"</string>
+ <string name="weeks">"uger"</string>
+ <string name="year">"år"</string>
+ <string name="years">"år"</string>
+ <string name="every_weekday">"Hver ugedag (man.-fre.)"</string>
+ <string name="daily">"Dagligt"</string>
+ <string name="weekly">"Ugentlig hver <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Månedligt"</string>
+ <string name="yearly">"Årligt"</string>
+ <string name="VideoView_error_title">"Video kan ikke afspilles"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Beklager! Denne video er ikke gyldig til streaming på denne enhed."</string>
+ <string name="VideoView_error_text_unknown">"Beklager! Denne video kan ikke afspilles."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"middag"</string>
+ <string name="Noon">"Middag"</string>
+ <string name="midnight">"midnat"</string>
+ <string name="Midnight">"Midnat"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Vælg alle"</string>
+ <string name="selectText">"Vælg tekst"</string>
+ <string name="stopSelectingText">"Stands med at vælge tekst"</string>
+ <string name="cut">"Klip"</string>
+ <string name="cutAll">"Klip alle"</string>
+ <string name="copy">"Kopier"</string>
+ <string name="copyAll">"Kopier alle"</string>
+ <string name="paste">"Indsæt"</string>
+ <string name="copyUrl">"Kopier webadresse"</string>
+ <string name="inputMethod">"Inputmetode"</string>
+ <string name="addToDictionary">"Føj \"%s\" til ordbog"</string>
+ <string name="editTextMenuTitle">"Rediger tekst"</string>
+ <string name="low_internal_storage_view_title">"Der er ikke så meget plads tilbage"</string>
+ <string name="low_internal_storage_view_text">"Der er næsten ikke mere plads på telefonen."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuller"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuller"</string>
+ <string name="dialog_alert_title">"Bemærk"</string>
+ <string name="capital_on">"TIL"</string>
+ <string name="capital_off">"FRA"</string>
+ <string name="whichApplication">"Afslut handling ved hjælp af"</string>
+ <string name="alwaysUse">"Brug som standard til denne handling."</string>
+ <string name="clearDefaultHintMsg">"Ryd standard i Startindstillinger > Programmer > Administrer programmer."</string>
+ <string name="chooseActivity">"Vælg en handling"</string>
+ <string name="noApplications">"Der er ingen programmer, der kan foretage denne handling."</string>
+ <string name="aerr_title">"Beklager!"</string>
+ <string name="aerr_application">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
+ <string name="aerr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> er standset uventet. Prøv igen."</string>
+ <string name="anr_title">"Beklager!"</string>
+ <string name="anr_activity_application">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_activity_process">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_application_process">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."</string>
+ <string name="force_close">"Tving til at lukke"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Vent"</string>
- <string name="debug" msgid="9103374629678531849">"Fejlretning"</string>
- <string name="sendText" msgid="5132506121645618310">"Vælg en handling for teksten"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Opkaldslydstyrke"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medielydstyrke"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spiller gennem Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Opkaldslydstyrke"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth-lydstyrke under opkald"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmlydstyrke"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Meddelelseslydstyrke"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Lydstyrke"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Lydløs"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Ukendt ringetone"</string>
+ <string name="wait">"Vent"</string>
+ <string name="debug">"Fejlretning"</string>
+ <string name="sendText">"Vælg en handling for teksten"</string>
+ <string name="volume_ringtone">"Opkaldslydstyrke"</string>
+ <string name="volume_music">"Medielydstyrke"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spiller gennem Bluetooth"</string>
+ <string name="volume_call">"Opkaldslydstyrke"</string>
+ <string name="volume_bluetooth_call">"Bluetooth-lydstyrke under opkald"</string>
+ <string name="volume_alarm">"Alarmlydstyrke"</string>
+ <string name="volume_notification">"Meddelelseslydstyrke"</string>
+ <string name="volume_unknown">"Lydstyrke"</string>
+ <string name="ringtone_default">"Standardringetone"</string>
+ <string name="ringtone_default_with_actual">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Lydløs"</string>
+ <string name="ringtone_picker_title">"Ringetoner"</string>
+ <string name="ringtone_unknown">"Ukendt ringetone"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netværk tilgængeligt"</item>
- <item quantity="other" msgid="4192424489168397386">"Tilgængelige Wi-Fi-netværk"</item>
+ <item quantity="one">"Wi-Fi-netværk tilgængeligt"</item>
+ <item quantity="other">"Tilgængelige Wi-Fi-netværk"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Åbent Wi-Fi-netværk tilgængeligt"</item>
- <item quantity="other" msgid="7915895323644292768">"Der er åbne Wi-Fi-netværk tilgængelige"</item>
+ <item quantity="one">"Åbent Wi-Fi-netværk tilgængeligt"</item>
+ <item quantity="other">"Der er åbne Wi-Fi-netværk tilgængelige"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Ukendt program"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-beskeder"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Der sendes et stort antal SMS-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe med at sende."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuller"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Indstil"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skjul"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Indlæser ..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB forbundet"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har forbundet din telefon til din computer via USB. Vælg \"Monter\", hvis du ønsker at kopiere filer mellem din computer og din telefons SD-kort."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Monter"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Indsæt ikke"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Der opstod et problem med at bruge dit SD-kort til USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB forbundet"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Vælg for at kopiere filer til/fra din computer."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Slå USB-lagringen fra"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Vælg for at slå USB-lagring fra."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Slå USB-lagring fra"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Inden du slår USB-lagringen fra, skal du sørge for, at du demonterer USB-værten. Vælg \"Slå fra\" for at slå USB-lagringen fra."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Slå fra"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuller"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Der opstod et problem med at slå USB-lagringen fra. Sørg for, at du har demonteret USB-værten, og prøv så igen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formater SD-kort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Er du sikker på, du ønsker at formatere SD-kortet? Alle data på kortet mistes."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formater"</string>
+ <string name="select_character">"Indsæt tegn"</string>
+ <string name="sms_control_default_app_name">"Ukendt program"</string>
+ <string name="sms_control_title">"Sender SMS-beskeder"</string>
+ <string name="sms_control_message">"Der sendes et stort antal SMS-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe med at sende."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuller"</string>
+ <string name="date_time_set">"Indstil"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Der kræves ingen tilladelser"</string>
+ <string name="perms_hide"><b>"Skjul"</b></string>
+ <string name="perms_show_all"><b>"Vis alle"</b></string>
+ <string name="googlewebcontenthelper_loading">"Indlæser ..."</string>
+ <string name="usb_storage_title">"USB forbundet"</string>
+ <string name="usb_storage_message">"Du har forbundet din telefon til din computer via USB. Vælg \"Monter\", hvis du ønsker at kopiere filer mellem din computer og din telefons SD-kort."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Indsæt ikke"</string>
+ <string name="usb_storage_error_message">"Der opstod et problem med at bruge dit SD-kort til USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB forbundet"</string>
+ <string name="usb_storage_notification_message">"Vælg for at kopiere filer til/fra din computer."</string>
+ <string name="usb_storage_stop_notification_title">"Slå USB-lagringen fra"</string>
+ <string name="usb_storage_stop_notification_message">"Vælg for at slå USB-lagring fra."</string>
+ <string name="usb_storage_stop_title">"Slå USB-lagring fra"</string>
+ <string name="usb_storage_stop_message">"Inden du slår USB-lagringen fra, skal du sørge for, at du demonterer USB-værten. Vælg \"Slå fra\" for at slå USB-lagringen fra."</string>
+ <string name="usb_storage_stop_button_mount">"Slå fra"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuller"</string>
+ <string name="usb_storage_stop_error_message">"Der opstod et problem med at slå USB-lagringen fra. Sørg for, at du har demonteret USB-værten, og prøv så igen."</string>
+ <string name="extmedia_format_title">"Formater SD-kort"</string>
+ <string name="extmedia_format_message">"Er du sikker på, du ønsker at formatere SD-kortet? Alle data på kortet mistes."</string>
+ <string name="extmedia_format_button_format">"Formater"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Vælg inputmetode"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Forbereder SD-kort"</string>
+ <string name="select_input_method">"Vælg inputmetode"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidater"</u></string>
+ <string name="ext_media_checking_notification_title">"Forbereder SD-kort"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Blankt SD-kort"</string>
+ <string name="ext_media_nofs_notification_title">"Blankt SD-kort"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beskadiget SD-kort"</string>
+ <string name="ext_media_unmountable_notification_title">"Beskadiget SD-kort"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kort blev uventet fjernet"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Demonter SD-kortet inden fjernelse for at undgå tab af data."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD-kortet kan fjernes sikkert"</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kort blev uventet fjernet"</string>
+ <string name="ext_media_badremoval_notification_message">"Demonter SD-kortet inden fjernelse for at undgå tab af data."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD-kortet kan fjernes sikkert"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-kortet er fjernet"</string>
+ <string name="ext_media_nomedia_notification_title">"SD-kortet er fjernet"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Der blev ikke fundet nogen matchende aktiviteter"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"opdater brugerstatistikker for komponenter"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillader ændring af indsamlede brugerstatistikker for komponenter. Ikke til brug til normale programmer."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tryk to gange for zoomkontrol"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Der opstod en fejl under forøgelsen af widgeten"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Gå"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Søg"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Send"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Næste"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Færdig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Udfør"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Ring til nummer"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Opret kontakt"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Der blev ikke fundet nogen matchende aktiviteter"</string>
+ <string name="permlab_pkgUsageStats">"opdater brugerstatistikker for komponenter"</string>
+ <string name="permdesc_pkgUsageStats">"Tillader ændring af indsamlede brugerstatistikker for komponenter. Ikke til brug til normale programmer."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tryk to gange for zoomkontrol"</string>
+ <string name="gadget_host_error_inflating">"Der opstod en fejl under forøgelsen af widgeten"</string>
+ <string name="ime_action_go">"Gå"</string>
+ <string name="ime_action_search">"Søg"</string>
+ <string name="ime_action_send">"Send"</string>
+ <string name="ime_action_next">"Næste"</string>
+ <string name="ime_action_done">"Færdig"</string>
+ <string name="ime_action_default">"Udfør"</string>
+ <string name="dial_number_using">"Ring til nummer"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Opret kontaktperson"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 34e52a5..9163c61 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<Unbenannt>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Keine Telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Unbekannt)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mailbox"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Verbindungsproblem oder ungültiger MMI-Code."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Dienst wurde aktiviert."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Dienst wurde aktiviert für:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Dienst wurde deaktiviert."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrierung war erfolgreich."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Löschvorgang erfolgreich."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Falsches Passwort."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI abgeschlossen."</string>
- <string name="badPin" msgid="5085454289896032547">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
- <string name="badPuk" msgid="5702522162746042460">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
- <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Anrufer-ID für eingehenden Anruf"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für abgehenden Anruf"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Rufweiterleitung"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Anklopfen"</string>
- <string name="BaMmi" msgid="455193067926770581">"Anrufsperre"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Passwort-Änderung"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-Änderung"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Rufnummer vorhanden"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Rufnummer begrenzt"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Dreierkonferenz"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Ablehnung unerwünschter Anrufe"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Rufnummernübermittlung"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Bitte nicht stören"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Dienst nicht eingerichtet."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Die Einstellung für die Anrufer-ID kann nicht geändert werden."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Eingeschränkter Zugriff geändert"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Daten-Dienst ist gesperrt."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Notruf ist gesperrt."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Sprach-/SMS-Dienst ist gesperrt."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle Sprach-/SMS-Dienste sind gesperrt."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Sprachnotiz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Daten"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchron"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchron"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roaming-Anzeige ein"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roaming-Anzeige aus"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roaming-Anzeige blinkend"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Außerhalb der Netzwerkumgebung"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Außerhalb des Gebäudes"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Bevorzugtes System"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Verfügbares System"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Allianzpartner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Premiumpartner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Volle Dienstfunktionalität"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Partielle Dienstfunktionalität"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roaming-Banner ein"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roaming-Banner aus"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Suche nach Dienst"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Funktionscode abgeschlossen"</string>
- <string name="fcError" msgid="3327560126588500777">"Verbindungsproblem oder ungültiger Funktionscode"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Auf der Webseite ist ein Fehler aufgetreten."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Die URL konnte nicht gefunden werden."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Das Authentifizierungsschema für die Site wird nicht unterstützt."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Authentifizierung ist fehlgeschlagen."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Es konnte keine Verbindung zum Server hergestellt werden."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Die Server-Kommunikation ist fehlgeschlagen. Versuchen Sie es später erneut."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Die Seite enthält zu viele Server-Redirects."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Das Protokoll wird nicht unterstützt."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Es konnte keine sichere Verbindung aufgebaut werden."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Die Seite konnte nicht geöffnet werden, weil die URL ungültig ist."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Auf die Datei konnte nicht zugegriffen werden."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Die angeforderte Datei wurde nicht gefunden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronisieren"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisieren"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
- <string name="me" msgid="6545696007631404292">"Eigene"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonoptionen"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Lautlos-Modus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Funk einschalten"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bildschirmsperre"</string>
- <string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Herunterfahren..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Ihr Telefon wird heruntergefahren."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Keine neuen Anwendungen."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonoptionen"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bildschirmsperre"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lautlos"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ton ist bereits AUS"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ton ist momentan AN"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS"</string>
- <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Ihr Standort"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Ihre Google-Konten"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Greift auf verfügbare Google-Konten zu."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkter Zugriff auf Hardware über Headset"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Anrufe"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Überwachen, Aufzeichnen und Verarbeiten von Telefonanrufen"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"System-Tools"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Zugriff und Steuerung des Systems auf niedrigerer Ebene."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Entwickler-Tools"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Greift auf die SD-Karte zu."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"Statusleiste ein-/ausblenden"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Abgehende Anrufe abfangen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS empfangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS empfangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Ermöglicht der Anwendung, MMS-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"Kurznachrichten senden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Ermöglicht Anwendungen das Senden von SMS-Nachrichten. Bei schädlichen Anwendungen können Kosten entstehen, wenn diese Nachrichten ohne Ihre Zustimmung versenden."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS oder MMS lesen"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu lesen. Schädliche Anwendungen lesen so möglicherweise Ihre vertraulichen Nachrichten."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS oder MMS bearbeiten"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu bearbeiten. Schädliche Anwendungen löschen möglicherweise Ihre Nachrichten."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP-Nachrichten empfangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Ermöglicht der Anwendung, WAP-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"Laufende Anwendungen abrufen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"Andere Anwendungen neu starten"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Ermöglicht einer Anwendung, den Neustart anderer Anwendungen zu erzwingen."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"Schließen von Anwendung erzwingen"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Ermöglicht einer Anwendung, den internen Status des Systems abzurufen. Schädliche Anwendungen rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"partielles Herunterfahren"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Anwendungswechsel verhindern"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindert den Nutzer daran, zu einer anderen Anwendung zu wechseln"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"Start von Anwendungen überwachen und steuern"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Ermöglicht der Anwendung, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Anwendungen können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Telefonnutzung benötigt."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Broadcast ohne Paket senden"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Ermöglicht einer Anwendung, eine Benachrichtigung zur Entfernung eines Anwendungspakets zu senden. Schädliche Anwendungen können so laufende Anwendungen beenden."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"per SMS empfangenen Broadcast senden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine Kurzmitteilung empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Eingang von Kurzmitteilungen zu erzwingen."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"von WAP-PUSH empfangenen Broadcast senden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Erhalt von MMS-Mitteilungen zu erzwingen, oder um unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte zu ersetzen."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Ermöglicht einer Anwendung, die maximale Anzahl an laufenden Prozessen zu steuern. Wird nicht für normale Anwendungen benötigt."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle Anwendungen im Hintergrund schließen"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Überlässt einer Anwendung die Entscheidung, ob Aktivitäten beendet werden, sobald Sie in den Hintergrund rücken. Wird nicht für normale Anwendungen benötigt."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"Akku-Daten ändern"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_backup" msgid="470013022865453920">"Systemsicherung und -wiederherstellung kontrollieren"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Ermöglicht der Anwendung, den Sicherungs- und Wiederherstellungsmechanismus des Systems zu kontrollieren. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"nicht autorisierte Fenster anzeigen"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"Anwendungs-Tokens verwalten"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"Tasten und Steuerungstasten drücken"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Ermöglicht einer Anwendung, ihre eigenen Eingabeaktionen (Drücken von Tasten etc.) an andere Anwendungen zu liefern. Schädliche Anwendungen können so die Kontrolle über Ihr Telefon übernehmen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"Tastatureingaben und Aktionen aufzeichnen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Ermöglicht Anwendungen, die von Ihnen gedrückten Tasten zu überwachen (etwa die Eingabe eines Passworts). Dies gilt auch für die Interaktion mit anderen Anwendungen. Sollte für normale Anwendungen nicht benötigt werden."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"An eine Eingabemethode binden"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Anwendungen benötigt werden."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"Anwendungen löschen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"Daten anderer Anwendungen löschen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Caches anderer Anwendungen löschen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"Speicherplatz der Anwendung abrufen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"Anwendungen direkt installieren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"Alle Cache-Daten der Anwendung löschen"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"System-Protokolldateien lesen"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Ermöglicht einer Anwendung, die Komponente einer anderen Anwendung nach Belieben zu aktivieren oder zu deaktivieren. Schädliche Anwendungen können so wichtige Funktionen des Telefons deaktivieren. Bei der Erteilung von Berechtigungen ist daher Vorsicht geboten, da die Anwendungskomponenten unbrauchbar, inkonsistent und unstabil werden können."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"Bevorzugte Einstellungen festlegen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Ermöglicht einer Anwendung, Ihre bevorzugten Einstellungen zu ändern. Schädliche Anwendungen können so laufende Anwendungen ohne Ihr Wissen ändern, damit die vorhandenen Anwendungen private Daten von Ihnen sammeln."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"Allgemeine Systemeinstellungen ändern"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Ermöglicht einer Anwendung, die Einstellungsdaten des Systems zu ändern. Schädliche Anwendungen können so die Systemkonfiguration beschädigen."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"Sicherheitseinstellungen für das System ändern"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Ermöglicht einer Anwendung, die Daten der Sicherheitseinstellungen des Systems zu ändern. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google Services Map ändern"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Ermöglicht einer Anwendung, Änderungen an der Google Services Map vorzunehmen. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"Automatisch nach dem Booten starten"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"dauerhaften Broadcast senden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Kontaktdaten lesen"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"Kontaktdaten schreiben"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern. Schädliche Anwendungen können so Ihre Kontaktdaten löschen oder verändern."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"Eigentümerdaten schreiben"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu ändern. Schädliche Anwendungen können so Eigentümerdaten löschen oder verändern."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Eigentümerdaten lesen"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu lesen. Schädliche Anwendungen können so Eigentümerdaten lesen."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Kalenderdaten lesen"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"Kalenderdaten schreiben"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kalenderereignisse zu ändern. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Falsche Standortquellen für Testzwecke"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Berechtigung zur Installation eines Standortanbieters"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben oder Ihren Standort überwachen und an eine externe Quelle weitergeben."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"genauer (GPS-) Standort"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ungefährer (netzwerkbasierter) Standort"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Ermöglicht einer Anwendung, den Inhalt des Frame-Puffers zu lesen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"Fotos aufnehmen"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Ermöglicht der Anwendung, Fotos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder zusammentragen, die von der Kamera erfasst werden."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren."</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"Neustart des Telefons erzwingen"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Externen Speicher formatieren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Erlaubt der Anwendung, austauschbaren Speicher zu formatieren."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"Vibrationsalarm steuern"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"Hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"Alle Telefonnummern direkt anrufen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Ermöglicht der Anwendung, ohne Ihr Eingreifen eine beliebige Telefonnummer zu wählen, einschließlich Notfallnummern. Schädliche Anwendungen können so unnötige und illegale Anrufe an Notdienste tätigen."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"Benachrichtigungen für Standortaktualisierung steuern"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Ermöglicht die Aktivierung/Deaktivierung der Mobilfunkbenachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"Auf Check-In-Eigenschaften zugreifen"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"Widgets auswählen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Ermöglicht der Anwendung, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Telefonstatus ändern"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"In Werkstestmodus ausführen"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"Hintergrundbild festlegen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, das System-Hintergrundbild festzulegen."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Größenhinweise für Hintergrundbild festlegen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für das Hintergrundbild festzulegen."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"System auf Werkseinstellung zurücksetzen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"Zeitzone festlegen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bekannte Konten suchen"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Uneingeschränkter Internetzugriff"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Einstellungen für Zugriffspunktname schreiben"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"Netzwerkkonnektivität ändern"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"WLAN-Status anzeigen"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"WLAN-Status ändern"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-Verwaltung"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-Verbindungen herstellen"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Synchronisierungseinstellungen schreiben"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Abonnierte Feeds lesen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"Abonnierte Feeds schreiben"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"Nutzerdefiniertes Wörterbuch lesen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Erlaubt einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"in nutzerdefiniertes Wörterbuch schreiben"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Erlaubt einer Anwendung, neue Wörter in das Wörterbuch des Nutzers zu schreiben."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"SD-Karten-Inhalt ändern/löschen"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<Unbenannt>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Keine Telefonnummer)"</string>
+ <string name="unknownName">"(Unbekannt)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Mailbox"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Verbindungsproblem oder ungültiger MMI-Code."</string>
+ <string name="serviceEnabled">"Dienst wurde aktiviert."</string>
+ <string name="serviceEnabledFor">"Dienst wurde aktiviert für:"</string>
+ <string name="serviceDisabled">"Dienst wurde deaktiviert."</string>
+ <string name="serviceRegistered">"Registrierung war erfolgreich."</string>
+ <string name="serviceErased">"Löschvorgang erfolgreich."</string>
+ <string name="passwordIncorrect">"Falsches Passwort."</string>
+ <string name="mmiComplete">"MMI abgeschlossen."</string>
+ <string name="badPin">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
+ <string name="badPuk">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
+ <string name="mismatchPin">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
+ <string name="invalidPin">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
+ <string name="needPuk">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
+ <string name="needPuk2">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
+ <string name="ClipMmi">"Anrufer-ID für eingehenden Anruf"</string>
+ <string name="ClirMmi">"Anrufer-ID für abgehenden Anruf"</string>
+ <string name="CfMmi">"Rufweiterleitung"</string>
+ <string name="CwMmi">"Anklopfen"</string>
+ <string name="BaMmi">"Anrufsperre"</string>
+ <string name="PwdMmi">"Passwort-Änderung"</string>
+ <string name="PinMmi">"PIN-Änderung"</string>
+ <string name="CnipMmi">"Rufnummer vorhanden"</string>
+ <string name="CnirMmi">"Rufnummer begrenzt"</string>
+ <string name="ThreeWCMmi">"Dreierkonferenz"</string>
+ <string name="RuacMmi">"Ablehnung unerwünschter Anrufe"</string>
+ <string name="CndMmi">"Rufnummernübermittlung"</string>
+ <string name="DndMmi">"Bitte nicht stören"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+ <string name="serviceNotProvisioned">"Dienst nicht eingerichtet."</string>
+ <string name="CLIRPermanent">"Die Einstellung für die Anrufer-ID kann nicht geändert werden."</string>
+ <string name="RestrictedChangedTitle">"Eingeschränkter Zugriff geändert"</string>
+ <string name="RestrictedOnData">"Daten-Dienst ist gesperrt."</string>
+ <string name="RestrictedOnEmergency">"Notruf ist gesperrt."</string>
+ <string name="RestrictedOnNormal">"Sprach-/SMS-Dienst ist gesperrt."</string>
+ <string name="RestrictedOnAll">"Alle Sprach-/SMS-Dienste sind gesperrt."</string>
+ <string name="serviceClassVoice">"Sprachnotiz"</string>
+ <string name="serviceClassData">"Daten"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchron"</string>
+ <string name="serviceClassDataSync">"Synchron"</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Roaming-Anzeige ein"</string>
+ <string name="roamingText1">"Roaming-Anzeige aus"</string>
+ <string name="roamingText2">"Roaming-Anzeige blinkend"</string>
+ <string name="roamingText3">"Außerhalb der Netzwerkumgebung"</string>
+ <string name="roamingText4">"Außerhalb des Gebäudes"</string>
+ <string name="roamingText5">"Roaming - Bevorzugtes System"</string>
+ <string name="roamingText6">"Roaming - Verfügbares System"</string>
+ <string name="roamingText7">"Roaming - Allianzpartner"</string>
+ <string name="roamingText8">"Roaming - Premiumpartner"</string>
+ <string name="roamingText9">"Roaming - Volle Dienstfunktionalität"</string>
+ <string name="roamingText10">"Roaming - Partielle Dienstfunktionalität"</string>
+ <string name="roamingText11">"Roaming-Banner ein"</string>
+ <string name="roamingText12">"Roaming-Banner aus"</string>
+ <string name="roamingTextSearching">"Suche nach Dienst"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="fcComplete">"Funktionscode abgeschlossen"</string>
+ <string name="fcError">"Verbindungsproblem oder ungültiger Funktionscode"</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Auf der Webseite ist ein Fehler aufgetreten."</string>
+ <string name="httpErrorLookup">"Die URL konnte nicht gefunden werden."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Das Authentifizierungsschema für die Site wird nicht unterstützt."</string>
+ <string name="httpErrorAuth">"Authentifizierung ist fehlgeschlagen."</string>
+ <string name="httpErrorProxyAuth">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
+ <string name="httpErrorConnect">"Es konnte keine Verbindung zum Server hergestellt werden."</string>
+ <string name="httpErrorIO">"Die Server-Kommunikation ist fehlgeschlagen. Versuchen Sie es später erneut."</string>
+ <string name="httpErrorTimeout">"Zeitüberschreitung bei Serververbindung."</string>
+ <string name="httpErrorRedirectLoop">"Die Seite enthält zu viele Server-Redirects."</string>
+ <string name="httpErrorUnsupportedScheme">"Das Protokoll wird nicht unterstützt."</string>
+ <string name="httpErrorFailedSslHandshake">"Es konnte keine sichere Verbindung aufgebaut werden."</string>
+ <string name="httpErrorBadUrl">"Die Seite konnte nicht geöffnet werden, weil die URL ungültig ist."</string>
+ <string name="httpErrorFile">"Auf die Datei konnte nicht zugegriffen werden."</string>
+ <string name="httpErrorFileNotFound">"Die angeforderte Datei wurde nicht gefunden."</string>
+ <string name="httpErrorTooManyRequests">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
+ <string name="contentServiceSync">"Synchronisieren"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronisieren"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
+ <string name="low_memory">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+ <string name="me">"Eigene"</string>
+ <string name="power_dialog">"Telefonoptionen"</string>
+ <string name="silent_mode">"Lautlos-Modus"</string>
+ <string name="turn_on_radio">"Funk einschalten"</string>
+ <string name="turn_off_radio">"Funk ausschalten"</string>
+ <string name="screen_lock">"Bildschirmsperre"</string>
+ <string name="power_off">"Ausschalten"</string>
+ <string name="shutdown_progress">"Herunterfahren..."</string>
+ <string name="shutdown_confirm">"Ihr Telefon wird heruntergefahren."</string>
+ <string name="no_recent_tasks">"Keine neuen Anwendungen."</string>
+ <string name="global_actions">"Telefonoptionen"</string>
+ <string name="global_action_lock">"Bildschirmsperre"</string>
+ <string name="global_action_power_off">"Ausschalten"</string>
+ <string name="global_action_toggle_silent_mode">"Lautlos"</string>
+ <string name="global_action_silent_mode_on_status">"Ton ist bereits AUS"</string>
+ <string name="global_action_silent_mode_off_status">"Ton ist momentan AN"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flugmodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flugmodus ist AN"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flugmodus ist AUS"</string>
+ <string name="safeMode">"Abgesicherter Modus"</string>
+ <string name="android_system_label">"Android System"</string>
+ <string name="permgrouplab_costMoney">"Kostenpflichtige Dienste"</string>
+ <string name="permgroupdesc_costMoney">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+ <string name="permgrouplab_messages">"Ihre Nachrichten"</string>
+ <string name="permgroupdesc_messages">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
+ <string name="permgrouplab_personalInfo">"Ihre persönlichen Informationen"</string>
+ <string name="permgroupdesc_personalInfo">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
+ <string name="permgrouplab_location">"Ihr Standort"</string>
+ <string name="permgroupdesc_location">"Ihren physischen Standort überwachen"</string>
+ <string name="permgrouplab_network">"Netzwerkkommunikation"</string>
+ <string name="permgroupdesc_network">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+ <string name="permgrouplab_accounts">"Ihre Google-Konten"</string>
+ <string name="permgroupdesc_accounts">"Greift auf verfügbare Google-Konten zu."</string>
+ <string name="permgrouplab_hardwareControls">"Hardware-Steuerelemente"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkter Zugriff auf Hardware über Headset"</string>
+ <string name="permgrouplab_phoneCalls">"Anrufe"</string>
+ <string name="permgroupdesc_phoneCalls">"Überwachen, Aufzeichnen und Verarbeiten von Telefonanrufen"</string>
+ <string name="permgrouplab_systemTools">"System-Tools"</string>
+ <string name="permgroupdesc_systemTools">"Zugriff und Steuerung des Systems auf niedrigerer Ebene."</string>
+ <string name="permgrouplab_developmentTools">"Entwickler-Tools"</string>
+ <string name="permgroupdesc_developmentTools">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
+ <string name="permgrouplab_storage">"Speicher"</string>
+ <string name="permgroupdesc_storage">"Greift auf die SD-Karte zu."</string>
+ <string name="permlab_statusBar">"Statusleiste deaktivieren oder ändern"</string>
+ <string name="permdesc_statusBar">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+ <string name="permlab_expandStatusBar">"Statusleiste ein-/ausblenden"</string>
+ <string name="permdesc_expandStatusBar">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
+ <string name="permlab_processOutgoingCalls">"Abgehende Anrufe abfangen"</string>
+ <string name="permdesc_processOutgoingCalls">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
+ <string name="permlab_receiveSms">"SMS empfangen"</string>
+ <string name="permdesc_receiveSms">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_receiveMms">"MMS empfangen"</string>
+ <string name="permdesc_receiveMms">"Ermöglicht der Anwendung, MMS-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_sendSms">"Kurznachrichten senden"</string>
+ <string name="permdesc_sendSms">"Ermöglicht Anwendungen das Senden von SMS-Nachrichten. Bei schädlichen Anwendungen können Kosten entstehen, wenn diese Nachrichten ohne Ihre Zustimmung versenden."</string>
+ <string name="permlab_readSms">"SMS oder MMS lesen"</string>
+ <string name="permdesc_readSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu lesen. Schädliche Anwendungen lesen so möglicherweise Ihre vertraulichen Nachrichten."</string>
+ <string name="permlab_writeSms">"SMS oder MMS bearbeiten"</string>
+ <string name="permdesc_writeSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu bearbeiten. Schädliche Anwendungen löschen möglicherweise Ihre Nachrichten."</string>
+ <string name="permlab_receiveWapPush">"WAP-Nachrichten empfangen"</string>
+ <string name="permdesc_receiveWapPush">"Ermöglicht der Anwendung, WAP-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_getTasks">"Laufende Anwendungen abrufen"</string>
+ <string name="permdesc_getTasks">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
+ <string name="permlab_reorderTasks">"Laufende Anwendungen neu ordnen"</string>
+ <string name="permdesc_reorderTasks">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
+ <string name="permlab_setDebugApp">"Fehlerbeseitigung für Anwendung aktivieren"</string>
+ <string name="permdesc_setDebugApp">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
+ <string name="permlab_changeConfiguration">"UI-Einstellungen ändern"</string>
+ <string name="permdesc_changeConfiguration">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+ <string name="permlab_restartPackages">"Andere Anwendungen neu starten"</string>
+ <string name="permdesc_restartPackages">"Ermöglicht einer Anwendung, den Neustart anderer Anwendungen zu erzwingen."</string>
+ <string name="permlab_forceBack">"Schließen von Anwendung erzwingen"</string>
+ <string name="permdesc_forceBack">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_dump">"Systeminternen Status abrufen"</string>
+ <string name="permdesc_dump">"Ermöglicht einer Anwendung, den internen Status des Systems abzurufen. Schädliche Anwendungen rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string>
+ <string name="permlab_shutdown">"partielles Herunterfahren"</string>
+ <string name="permdesc_shutdown">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
+ <string name="permlab_stopAppSwitches">"Anwendungswechsel verhindern"</string>
+ <string name="permdesc_stopAppSwitches">"Hindert den Nutzer daran, zu einer anderen Anwendung zu wechseln"</string>
+ <string name="permlab_runSetActivityWatcher">"Start von Anwendungen überwachen und steuern"</string>
+ <string name="permdesc_runSetActivityWatcher">"Ermöglicht der Anwendung, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Anwendungen können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Telefonnutzung benötigt."</string>
+ <string name="permlab_broadcastPackageRemoved">"Broadcast ohne Paket senden"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Ermöglicht einer Anwendung, eine Benachrichtigung zur Entfernung eines Anwendungspakets zu senden. Schädliche Anwendungen können so laufende Anwendungen beenden."</string>
+ <string name="permlab_broadcastSmsReceived">"per SMS empfangenen Broadcast senden"</string>
+ <string name="permdesc_broadcastSmsReceived">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine Kurzmitteilung empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Eingang von Kurzmitteilungen zu erzwingen."</string>
+ <string name="permlab_broadcastWapPush">"von WAP-PUSH empfangenen Broadcast senden"</string>
+ <string name="permdesc_broadcastWapPush">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Erhalt von MMS-Mitteilungen zu erzwingen, oder um unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte zu ersetzen."</string>
+ <string name="permlab_setProcessLimit">"Anzahl der laufenden Prozesse beschränken"</string>
+ <string name="permdesc_setProcessLimit">"Ermöglicht einer Anwendung, die maximale Anzahl an laufenden Prozessen zu steuern. Wird nicht für normale Anwendungen benötigt."</string>
+ <string name="permlab_setAlwaysFinish">"alle Anwendungen im Hintergrund schließen"</string>
+ <string name="permdesc_setAlwaysFinish">"Überlässt einer Anwendung die Entscheidung, ob Aktivitäten beendet werden, sobald Sie in den Hintergrund rücken. Wird nicht für normale Anwendungen benötigt."</string>
+ <string name="permlab_batteryStats">"Akku-Daten ändern"</string>
+ <string name="permdesc_batteryStats">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_backup">"Systemsicherung und -wiederherstellung kontrollieren"</string>
+ <string name="permdesc_backup">"Ermöglicht der Anwendung, den Sicherungs- und Wiederherstellungsmechanismus des Systems zu kontrollieren. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_internalSystemWindow">"nicht autorisierte Fenster anzeigen"</string>
+ <string name="permdesc_internalSystemWindow">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
+ <string name="permlab_systemAlertWindow">"Warnungen auf Systemebene anzeigen"</string>
+ <string name="permdesc_systemAlertWindow">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
+ <string name="permlab_setAnimationScale">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
+ <string name="permdesc_setAnimationScale">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+ <string name="permlab_manageAppTokens">"Anwendungs-Tokens verwalten"</string>
+ <string name="permdesc_manageAppTokens">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_injectEvents">"Tasten und Steuerungstasten drücken"</string>
+ <string name="permdesc_injectEvents">"Ermöglicht einer Anwendung, ihre eigenen Eingabeaktionen (Drücken von Tasten etc.) an andere Anwendungen zu liefern. Schädliche Anwendungen können so die Kontrolle über Ihr Telefon übernehmen."</string>
+ <string name="permlab_readInputState">"Tastatureingaben und Aktionen aufzeichnen"</string>
+ <string name="permdesc_readInputState">"Ermöglicht Anwendungen, die von Ihnen gedrückten Tasten zu überwachen (etwa die Eingabe eines Passworts). Dies gilt auch für die Interaktion mit anderen Anwendungen. Sollte für normale Anwendungen nicht benötigt werden."</string>
+ <string name="permlab_bindInputMethod">"An eine Eingabemethode binden"</string>
+ <string name="permdesc_bindInputMethod">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_setOrientation">"Bildschirmausrichtung ändern"</string>
+ <string name="permdesc_setOrientation">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_signalPersistentProcesses">"Linux-Signale an Anwendungen senden"</string>
+ <string name="permdesc_signalPersistentProcesses">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+ <string name="permlab_persistentActivity">"Anwendungen permanent ausführen"</string>
+ <string name="permdesc_persistentActivity">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+ <string name="permlab_deletePackages">"Anwendungen löschen"</string>
+ <string name="permdesc_deletePackages">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
+ <string name="permlab_clearAppUserData">"Daten anderer Anwendungen löschen"</string>
+ <string name="permdesc_clearAppUserData">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+ <string name="permlab_deleteCacheFiles">"Caches anderer Anwendungen löschen"</string>
+ <string name="permdesc_deleteCacheFiles">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+ <string name="permlab_getPackageSize">"Speicherplatz der Anwendung abrufen"</string>
+ <string name="permdesc_getPackageSize">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+ <string name="permlab_installPackages">"Anwendungen direkt installieren"</string>
+ <string name="permdesc_installPackages">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
+ <string name="permlab_clearAppCache">"Alle Cache-Daten der Anwendung löschen"</string>
+ <string name="permdesc_clearAppCache">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
+ <string name="permlab_readLogs">"System-Protokolldateien lesen"</string>
+ <string name="permdesc_readLogs">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
+ <string name="permlab_diagnostic">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
+ <string name="permdesc_diagnostic">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
+ <string name="permlab_changeComponentState">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
+ <string name="permdesc_changeComponentState">"Ermöglicht einer Anwendung, die Komponente einer anderen Anwendung nach Belieben zu aktivieren oder zu deaktivieren. Schädliche Anwendungen können so wichtige Funktionen des Telefons deaktivieren. Bei der Erteilung von Berechtigungen ist daher Vorsicht geboten, da die Anwendungskomponenten unbrauchbar, inkonsistent und unstabil werden können."</string>
+ <string name="permlab_setPreferredApplications">"Bevorzugte Einstellungen festlegen"</string>
+ <string name="permdesc_setPreferredApplications">"Ermöglicht einer Anwendung, Ihre bevorzugten Einstellungen zu ändern. Schädliche Anwendungen können so laufende Anwendungen ohne Ihr Wissen ändern, damit die vorhandenen Anwendungen private Daten von Ihnen sammeln."</string>
+ <string name="permlab_writeSettings">"Allgemeine Systemeinstellungen ändern"</string>
+ <string name="permdesc_writeSettings">"Ermöglicht einer Anwendung, die Einstellungsdaten des Systems zu ändern. Schädliche Anwendungen können so die Systemkonfiguration beschädigen."</string>
+ <string name="permlab_writeSecureSettings">"Sicherheitseinstellungen für das System ändern"</string>
+ <string name="permdesc_writeSecureSettings">"Ermöglicht einer Anwendung, die Daten der Sicherheitseinstellungen des Systems zu ändern. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_writeGservices">"Google Services Map ändern"</string>
+ <string name="permdesc_writeGservices">"Ermöglicht einer Anwendung, Änderungen an der Google Services Map vorzunehmen. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_receiveBootCompleted">"Automatisch nach dem Booten starten"</string>
+ <string name="permdesc_receiveBootCompleted">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
+ <string name="permlab_broadcastSticky">"dauerhaften Broadcast senden"</string>
+ <string name="permdesc_broadcastSticky">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
+ <string name="permlab_readContacts">"Kontaktdaten lesen"</string>
+ <string name="permdesc_readContacts">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
+ <string name="permlab_writeContacts">"Kontaktdaten schreiben"</string>
+ <string name="permdesc_writeContacts">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern. Schädliche Anwendungen können so Ihre Kontaktdaten löschen oder verändern."</string>
+ <string name="permlab_writeOwnerData">"Eigentümerdaten schreiben"</string>
+ <string name="permdesc_writeOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu ändern. Schädliche Anwendungen können so Eigentümerdaten löschen oder verändern."</string>
+ <string name="permlab_readOwnerData">"Eigentümerdaten lesen"</string>
+ <string name="permdesc_readOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu lesen. Schädliche Anwendungen können so Eigentümerdaten lesen."</string>
+ <string name="permlab_readCalendar">"Kalenderdaten lesen"</string>
+ <string name="permdesc_readCalendar">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
+ <string name="permlab_writeCalendar">"Kalenderdaten schreiben"</string>
+ <string name="permdesc_writeCalendar">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kalenderereignisse zu ändern. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern."</string>
+ <string name="permlab_accessMockLocation">"Falsche Standortquellen für Testzwecke"</string>
+ <string name="permdesc_accessMockLocation">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
+ <string name="permlab_accessLocationExtraCommands">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
+ <string name="permlab_installLocationProvider">"Berechtigung zur Installation eines Standortanbieters"</string>
+ <string name="permdesc_installLocationProvider">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben oder Ihren Standort überwachen und an eine externe Quelle weitergeben."</string>
+ <string name="permlab_accessFineLocation">"genauer (GPS-) Standort"</string>
+ <string name="permdesc_accessFineLocation">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
+ <string name="permlab_accessCoarseLocation">"ungefährer (netzwerkbasierter) Standort"</string>
+ <string name="permdesc_accessCoarseLocation">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
+ <string name="permlab_accessSurfaceFlinger">"Auf SurfaceFlinger zugreifen"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+ <string name="permlab_readFrameBuffer">"Frame-Puffer lesen"</string>
+ <string name="permdesc_readFrameBuffer">"Ermöglicht einer Anwendung, den Inhalt des Frame-Puffers zu lesen."</string>
+ <string name="permlab_modifyAudioSettings">"Audio-Einstellungen ändern"</string>
+ <string name="permdesc_modifyAudioSettings">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+ <string name="permlab_recordAudio">"Audio aufnehmen"</string>
+ <string name="permdesc_recordAudio">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+ <string name="permlab_camera">"Fotos aufnehmen"</string>
+ <string name="permdesc_camera">"Ermöglicht der Anwendung, Fotos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder zusammentragen, die von der Kamera erfasst werden."</string>
+ <string name="permlab_brick">"Telefon dauerhaft deaktivieren."</string>
+ <string name="permdesc_brick">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
+ <string name="permlab_reboot">"Neustart des Telefons erzwingen"</string>
+ <string name="permdesc_reboot">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+ <string name="permlab_mount_unmount_filesystems">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
+ <string name="permlab_mount_format_filesystems">"Externen Speicher formatieren"</string>
+ <string name="permdesc_mount_format_filesystems">"Erlaubt der Anwendung, austauschbaren Speicher zu formatieren."</string>
+ <string name="permlab_vibrate">"Vibrationsalarm steuern"</string>
+ <string name="permdesc_vibrate">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+ <string name="permlab_flashlight">"Lichtanzeige steuern"</string>
+ <string name="permdesc_flashlight">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
+ <string name="permlab_hardware_test">"Hardware testen"</string>
+ <string name="permdesc_hardware_test">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+ <string name="permlab_callPhone">"Telefonnummern direkt anrufen"</string>
+ <string name="permdesc_callPhone">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
+ <string name="permlab_callPrivileged">"Alle Telefonnummern direkt anrufen"</string>
+ <string name="permdesc_callPrivileged">"Ermöglicht der Anwendung, ohne Ihr Eingreifen eine beliebige Telefonnummer zu wählen, einschließlich Notfallnummern. Schädliche Anwendungen können so unnötige und illegale Anrufe an Notdienste tätigen."</string>
+ <string name="permlab_locationUpdates">"Benachrichtigungen für Standortaktualisierung steuern"</string>
+ <string name="permdesc_locationUpdates">"Ermöglicht die Aktivierung/Deaktivierung der Mobilfunkbenachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_checkinProperties">"Auf Check-In-Eigenschaften zugreifen"</string>
+ <string name="permdesc_checkinProperties">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_bindGadget">"Widgets auswählen"</string>
+ <string name="permdesc_bindGadget">"Ermöglicht der Anwendung, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_modifyPhoneState">"Telefonstatus ändern"</string>
+ <string name="permdesc_modifyPhoneState">"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
+ <string name="permlab_readPhoneState">"Telefonstatus lesen"</string>
+ <string name="permdesc_readPhoneState">"Ermöglicht der Anwendung, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
+ <string name="permlab_wakeLock">"Standby-Modus deaktivieren"</string>
+ <string name="permdesc_wakeLock">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+ <string name="permlab_devicePower">"Gerät ein- oder ausschalten"</string>
+ <string name="permdesc_devicePower">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+ <string name="permlab_factoryTest">"In Werkstestmodus ausführen"</string>
+ <string name="permdesc_factoryTest">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
+ <string name="permlab_setWallpaper">"Hintergrundbild festlegen"</string>
+ <string name="permdesc_setWallpaper">"Ermöglicht der Anwendung, das System-Hintergrundbild festzulegen."</string>
+ <string name="permlab_setWallpaperHints">"Größenhinweise für Hintergrundbild festlegen"</string>
+ <string name="permdesc_setWallpaperHints">"Ermöglicht der Anwendung, die Größenhinweise für das Hintergrundbild festzulegen."</string>
+ <string name="permlab_masterClear">"System auf Werkseinstellung zurücksetzen"</string>
+ <string name="permdesc_masterClear">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
+ <string name="permlab_setTimeZone">"Zeitzone festlegen"</string>
+ <string name="permdesc_setTimeZone">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+ <string name="permlab_getAccounts">"bekannte Konten suchen"</string>
+ <string name="permdesc_getAccounts">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+ <string name="permlab_accessNetworkState">"Netzwerkstatus anzeigen"</string>
+ <string name="permdesc_accessNetworkState">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+ <string name="permlab_createNetworkSockets">"Uneingeschränkter Internetzugriff"</string>
+ <string name="permdesc_createNetworkSockets">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+ <string name="permlab_writeApnSettings">"Einstellungen für Zugriffspunktname schreiben"</string>
+ <string name="permdesc_writeApnSettings">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+ <string name="permlab_changeNetworkState">"Netzwerkkonnektivität ändern"</string>
+ <string name="permdesc_changeNetworkState">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+ <string name="permlab_changeBackgroundDataSetting">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
+ <string name="permlab_accessWifiState">"WLAN-Status anzeigen"</string>
+ <string name="permdesc_accessWifiState">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+ <string name="permlab_changeWifiState">"WLAN-Status ändern"</string>
+ <string name="permdesc_changeWifiState">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+ <string name="permlab_changeWifiMulticastState">"WLAN-Multicast-Empfang zulassen"</string>
+ <string name="permdesc_changeWifiMulticastState">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth-Verwaltung"</string>
+ <string name="permdesc_bluetoothAdmin">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+ <string name="permlab_bluetooth">"Bluetooth-Verbindungen herstellen"</string>
+ <string name="permdesc_bluetooth">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+ <string name="permlab_disableKeyguard">"Tastensperre deaktivieren"</string>
+ <string name="permdesc_disableKeyguard">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
+ <string name="permlab_readSyncSettings">"Synchronisierungseinstellungen lesen"</string>
+ <string name="permdesc_readSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permlab_writeSyncSettings">"Synchronisierungseinstellungen schreiben"</string>
+ <string name="permdesc_writeSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permlab_readSyncStats">"Synchronisierungsstatistiken lesen"</string>
+ <string name="permdesc_readSyncStats">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+ <string name="permlab_subscribedFeedsRead">"Abonnierte Feeds lesen"</string>
+ <string name="permdesc_subscribedFeedsRead">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+ <string name="permlab_subscribedFeedsWrite">"Abonnierte Feeds schreiben"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
+ <string name="permlab_readDictionary">"Nutzerdefiniertes Wörterbuch lesen"</string>
+ <string name="permdesc_readDictionary">"Erlaubt einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+ <string name="permlab_writeDictionary">"in nutzerdefiniertes Wörterbuch schreiben"</string>
+ <string name="permdesc_writeDictionary">"Erlaubt einer Anwendung, neue Wörter in das Wörterbuch des Nutzers zu schreiben."</string>
+ <string name="permlab_sdcardWrite">"SD-Karten-Inhalt ändern/löschen"</string>
+ <string name="permdesc_sdcardWrite">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Privat"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbeit"</item>
- <item msgid="1103601433382158155">"Fax (Arbeit)"</item>
- <item msgid="1735177144948329370">"Fax (privat)"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Andere"</item>
- <item msgid="9192514806975898961">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Mobil"</item>
+ <item>"Arbeit"</item>
+ <item>"Fax (Arbeit)"</item>
+ <item>"Fax (privat)"</item>
+ <item>"Pager"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Privat"</item>
- <item msgid="7084237356602625604">"Arbeit"</item>
- <item msgid="1112044410659011023">"Andere"</item>
- <item msgid="2374913952870110618">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Privat"</item>
- <item msgid="5629153956045109251">"Arbeit"</item>
- <item msgid="4966604264500343469">"Andere"</item>
- <item msgid="4932682847595299369">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Privat"</item>
- <item msgid="1359644565647383708">"Arbeit"</item>
- <item msgid="7868549401053615677">"Andere"</item>
- <item msgid="3145118944639869809">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbeit"</item>
- <item msgid="4378074129049520373">"Andere"</item>
- <item msgid="3455047468583965104">"Benutzerdefiniert"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-Code eingeben"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Falscher PIN-Code!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(kein Dienst)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Schema für Entsperrung zeichnen"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Notruf"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Korrekt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Tut uns leid. Versuchen Sie es noch einmal."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Wird geladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Aufgeladen"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Bitte Ladegerät anschließen"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Keine SIM-Karte."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Keine SIM-Karte im Telefon."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Bitte legen Sie eine SIM-Karte ein."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN-Code eingeben"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Muster vergessen?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Zu viele Versuche!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nutzername (E-Mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passwort"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Anmelden"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ungültiger Nutzername oder ungültiges Passwort."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Wird aufgeladen..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Ladegerät anschließen"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Akku ist fast leer."</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Nur noch weniger als <xliff:g id="NUMBER">%d%%</xliff:g> vorhanden."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Warum?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Werkstest fehlgeschlagen"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Neu booten"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
- <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Niemals"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"Leerzeichen"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"löschen"</string>
- <string name="search_go" msgid="8298016669822141719">"Suche"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN-Code eingeben"</string>
+ <string name="keyguard_password_wrong_pin_code">"Falscher PIN-Code!"</string>
+ <string name="keyguard_label_text">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
+ <string name="emergency_call_dialog_number_for_display">"Notrufnummer"</string>
+ <string name="lockscreen_carrier_default">"(kein Dienst)"</string>
+ <string name="lockscreen_screen_locked">"Display gesperrt."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Zum Entsperren die Menütaste drücken"</string>
+ <string name="lockscreen_pattern_instructions">"Schema für Entsperrung zeichnen"</string>
+ <string name="lockscreen_emergency_call">"Notruf"</string>
+ <string name="lockscreen_pattern_correct">"Korrekt!"</string>
+ <string name="lockscreen_pattern_wrong">"Tut uns leid. Versuchen Sie es noch einmal."</string>
+ <string name="lockscreen_plugged_in">"Wird geladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Bitte Ladegerät anschließen"</string>
+ <string name="lockscreen_missing_sim_message_short">"Keine SIM-Karte."</string>
+ <string name="lockscreen_missing_sim_message">"Keine SIM-Karte im Telefon."</string>
+ <string name="lockscreen_missing_sim_instructions">"Bitte legen Sie eine SIM-Karte ein."</string>
+ <string name="lockscreen_network_locked_message">"Netzwerk gesperrt"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
+ <string name="lockscreen_sim_locked_message">"Bitte PIN-Code eingeben"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-Karte wird entsperrt..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Muster vergessen?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Zu viele Versuche!"</string>
+ <string name="lockscreen_glogin_instructions">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+ <string name="lockscreen_glogin_username_hint">"Nutzername (E-Mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Passwort"</string>
+ <string name="lockscreen_glogin_submit_button">"Anmelden"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ungültiger Nutzername oder ungültiges Passwort."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Keine Benachrichtigungen"</string>
+ <string name="status_bar_ongoing_events_title">"Aktuell"</string>
+ <string name="status_bar_latest_events_title">"Benachrichtigungen"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Wird aufgeladen..."</string>
+ <string name="battery_low_title">"Ladegerät anschließen"</string>
+ <string name="battery_low_subtitle">"Akku ist fast leer."</string>
+ <string name="battery_low_percent_format">"Nur noch weniger als <xliff:g id="NUMBER">%d%%</xliff:g> vorhanden."</string>
+ <string name="battery_low_why">"Warum?"</string>
+ <string name="factorytest_failed">"Werkstest fehlgeschlagen"</string>
+ <string name="factorytest_not_system">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
+ <string name="factorytest_no_action">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
+ <string name="factorytest_reboot">"Neu booten"</string>
+ <string name="js_dialog_title">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
+ <string name="save_password_label">"Bestätigen"</string>
+ <string name="permlab_readHistoryBookmarks">"Browserverlauf und Lesezeichen lesen"</string>
+ <string name="permdesc_readHistoryBookmarks">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
+ <string name="permlab_writeHistoryBookmarks">"Browserverlauf und Lesezeichen schreiben"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
+ <string name="save_password_message">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
+ <string name="save_password_notnow">"Nicht jetzt"</string>
+ <string name="save_password_remember">"Speichern"</string>
+ <string name="save_password_never">"Niemals"</string>
+ <string name="open_permission_deny">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
+ <string name="text_copied">"Text in Zwischenablage kopiert."</string>
+ <string name="more_item_label">"Mehr"</string>
+ <string name="prepend_shortcut_label">"Menü+"</string>
+ <string name="menu_space_shortcut_label">"Leerzeichen"</string>
+ <string name="menu_enter_shortcut_label">"Enter"</string>
+ <string name="menu_delete_shortcut_label">"löschen"</string>
+ <string name="search_go">"Suche"</string>
+ <string name="oneMonthDurationPast">"Vor 1 Monat"</string>
+ <string name="beforeOneMonthDurationPast">"Vor mehr als 1 Monat"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Vor 1 Sekunde"</item>
- <item quantity="other" msgid="3903706804349556379">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"Vor 1 Sekunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Vor 1 Minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"Vor 1 Minute"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Vor 1 Stunde"</item>
- <item quantity="other" msgid="2467273239587587569">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"Vor 1 Stunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"Gestern"</item>
- <item quantity="other" msgid="2479586466153314633">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"Gestern"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"in 1 Sekunde"</item>
- <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"in 1 Sekunde"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"in 1 Minute"</item>
- <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"in 1 Minute"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"in 1 Stunde"</item>
- <item quantity="other" msgid="547290677353727389">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"in 1 Stunde"</item>
+ <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"vor 1 Sekunde"</item>
- <item quantity="other" msgid="3699169366650930415">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"vor 1 Sekunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"vor 1 Minute"</item>
- <item quantity="other" msgid="851164968597150710">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"vor 1 Minute"</item>
+ <item quantity="other">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Vor 1 Stunde"</item>
- <item quantity="other" msgid="6889970745748538901">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"Vor 1 Stunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"Gestern"</item>
- <item quantity="other" msgid="3453342639616481191">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"Gestern"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"in 1 Sekunde"</item>
- <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"in 1 Sekunde"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"in 1 Minute"</item>
- <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"in 1 Minute"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"in 1 Stunde"</item>
- <item quantity="other" msgid="3705373766798013406">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"in 1 Stunde"</item>
+ <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"am %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"am %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"in %s"</string>
- <string name="day" msgid="8144195776058119424">"Tag"</string>
- <string name="days" msgid="4774547661021344602">"Tage"</string>
- <string name="hour" msgid="2126771916426189481">"Stunde"</string>
- <string name="hours" msgid="894424005266852993">"Stunden"</string>
- <string name="minute" msgid="9148878657703769868">"Min"</string>
- <string name="minutes" msgid="5646001005827034509">"Minuten"</string>
- <string name="second" msgid="3184235808021478">"Sek"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"Woche"</string>
- <string name="weeks" msgid="6509623834583944518">"Wochen"</string>
- <string name="year" msgid="4001118221013892076">"Jahr"</string>
- <string name="years" msgid="6881577717993213522">"Jahre"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Jeden Wochentag (Mo-Fr)"</string>
- <string name="daily" msgid="5738949095624133403">"Täglich"</string>
- <string name="weekly" msgid="983428358394268344">"Jede Woche am <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Monatlich"</string>
- <string name="yearly" msgid="1519577999407493836">"Jährlich"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kann nicht wiedergegeben werden."</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Leider ist dieses Video nicht für Streaming auf diesem Gerät gültig."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Dieses Video kann leider nicht abgespielt werden."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"Mittag"</string>
- <string name="Noon" msgid="3342127745230013127">"Mittag"</string>
- <string name="midnight" msgid="7166259508850457595">"Mitternacht"</string>
- <string name="Midnight" msgid="5630806906897892201">"Mitternacht"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string>
- <string name="selectText" msgid="3889149123626888637">"Text auswählen"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Textauswahl beenden"</string>
- <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string>
- <string name="cutAll" msgid="2436383270024931639">"Alles ausschneiden"</string>
- <string name="copy" msgid="2681946229533511987">"Kopieren"</string>
- <string name="copyAll" msgid="2590829068100113057">"Alles kopieren"</string>
- <string name="paste" msgid="5629880836805036433">"Einfügen"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL kopieren"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Eingabemethode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"\"%s\" dem Wörterbuch hinzufügen"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Text bearbeiten"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Geringer Speicher"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Kaum noch freier Telefonspeicher verfügbar."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Abbrechen"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
- <string name="capital_on" msgid="1544682755514494298">"EIN"</string>
- <string name="capital_off" msgid="6815870386972805832">"AUS"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Aktion durchführen mit"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Löschen Sie die Standardeinstellungen unter \"Starteinstellungen > Anwendungen > Anwendungen verwalten\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Aktion auswählen"</string>
- <string name="noApplications" msgid="1691104391758345586">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
- <string name="aerr_title" msgid="653922989522758100">"Tut uns leid!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde unerwartet beendet. Versuchen Sie es erneut."</string>
- <string name="anr_title" msgid="3100070910664756057">"Tut uns leid!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Anwendung <xliff:g id="APPLICATION">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_process" msgid="1246866008169975783">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."</string>
- <string name="force_close" msgid="3653416315450806396">"Schließen erzwingen"</string>
- <string name="report" msgid="4060218260984795706">"Bericht"</string>
- <string name="wait" msgid="7147118217226317732">"Warten"</string>
- <string name="debug" msgid="9103374629678531849">"Fehler suchen"</string>
- <string name="sendText" msgid="5132506121645618310">"Aktion für Text auswählen"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Wiedergabe durch Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Hörerlautstärke"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Lautstärke bei eingehendem Bluetooth-Anruf"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Lautstärke für Alarm"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Benachrichtigungslautstärke"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Lautstärke"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standard-Klingelton"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Lautlos"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Unbekannter Klingelton"</string>
+ <string name="preposition_for_date">"am %s"</string>
+ <string name="preposition_for_time">"am %s"</string>
+ <string name="preposition_for_year">"in %s"</string>
+ <string name="day">"Tag"</string>
+ <string name="days">"Tage"</string>
+ <string name="hour">"Stunde"</string>
+ <string name="hours">"Stunden"</string>
+ <string name="minute">"Min"</string>
+ <string name="minutes">"Minuten"</string>
+ <string name="second">"Sek"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"Woche"</string>
+ <string name="weeks">"Wochen"</string>
+ <string name="year">"Jahr"</string>
+ <string name="years">"Jahre"</string>
+ <string name="every_weekday">"Jeden Wochentag (Mo-Fr)"</string>
+ <string name="daily">"Täglich"</string>
+ <string name="weekly">"Jede Woche am <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Monatlich"</string>
+ <string name="yearly">"Jährlich"</string>
+ <string name="VideoView_error_title">"Video kann nicht wiedergegeben werden."</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Leider ist dieses Video nicht für Streaming auf diesem Gerät gültig."</string>
+ <string name="VideoView_error_text_unknown">"Dieses Video kann leider nicht abgespielt werden."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"Mittag"</string>
+ <string name="Noon">"Mittag"</string>
+ <string name="midnight">"Mitternacht"</string>
+ <string name="Midnight">"Mitternacht"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Alles auswählen"</string>
+ <string name="selectText">"Text auswählen"</string>
+ <string name="stopSelectingText">"Textauswahl beenden"</string>
+ <string name="cut">"Ausschneiden"</string>
+ <string name="cutAll">"Alles ausschneiden"</string>
+ <string name="copy">"Kopieren"</string>
+ <string name="copyAll">"Alles kopieren"</string>
+ <string name="paste">"Einfügen"</string>
+ <string name="copyUrl">"URL kopieren"</string>
+ <string name="inputMethod">"Eingabemethode"</string>
+ <string name="addToDictionary">"\"%s\" dem Wörterbuch hinzufügen"</string>
+ <string name="editTextMenuTitle">"Text bearbeiten"</string>
+ <string name="low_internal_storage_view_title">"Geringer Speicher"</string>
+ <string name="low_internal_storage_view_text">"Kaum noch freier Telefonspeicher verfügbar."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Abbrechen"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Abbrechen"</string>
+ <string name="dialog_alert_title">"Achtung"</string>
+ <string name="capital_on">"EIN"</string>
+ <string name="capital_off">"AUS"</string>
+ <string name="whichApplication">"Aktion durchführen mit"</string>
+ <string name="alwaysUse">"Standardmäßig für diese Aktion verwenden."</string>
+ <string name="clearDefaultHintMsg">"Löschen Sie die Standardeinstellungen unter \"Starteinstellungen > Anwendungen > Anwendungen verwalten\"."</string>
+ <string name="chooseActivity">"Aktion auswählen"</string>
+ <string name="noApplications">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
+ <string name="aerr_title">"Tut uns leid!"</string>
+ <string name="aerr_application">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+ <string name="aerr_process">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+ <string name="anr_title">"Tut uns leid!"</string>
+ <string name="anr_activity_application">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Anwendung <xliff:g id="APPLICATION">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_activity_process">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_application_process">"Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_process">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."</string>
+ <string name="force_close">"Schließen erzwingen"</string>
+ <string name="report">"Bericht"</string>
+ <string name="wait">"Warten"</string>
+ <string name="debug">"Fehler suchen"</string>
+ <string name="sendText">"Aktion für Text auswählen"</string>
+ <string name="volume_ringtone">"Klingeltonlautstärke"</string>
+ <string name="volume_music">"Medienlautstärke"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Wiedergabe durch Bluetooth"</string>
+ <string name="volume_call">"Hörerlautstärke"</string>
+ <string name="volume_bluetooth_call">"Lautstärke bei eingehendem Bluetooth-Anruf"</string>
+ <string name="volume_alarm">"Lautstärke für Alarm"</string>
+ <string name="volume_notification">"Benachrichtigungslautstärke"</string>
+ <string name="volume_unknown">"Lautstärke"</string>
+ <string name="ringtone_default">"Standard-Klingelton"</string>
+ <string name="ringtone_default_with_actual">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Lautlos"</string>
+ <string name="ringtone_picker_title">"Klingeltöne"</string>
+ <string name="ringtone_unknown">"Unbekannter Klingelton"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"WLAN-Netzwerk verfügbar"</item>
- <item quantity="other" msgid="4192424489168397386">"WLAN-Netzwerke verfügbar"</item>
+ <item quantity="one">"WLAN-Netzwerk verfügbar"</item>
+ <item quantity="other">"WLAN-Netzwerke verfügbar"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Verfügbares WLAN-Netzwerk öffnen"</item>
- <item quantity="other" msgid="7915895323644292768">"Verfügbare WLAN-Netzwerke öffnen"</item>
+ <item quantity="one">"Verfügbares WLAN-Netzwerk öffnen"</item>
+ <item quantity="other">"Verfügbare WLAN-Netzwerke öffnen"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Unbekannte Anwendung"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Abbrechen"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Einstellen"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ausblenden"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Alle anzeigen"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Ladevorgang läuft..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-Verbindung"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Sie haben Ihr Telefon über einen USB-Anschluss mit Ihrem Computer verbunden. Wählen Sie \"Bereitstellen\", wenn Sie Dateien auf Ihren Computer oder die SD-Karte Ihres Telefons kopieren möchten."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Bereitstellen"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nicht bereitstellen"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Auswählen, um USB-Speicher zu deaktivieren."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB-Speicher deaktivieren"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Bevor Sie den USB-Speicher deaktivieren, stellen Sie sicher, dass Sie Ihn vom USB-Host getrennt haben. Wählen Sie \"Deaktivieren\", um den USB-Speicher zu deaktivieren."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Ausschalten"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Abbrechen"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Wir haben beim Deaktivieren des USB-Speichers ein Problem festgestellt. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD-Karte formatieren"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging verbunden"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Ihr Telefon ist mit einem Computer verbunden."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Eingabemethode auswählen"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD-Karte wird vorbereitet"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Nach Fehlern wird gesucht."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"SD-Karte leer"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beschädigte SD-Karte"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-Karte unerwartet entfernt"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD-Karte\nkann entfernt werden."</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Die SD-Karte kann entfernt werden."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-Karte entfernt"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Keine passenden Aktivitäten gefunden"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"Nutzungsstatistik der Komponente aktualisieren"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fehler beim Vergrößern des Widgets"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Suchen"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Senden"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Weiter"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Fertig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ausführen"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Nummer"\n"mit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt"\n"mit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"aktiviert"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"nicht aktiviert"</string>
+ <string name="select_character">"Zeichen einfügen"</string>
+ <string name="sms_control_default_app_name">"Unbekannte Anwendung"</string>
+ <string name="sms_control_title">"Kurznachrichten werden gesendet"</string>
+ <string name="sms_control_message">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Abbrechen"</string>
+ <string name="date_time_set">"Einstellen"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Keine Berechtigungen erforderlich"</string>
+ <string name="perms_hide"><b>"Ausblenden"</b></string>
+ <string name="perms_show_all"><b>"Alle anzeigen"</b></string>
+ <string name="googlewebcontenthelper_loading">"Ladevorgang läuft..."</string>
+ <string name="usb_storage_title">"USB-Verbindung"</string>
+ <string name="usb_storage_message">"Sie haben Ihr Telefon über einen USB-Anschluss mit Ihrem Computer verbunden. Wählen Sie \"Bereitstellen\", wenn Sie Dateien auf Ihren Computer oder die SD-Karte Ihres Telefons kopieren möchten."</string>
+ <string name="usb_storage_button_mount">"Bereitstellen"</string>
+ <string name="usb_storage_button_unmount">"Nicht bereitstellen"</string>
+ <string name="usb_storage_error_message">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
+ <string name="usb_storage_notification_title">"USB-Verbindung"</string>
+ <string name="usb_storage_notification_message">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
+ <string name="usb_storage_stop_notification_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_notification_message">"Auswählen, um USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_message">"Bevor Sie den USB-Speicher deaktivieren, stellen Sie sicher, dass Sie Ihn vom USB-Host getrennt haben. Wählen Sie \"Deaktivieren\", um den USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_button_mount">"Ausschalten"</string>
+ <string name="usb_storage_stop_button_unmount">"Abbrechen"</string>
+ <string name="usb_storage_stop_error_message">"Wir haben beim Deaktivieren des USB-Speichers ein Problem festgestellt. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
+ <string name="extmedia_format_title">"SD-Karte formatieren"</string>
+ <string name="extmedia_format_message">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Eingabemethode auswählen"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"Kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-Karte wird vorbereitet"</string>
+ <string name="ext_media_checking_notification_message">"Nach Fehlern wird gesucht."</string>
+ <string name="ext_media_nofs_notification_title">"SD-Karte leer"</string>
+ <string name="ext_media_nofs_notification_message">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschädigte SD-Karte"</string>
+ <string name="ext_media_unmountable_notification_message">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-Karte unerwartet entfernt"</string>
+ <string name="ext_media_badremoval_notification_message">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD-Karte\nkann entfernt werden."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Die SD-Karte kann entfernt werden."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-Karte entfernt"</string>
+ <string name="ext_media_nomedia_notification_message">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
+ <string name="activity_list_empty">"Keine passenden Aktivitäten gefunden"</string>
+ <string name="permlab_pkgUsageStats">"Nutzungsstatistik der Komponente aktualisieren"</string>
+ <string name="permdesc_pkgUsageStats">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Für Zoomeinstellung zweimal berühren"</string>
+ <string name="gadget_host_error_inflating">"Fehler beim Vergrößern des Widgets"</string>
+ <string name="ime_action_go">"Los"</string>
+ <string name="ime_action_search">"Suchen"</string>
+ <string name="ime_action_send">"Senden"</string>
+ <string name="ime_action_next">"Weiter"</string>
+ <string name="ime_action_done">"Fertig"</string>
+ <string name="ime_action_default">"Ausführen"</string>
+ <string name="dial_number_using">"Nummer"\n"mit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
+ <string name="create_contact_using">"Neuer Kontakt"\n"mit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
+ <string name="accessibility_compound_button_selected">"aktiviert"</string>
+ <string name="accessibility_compound_button_unselected">"nicht aktiviert"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ba39b94..3158a37 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<χωρίς τίτλο>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Δεν υπάρχει τηλεφωνικός αριθμός)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Άγνωστο)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτόματος τηλεφωνητής"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Πρόβλημα σύνδεσης ή μη έγκυρος κώδικας MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Η υπηρεσία ενεργοποιήθηκε."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Η υπηρεσία ενεργοποιήθηκε για:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Η υπηρεσία έχει απενεργοποιηθεί."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Η εγγραφή ήταν επιτυχής."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Η διαγραφή ήταν επιτυχής."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Εσφαλμένος κωδικός πρόσβασης."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Το MMI ολοκληρώθηκε."</string>
- <string name="badPin" msgid="5085454289896032547">"Ο παλιός αριθμός PIN που πληκτρολογήσατε είναι εσφαλμένος."</string>
- <string name="badPuk" msgid="5702522162746042460">"Ο κωδικός PUK που πληκτρολογήσατε είναι εσφαλμένος."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Οι αριθμοί PIN που πληκτρολογήσατε δεν ταιριάζουν."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Πληκτρολογήστε έναν αριθμό PIN μεγέθους 4 έως 8 αριθμών."</string>
- <string name="needPuk" msgid="919668385956251611">"Η κάρτα SIM έχει κλειδωθεί με κωδικό PUK. Πληκτρολογήστε τον κωδικό PUK για να την ξεκλειδώσετε."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Πληκτρολογήστε τον κωδικό PUK2 για την κατάργηση αποκλεισμού της κάρτας SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Εισερχόμενη αναγνώριση κλήσης"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Εξερχόμενη αναγνώριση κλήσης"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Προώθηση κλήσεων"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Αναμ. κλήσ."</string>
- <string name="BaMmi" msgid="455193067926770581">"Φραγή κλήσεων"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Αλλαγή κωδικού πρόσβασης"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Αλλαγή αριθμού PIN"</string>
+ <string name="untitled">"<χωρίς τίτλο>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Δεν υπάρχει τηλεφωνικός αριθμός)"</string>
+ <string name="unknownName">"(Άγνωστο)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Αυτόματος τηλεφωνητής"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Πρόβλημα σύνδεσης ή μη έγκυρος κώδικας MMI."</string>
+ <string name="serviceEnabled">"Η υπηρεσία ενεργοποιήθηκε."</string>
+ <string name="serviceEnabledFor">"Η υπηρεσία ενεργοποιήθηκε για:"</string>
+ <string name="serviceDisabled">"Η υπηρεσία έχει απενεργοποιηθεί."</string>
+ <string name="serviceRegistered">"Η εγγραφή ήταν επιτυχής."</string>
+ <string name="serviceErased">"Η διαγραφή ήταν επιτυχής."</string>
+ <string name="passwordIncorrect">"Εσφαλμένος κωδικός πρόσβασης."</string>
+ <string name="mmiComplete">"Το MMI ολοκληρώθηκε."</string>
+ <string name="badPin">"Ο παλιός αριθμός PIN που πληκτρολογήσατε είναι εσφαλμένος."</string>
+ <string name="badPuk">"Ο κωδικός PUK που πληκτρολογήσατε είναι εσφαλμένος."</string>
+ <string name="mismatchPin">"Οι αριθμοί PIN που πληκτρολογήσατε δεν ταιριάζουν."</string>
+ <string name="invalidPin">"Πληκτρολογήστε έναν αριθμό PIN μεγέθους 4 έως 8 αριθμών."</string>
+ <string name="needPuk">"Η κάρτα SIM έχει κλειδωθεί με κωδικό PUK. Πληκτρολογήστε τον κωδικό PUK για να την ξεκλειδώσετε."</string>
+ <string name="needPuk2">"Πληκτρολογήστε τον κωδικό PUK2 για την κατάργηση αποκλεισμού της κάρτας SIM."</string>
+ <string name="ClipMmi">"Εισερχόμενη αναγνώριση κλήσης"</string>
+ <string name="ClirMmi">"Εξερχόμενη αναγνώριση κλήσης"</string>
+ <string name="CfMmi">"Προώθηση κλήσεων"</string>
+ <string name="CwMmi">"Αναμονή κλήσης"</string>
+ <string name="BaMmi">"Φραγή κλήσεων"</string>
+ <string name="PwdMmi">"Αλλαγή κωδικού πρόσβασης"</string>
+ <string name="PinMmi">"Αλλαγή αριθμού PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"περιορισμένη\". Επόμενη κλήση: Περιορισμένη."</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Περιορισμένη."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Η υπηρεσία δεν προβλέπεται."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Δεν είναι δυνατή η αλλαγή της ρύθμισης αναγνώρισης κλήσης."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Η περιορισμένη πρόσβαση άλλαξε"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Η υπηρεσία δεδομένων είναι αποκλεισμένη."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Η υπηρεσία έκτακτης ανάγκης είναι αποκλεισμένη."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Η φωνητική υπηρεσία/υπηρεσία SMS είναι αποκλεισμένη."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Όλες οι φωνητικές υπηρεσίες/υπηρεσίες SMS έχουν αποκλειστεί."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Φωνή"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Δεδομένα"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"ΦΑΞ"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Μη συγχρονισμένα"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Συγχρονισμός"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Πακέτο"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"περιορισμένη\". Επόμενη κλήση: Περιορισμένη."</string>
+ <string name="CLIRDefaultOnNextCallOff">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Περιορισμένη."</string>
+ <string name="CLIRDefaultOffNextCallOff">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
+ <string name="serviceNotProvisioned">"Η υπηρεσία δεν προβλέπεται."</string>
+ <string name="CLIRPermanent">"Δεν είναι δυνατή η αλλαγή της ρύθμισης αναγνώρισης κλήσης."</string>
+ <string name="RestrictedChangedTitle">"Η περιορισμένη πρόσβαση άλλαξε"</string>
+ <string name="RestrictedOnData">"Η υπηρεσία δεδομένων είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnEmergency">"Η υπηρεσία έκτακτης ανάγκης είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnNormal">"Η φωνητική υπηρεσία/υπηρεσία SMS είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnAll">"Όλες οι φωνητικές υπηρεσίες/υπηρεσίες SMS έχουν αποκλειστεί."</string>
+ <string name="serviceClassVoice">"Φωνή"</string>
+ <string name="serviceClassData">"Δεδομένα"</string>
+ <string name="serviceClassFAX">"ΦΑΞ"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Μη συγχρονισμένα"</string>
+ <string name="serviceClassDataSync">"Συγχρονισμός"</string>
+ <string name="serviceClassPacket">"Πακέτο"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτερόλεπτα"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτερόλεπτα"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Η ιστοσελίδα περιέχει ένα σφάλμα."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Δεν ήταν δυνατή η εύρεση της διεύθυνσης URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Το πλάνο ελέγχου ταυτότητας ιστοτόπου δεν υποστηρίζεται."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Ο έλεγχος ταυτότητας δεν ήταν επιτυχής."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Ο έλεγχος ταυτότητας μέσω του διακομιστή μεσολάβησης δεν ήταν επιτυχής."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Η σύνδεση στον διακομιστή δεν ήταν επιτυχής."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Η επικοινωνία με τον διακομιστή απέτυχε. Προσπαθήστε ξανά αργότερα."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Το όριο χρόνου της σύνδεσης στον διακομιστή έληξε."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Αυτή η σελίδα περιέχει πάρα πολλές ανακατευθύνσεις διακομιστή."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Το πρωτόκολλο δεν υποστηρίζεται."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Δεν ήταν δυνατή η επίτευξη ασφαλούς σύνδεσης."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Δεν ήταν δυνατό το άνοιγμα της σελίδας επειδή η διεύθυνση URL δεν είναι έγκυρη."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Η πρόσβαση στο αρχείο δεν ήταν δυνατή."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Το αρχείο που ζητήθηκε δεν βρέθηκε."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Πραγματοποιείται επεξεργασία πάρα πολλών αιτημάτων. Προσπαθήστε ξανά αργότερα."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Συγχρονισμός"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Συγχρονισμός"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
- <string name="low_memory" msgid="6632412458436461203">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης! Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
- <string name="me" msgid="6545696007631404292">"Για εμένα"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Επιλογές τηλεφώνου"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Λειτουργία σίγασης"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Ενεργοποίηση ασύρματου"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Απενεργοποίηση ασύρματου"</string>
- <string name="screen_lock" msgid="799094655496098153">"Κλείδωμα οθόνης"</string>
- <string name="power_off" msgid="4266614107412865048">"Απενεργοποίηση"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Απενεργοποίηση..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Το τηλέφωνό σας θα απενεργοποιηθεί."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Δεν υπάρχουν πρόσφατες εφαρμογές."</string>
- <string name="global_actions" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Απενεργοποίηση"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Λειτουργία σίγασης"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ο ήχος είναι απενεργοποιημένος"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ο ήχος είναι ενεργοποιημένος"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Λειτουργία πτήσης"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Η λειτουργία πτήσης είναι απενεργοποιημένη"</string>
- <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Υπηρεσίες επί πληρωμή"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Επιτρέπει σε εφαρμογές να πραγματοποιήσουν ενέργειες για τις οποίες ενδέχεται να χρεωθείτε."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Τα μηνύματά σας"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Ανάγνωση και εγγραφή των μηνυμάτων SMS, των μηνυμάτων ηλεκτρονικού ταχυδρομείου και άλλων μηνυμάτων."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Οι προσωπικές σας πληροφορίες"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Άμεση πρόσβαση στις επαφές και στο ημερολόγιό σας που είναι αποθηκευμένα στο τηλέφωνο."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Η τοποθεσία σας"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Παρακολούθηση της φυσικής τοποθεσίας σας"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Επικοινωνία δικτύου"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Επιτρέπει σε εφαρμογές να αποκτήσουν πρόσβαση σε διάφορες λειτουργίες δικτύου."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Οι λογαριασμοί σας Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Πρόσβαση στους διαθέσιμους λογαριασμούς Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Στοιχεία ελέγχου υλικού"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Άμεση πρόσβαση στο υλικό της συσκευής τηλεφώνου."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Τηλεφωνικές κλήσεις"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Παρακολούθηση, καταγραφή και επεξεργασία τηλεφωνικών κλήσεων."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Εργαλεία συστήματος"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Χαμηλού επιπέδου πρόσβαση και έλεγχος του συστήματος."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Εργαλεία ανάπτυξης"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Δυνατότητες που είναι απαραίτητες μόνο σε προγραμματιστές εφαρμογών."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Η ιστοσελίδα περιέχει ένα σφάλμα."</string>
+ <string name="httpErrorLookup">"Δεν ήταν δυνατή η εύρεση της διεύθυνσης URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Το πλάνο ελέγχου ταυτότητας ιστοτόπου δεν υποστηρίζεται."</string>
+ <string name="httpErrorAuth">"Ο έλεγχος ταυτότητας δεν ήταν επιτυχής."</string>
+ <string name="httpErrorProxyAuth">"Ο έλεγχος ταυτότητας μέσω του διακομιστή μεσολάβησης δεν ήταν επιτυχής."</string>
+ <string name="httpErrorConnect">"Η σύνδεση στον διακομιστή δεν ήταν επιτυχής."</string>
+ <string name="httpErrorIO">"Η επικοινωνία με τον διακομιστή απέτυχε. Προσπαθήστε ξανά αργότερα."</string>
+ <string name="httpErrorTimeout">"Το όριο χρόνου της σύνδεσης στον διακομιστή έληξε."</string>
+ <string name="httpErrorRedirectLoop">"Αυτή η σελίδα περιέχει πάρα πολλές ανακατευθύνσεις διακομιστή."</string>
+ <string name="httpErrorUnsupportedScheme">"Το πρωτόκολλο δεν υποστηρίζεται."</string>
+ <string name="httpErrorFailedSslHandshake">"Δεν ήταν δυνατή η επίτευξη ασφαλούς σύνδεσης."</string>
+ <string name="httpErrorBadUrl">"Δεν ήταν δυνατό το άνοιγμα της σελίδας επειδή η διεύθυνση URL δεν είναι έγκυρη."</string>
+ <string name="httpErrorFile">"Η πρόσβαση στο αρχείο δεν ήταν δυνατή."</string>
+ <string name="httpErrorFileNotFound">"Το αρχείο που ζητήθηκε δεν βρέθηκε."</string>
+ <string name="httpErrorTooManyRequests">"Πραγματοποιείται επεξεργασία πάρα πολλών αιτημάτων. Προσπαθήστε ξανά αργότερα."</string>
+ <string name="contentServiceSync">"Συγχρονισμός"</string>
+ <string name="contentServiceSyncNotificationTitle">"Συγχρονισμός"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
+ <string name="low_memory">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης! Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
+ <string name="me">"Για εμένα"</string>
+ <string name="power_dialog">"Επιλογές τηλεφώνου"</string>
+ <string name="silent_mode">"Λειτουργία σίγασης"</string>
+ <string name="turn_on_radio">"Ενεργοποίηση ασύρματου"</string>
+ <string name="turn_off_radio">"Απενεργοποίηση ασύρματου"</string>
+ <string name="screen_lock">"Κλείδωμα οθόνης"</string>
+ <string name="power_off">"Απενεργοποίηση"</string>
+ <string name="shutdown_progress">"Απενεργοποίηση..."</string>
+ <string name="shutdown_confirm">"Το τηλέφωνό σας θα απενεργοποιηθεί."</string>
+ <string name="no_recent_tasks">"Δεν υπάρχουν πρόσφατες εφαρμογές."</string>
+ <string name="global_actions">"Επιλογές τηλεφώνου"</string>
+ <string name="global_action_lock">"Κλείδωμα οθόνης"</string>
+ <string name="global_action_power_off">"Απενεργοποίηση"</string>
+ <string name="global_action_toggle_silent_mode">"Λειτουργία σίγασης"</string>
+ <string name="global_action_silent_mode_on_status">"Ο ήχος είναι απενεργοποιημένος"</string>
+ <string name="global_action_silent_mode_off_status">"Ο ήχος είναι ενεργοποιημένος"</string>
+ <string name="global_actions_toggle_airplane_mode">"Λειτουργία πτήσης"</string>
+ <string name="global_actions_airplane_mode_on_status">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
+ <string name="global_actions_airplane_mode_off_status">"Η λειτουργία πτήσης είναι απενεργοποιημένη"</string>
+ <string name="safeMode">"Ασφαλής λειτουργία"</string>
+ <string name="android_system_label">"Σύστημα Android"</string>
+ <string name="permgrouplab_costMoney">"Υπηρεσίες επί πληρωμή."</string>
+ <string name="permgroupdesc_costMoney">"Επιτρέπει σε εφαρμογές να πραγματοποιήσουν ενέργειες για τις οποίες ενδέχεται να χρεωθείτε."</string>
+ <string name="permgrouplab_messages">"Τα μηνύματά σας"</string>
+ <string name="permgroupdesc_messages">"Ανάγνωση και εγγραφή των μηνυμάτων SMS, των μηνυμάτων ηλεκτρονικού ταχυδρομείου και άλλων μηνυμάτων."</string>
+ <string name="permgrouplab_personalInfo">"Οι προσωπικές σας πληροφορίες"</string>
+ <string name="permgroupdesc_personalInfo">"Άμεση πρόσβαση στις επαφές και στο ημερολόγιό σας που είναι αποθηκευμένα στο τηλέφωνο."</string>
+ <string name="permgrouplab_location">"Η τοποθεσία σας"</string>
+ <string name="permgroupdesc_location">"Παρακολούθηση της φυσικής τοποθεσίας σας"</string>
+ <string name="permgrouplab_network">"Επικοινωνία δικτύου"</string>
+ <string name="permgroupdesc_network">"Επιτρέπει σε εφαρμογές να αποκτήσουν πρόσβαση σε διάφορες λειτουργίες δικτύου."</string>
+ <string name="permgrouplab_accounts">"Οι λογαριασμοί σας Google"</string>
+ <string name="permgroupdesc_accounts">"Πρόσβαση στους διαθέσιμους λογαριασμούς Google."</string>
+ <string name="permgrouplab_hardwareControls">"Στοιχεία ελέγχου υλικού"</string>
+ <string name="permgroupdesc_hardwareControls">"Άμεση πρόσβαση στο υλικό της συσκευής τηλεφώνου."</string>
+ <string name="permgrouplab_phoneCalls">"Τηλεφωνικές κλήσεις"</string>
+ <string name="permgroupdesc_phoneCalls">"Παρακολούθηση, καταγραφή και επεξεργασία τηλεφωνικών κλήσεων."</string>
+ <string name="permgrouplab_systemTools">"Εργαλεία συστήματος"</string>
+ <string name="permgroupdesc_systemTools">"Χαμηλού επιπέδου πρόσβαση και έλεγχος του συστήματος."</string>
+ <string name="permgrouplab_developmentTools">"Εργαλεία ανάπτυξης"</string>
+ <string name="permgroupdesc_developmentTools">"Δυνατότητες που είναι απαραίτητες μόνο σε προγραμματιστές εφαρμογών."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"απενεργοποίηση ή τροποποίηση γραμμής κατάστασης"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ανάπτυξη/σύμπτυξη γραμμής κατάστασης"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Επιτρέπει σε μια εφαρμογή να αναπτύξει ή να συμπτύξει την γραμμή κατάστασης."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"φραγή εξερχόμενων κλήσεων"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Επιτρέπει σε μια εφαρμογή την επεξεργασία εξερχόμενων κλήσεων και την αλλαγή του αριθμού που πρόκειται να κληθεί. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν, να ανακατευθύνουν ή να παρεμποδίζουν εξερχόμενες κλήσεις."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"λήψη SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Επιτρέπει σε μια εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"λήψη MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Επιτρέπει σε μια εφαρμογή την λήψη και την επεξεργασία μηνυμάτων MMS. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"αποστολή μηνυμάτων SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Επιτρέπει σε μια εφαρμογή την αποστολή μηνυμάτων SMS. Κακόβουλες εφαρμογές ενδέχεται να σας χρεώσουν αποστέλλοντας μηνύματα χωρίς την έγκρισή σας."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ανάγνωση μηνυμάτων SMS ή MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Επιτρέπει σε μια εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα SIM. Κακόβουλες εφαρμογές ενδέχεται να αναγνώσουν τα εμπιστευτικά σας μηνύματα."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"επεξεργασία SMS ή MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Επιτρέπει σε μια εφαρμογή την εγγραφή σε μηνύματα SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα SIM. Κακόβουλες εφαρμογές ενδέχεται να διαγράψουν τα μηνύματά σας."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"λήψη WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Επιτρέπει σε μια εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων WAP. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"ανάκτηση εκτελούμενων εφαρμογών"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Επιτρέπει σε μια εφαρμογή να ανακτήσει πληροφορίες σχετικά με τις τρέχουσες εκτελούμενες εργασίες και στις εργασίες που έχουν πρόσφατα εκτελεστεί. Ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαρμογές να ανακαλύψουν ιδιωτικές πληροφορίες σχετικά με άλλες εφαρμογές."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Επιτρέπει σε μια εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να τερματίσουν άλλες εφαρμογές."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Επιτρέπει σε μια εφαρμογή την αλλαγή της τρέχουσας διαμόρφωσης, όπως οι τοπικές ρυθμίσεις ή το μέγεθος γραμματοσειράς γενικά."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"επανεκκίνηση άλλων εφαρμογών"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Επιτρέπει σε μια εφαρμογή να πραγματοποιήσει αναγκαστική επανεκκίνηση άλλων εφαρμογών."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"αναγκαστικός τερματισμός εφαρμογής"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Επιτρέπει σε μια εφαρμογή να εξαναγκάσει οποιαδήποτε δραστηριότητα που βρίσκεται στο προσκήνιο να κλείσει και να μεταβεί στο φόντο. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"ανάκτηση εσωτερικής κατάστασης συστήματος"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Επιτρέπει σε μια εφαρμογή να ανακτήσει την εσωτερική κατάσταση του συστήματος. Κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν μεγάλο εύρος ιδιωτικών και ασφαλών πληροφοριών, τις οποίες δεν χρειάζονται."</string>
+ <string name="permlab_statusBar">"απενεργοποίηση ή τροποποίηση γραμμής κατάστασης"</string>
+ <string name="permdesc_statusBar">"Επιτρέπει στην εφαρμογή να απενεργοποιεί τη γραμμή κατάστασης ή να προσθέτει και να αφαιρεί εικονίδια συστήματος."</string>
+ <string name="permlab_expandStatusBar">"ανάπτυξη/σύμπτυξη γραμμής κατάστασης"</string>
+ <string name="permdesc_expandStatusBar">"Επιτρέπει σε μια εφαρμογή να αναπτύξει ή να συμπτύξει την γραμμή κατάστασης."</string>
+ <string name="permlab_processOutgoingCalls">"φραγή εξερχόμενων κλήσεων"</string>
+ <string name="permdesc_processOutgoingCalls">"Επιτρέπει σε μια εφαρμογή την επεξεργασία εξερχόμενων κλήσεων και την αλλαγή του αριθμού που πρόκειται να κληθεί. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν, να ανακατευθύνουν ή να παρεμποδίζουν εξερχόμενες κλήσεις."</string>
+ <string name="permlab_receiveSms">"λήψη SMS"</string>
+ <string name="permdesc_receiveSms">"Επιτρέπει σε μια εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
+ <string name="permlab_receiveMms">"λήψη MMS"</string>
+ <string name="permdesc_receiveMms">"Επιτρέπει σε μια εφαρμογή την λήψη και την επεξεργασία μηνυμάτων MMS. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
+ <string name="permlab_sendSms">"αποστολή μηνυμάτων SMS"</string>
+ <string name="permdesc_sendSms">"Επιτρέπει σε μια εφαρμογή την αποστολή μηνυμάτων SMS. Κακόβουλες εφαρμογές ενδέχεται να σας χρεώσουν αποστέλλοντας μηνύματα χωρίς την έγκρισή σας."</string>
+ <string name="permlab_readSms">"ανάγνωση μηνυμάτων SMS ή MMS"</string>
+ <string name="permdesc_readSms">"Επιτρέπει σε μια εφαρμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα SIM. Κακόβουλες εφαρμογές ενδέχεται να αναγνώσουν τα εμπιστευτικά σας μηνύματα."</string>
+ <string name="permlab_writeSms">"επεξεργασία SMS ή MMS"</string>
+ <string name="permdesc_writeSms">"Επιτρέπει σε μια εφαρμογή την εγγραφή σε μηνύματα SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάρτα SIM. Κακόβουλες εφαρμογές ενδέχεται να διαγράψουν τα μηνύματά σας."</string>
+ <string name="permlab_receiveWapPush">"λήψη WAP"</string>
+ <string name="permdesc_receiveWapPush">"Επιτρέπει σε μια εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων WAP. Κακόβουλες εφαρμογές ενδέχεται να παρακολουθούν τα μηνύματά σας ή να τα διαγράφουν χωρίς να σας ειδοποιούν."</string>
+ <string name="permlab_getTasks">"ανάκτηση εκτελούμενων εφαρμογών"</string>
+ <string name="permdesc_getTasks">"Επιτρέπει σε μια εφαρμογή να ανακτήσει πληροφορίες σχετικά με τις τρέχουσες εκτελούμενες εργασίες και στις εργασίες που έχουν πρόσφατα εκτελεστεί. Ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαρμογές να ανακαλύψουν ιδιωτικές πληροφορίες σχετικά με άλλες εφαρμογές."</string>
+ <string name="permlab_reorderTasks">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
+ <string name="permdesc_reorderTasks">"Επιτρέπει σε μια εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
+ <string name="permlab_setDebugApp">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
+ <string name="permdesc_setDebugApp">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να τερματίσουν άλλες εφαρμογές."</string>
+ <string name="permlab_changeConfiguration">"αλλαγή των ρυθμίσεων του UI"</string>
+ <string name="permdesc_changeConfiguration">"Επιτρέπει σε μια εφαρμογή την αλλαγή της τρέχουσας διαμόρφωσης, όπως οι τοπικές ρυθμίσεις ή το μέγεθος γραμματοσειράς γενικά."</string>
+ <string name="permlab_restartPackages">"επανεκκίνηση άλλων εφαρμογών"</string>
+ <string name="permdesc_restartPackages">"Επιτρέπει σε μια εφαρμογή να πραγματοποιήσει αναγκαστική επανεκκίνηση άλλων εφαρμογών."</string>
+ <string name="permlab_forceBack">"αναγκαστικός τερματισμός εφαρμογής"</string>
+ <string name="permdesc_forceBack">"Επιτρέπει σε μια εφαρμογή να εξαναγκάσει οποιαδήποτε δραστηριότητα που βρίσκεται στο προσκήνιο να κλείσει και να μεταβεί στο φόντο. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
+ <string name="permlab_dump">"ανάκτηση εσωτερικής κατάστασης συστήματος"</string>
+ <string name="permdesc_dump">"Επιτρέπει σε μια εφαρμογή να ανακτήσει την εσωτερική κατάσταση του συστήματος. Κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν μεγάλο εύρος ιδιωτικών και ασφαλών πληροφοριών, τις οποίες δεν χρειάζονται."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"παρακολούθηση και έλεγχος όλων των εκκινήσεων εφαρμογών"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Επιτρέπει σε μια εφαρμογή να παρακολουθεί και να ελέγχει τον τρόπο με τον οποίο το σύστημα εκκινεί δραστηριότητες. Κακόβουλες εφαρμογές ενδέχεται να θέσουν σε κίνδυνο το σύστημα. Αυτή η άδεια είναι απαραίτητη μόνο για ανάπτυξη και ποτέ για κανονική χρήση τηλεφώνου."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"αποστολή εκπομπής χωρίς πακέτο"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Επιτρέπει σε μια εφαρμογή την εκπομπή μια ειδοποίησης σχετικά με την κατάργηση ενός πακέτου εφαρμογών. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να τερματίσουν άλλες εκτελούμενες εφαρμογές."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"αποστολή εκπομπής που έχει ληφθεί με μήνυμα SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Επιτρέπει σε μια εφαρμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνύματος SMS. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για την δημιουργία πλαστών εισερχόμενων μηνυμάτων SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Επιτρέπει σε μια εφαρμογή να εκπέμψει μια ειδοποίηση σχετικά με τη λήψη μηνύματος WAP PUSH. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να δημιουργήσουν ψευδείς λήψεις μηνυμάτων MMS ή για να αντικαταστήσουν χωρίς ειδοποίηση το περιεχόμενο μιας ιστοσελίδας με κακόβουλες παραλλαγές."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"περιορισμός αριθμού εκτελούμενων διαδικασιών"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Επιτρέπει σε μια εφαρμογή τον έλεγχο του μέγιστου αριθμού διαδικασιών που θα εκτελούνται. Δεν είναι ποτέ απαραίτητο για κανονικές εφαρμογές."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"κλείσιμο όλων των εφαρμογών στο φόντο"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Επιτρέπει σε μια εφαρμογή να ελέγχει εάν οι δραστηριότητες ολοκληρώνονται πάντοτε μόλις μεταβούν στο φόντο. Δεν είναι ποτέ απαραίτητο για κανονικές εφαρμογές."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"τροποποίηση στατιστικών μπαταρίας"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Επιτρέπει την τροποποίηση στατιστικών μπαταρίας που έχουν συλλεχθεί. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
+ <string name="permlab_runSetActivityWatcher">"παρακολούθηση και έλεγχος όλων των εκκινήσεων εφαρμογών"</string>
+ <string name="permdesc_runSetActivityWatcher">"Επιτρέπει σε μια εφαρμογή να παρακολουθεί και να ελέγχει τον τρόπο με τον οποίο το σύστημα εκκινεί δραστηριότητες. Κακόβουλες εφαρμογές ενδέχεται να θέσουν σε κίνδυνο το σύστημα. Αυτή η άδεια είναι απαραίτητη μόνο για ανάπτυξη και ποτέ για κανονική χρήση τηλεφώνου."</string>
+ <string name="permlab_broadcastPackageRemoved">"αποστολή εκπομπής χωρίς πακέτο"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Επιτρέπει σε μια εφαρμογή την εκπομπή μια ειδοποίησης σχετικά με την κατάργηση ενός πακέτου εφαρμογών. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να τερματίσουν άλλες εκτελούμενες εφαρμογές."</string>
+ <string name="permlab_broadcastSmsReceived">"αποστολή εκπομπής που έχει ληφθεί με μήνυμα SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Επιτρέπει σε μια εφαρμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνύματος SMS. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για την δημιουργία πλαστών εισερχόμενων μηνυμάτων SMS."</string>
+ <string name="permlab_broadcastWapPush">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Επιτρέπει σε μια εφαρμογή να εκπέμψει μια ειδοποίηση σχετικά με τη λήψη μηνύματος WAP PUSH. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν για να δημιουργήσουν ψευδείς λήψεις μηνυμάτων MMS ή για να αντικαταστήσουν χωρίς ειδοποίηση το περιεχόμενο μιας ιστοσελίδας με κακόβουλες παραλλαγές."</string>
+ <string name="permlab_setProcessLimit">"περιορισμός αριθμού εκτελούμενων διαδικασιών"</string>
+ <string name="permdesc_setProcessLimit">"Επιτρέπει σε μια εφαρμογή τον έλεγχο του μέγιστου αριθμού διαδικασιών που θα εκτελούνται. Δεν είναι ποτέ απαραίτητο για κανονικές εφαρμογές."</string>
+ <string name="permlab_setAlwaysFinish">"κλείσιμο όλων των εφαρμογών στο φόντο"</string>
+ <string name="permdesc_setAlwaysFinish">"Επιτρέπει σε μια εφαρμογή να ελέγχει εάν οι δραστηριότητες ολοκληρώνονται πάντοτε μόλις μεταβούν στο φόντο. Δεν είναι ποτέ απαραίτητο για κανονικές εφαρμογές."</string>
+ <string name="permlab_batteryStats">"τροποποίηση στατιστικών μπαταρίας"</string>
+ <string name="permdesc_batteryStats">"Επιτρέπει την τροποποίηση στατιστικών μπαταρίας που έχουν συλλεχθεί. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"προβολή μη εξουσιοδοτημένων παραθύρων"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Επιτρέπει τη δημιουργία παραθύρων που πρόκειται να χρησιμοποιηθούν από την εσωτερική διεπαφή χρήστη του συστήματος. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"εμφάνιση ειδοποιήσεων επιπέδου συστήματος"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Επιτρέπει σε μια εφαρμογή την προβολή παραθύρων ειδοποίησης συστήματος. Κακόβουλες εφαρμογές μπορούν να εμφανιστούν σε ολόκληρη την οθόνη του τηλεφώνου."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"τροποποίηση καθολικής ταχύτητας κίνησης εικόνας"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Επιτρέπει σε μια εφαρμογή την αλλαγή της καθολικής ταχύτητας κίνησης εικόνας (ταχύτερη ή βραδύτερη κίνηση) οποιαδήποτε στιγμή."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"διαχείριση αναγνωριστικών εφαρμογής"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Επιτρέπει σε εφαρμογές τη δημιουργία και τη διαχείριση των δικών τους αναγνωριστικών, παρακάμπτοντας την κανονική διάταξη Z. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"πάτημα πλήκτρων και κουμπιών ελέγχου"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Επιτρέπει σε μια εφαρμογή την απόδοση των γεγονότων εισόδου της (πατήματα πλήκτρων κ.λπ.) σε άλλες εφαρμογές. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αναλάβουν τον έλεγχο του τηλεφώνου."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"καταγραφή των ενεργειών σας και των στοιχείων που πληκτρολογείτε"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Επιτρέπει σε εφαρμογές να παρακολουθούν τα πλήκτρα που πατάτε, ακόμη και σε μια άλλη εφαρμογή (όπως π.χ. η καταχώρηση ενός κωδικού πρόσβασης). Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"δέσμευση σε μέθοδο εισόδου"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Επιτρέπει σε μια εφαρμογή την αλλαγή της περιστροφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"αποστολή σημάτων Linux σε εφαρμογές"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Επιτρέπει σε μια εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"η εφαρμογή να εκτελείται συνεχώς"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Επιτρέπει σε μια εφαρμογή την μετατροπή τμημάτων της σε συνεχή, ώστε το σύστημα να μην μπορεί να τη χρησιμοποιήσει για άλλες εφαρμογές."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"διαγραφή εφαρμογών"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Επιτρέπει σε μια εφαρμογή τη διαγραφή πακέτων Android. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν σημαντικές εφαρμογές."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"διαγραφή δεδομένων άλλων εφαρμογών"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Επιτρέπει σε μια εφαρμογή να εκκαθαρίζει τα δεδομένα χρήστη."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"διαγραφή προσωρινών μνημών άλλων εφαρμογών"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Επιτρέπει σε μια εφαρμογή τη διαγραφή αρχείων προσωρινής μνήμης."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Επιτρέπει σε μια εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"απευθείας εγκατάσταση εφαρμογών"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Επιτρέπει σε μια εφαρμογή την εγκατάσταση νέων ή ενημερωμένων πακέτων Android. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσθέσουν νέες εφαρμογές με πολλές αυθαίρετες άδειες."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"διαγραφή όλων των δεδομένων προσωρινής μνήμης εφαρμογής"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Επιτρέπει σε μια εφαρμογή να αυξήσει τον ελεύθερο χώρο αποθήκευσης του τηλεφώνου διαγράφοντας αρχεία από τον κατάλογο προσωρινής μνήμης της εφαρμογής. Η πρόσβαση είναι συνήθως πολύ περιορισμένη στη διαδικασία συστήματος."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ανάγνωση αρχείων καταγραφής συστήματος"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Επιτρέπει σε μια εφαρμογή να αναγνώσει τα αρχεία καταγραφής του συστήματος. Έτσι μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, όμως δεν θα πρέπει να περιέχουν προσωπικές ή ιδιωτικές πληροφορίες."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Επιτρέπει σε μια εφαρμογή την ανάγνωση και την εγγραφή σε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού του κατασκευαστή ή του χειριστή."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Επιτρέπει σε μια εφαρμογή την επιλογή ενεργοποίησης ή μη ενός στοιχείου μιας άλλης εφαρμογής. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να απενεργοποιήσουν σημαντικές δυνατότητες του τηλεφώνου. Η χορήγηση άδειας πρέπει να γίνεται με προσοχή, καθώς είναι πιθανό τα στοιχεία μιας εφαρμογής να καταστούν ασυνεχή, ασταθή ή να είναι αδύνατον να χρησιμοποιηθούν."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ορισμός προτιμώμενων εφαρμογών"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τις εφαρμογές που προτιμάτε. Αυτό ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαρμογές να αλλάξουν χωρίς ειδοποίηση τις εφαρμογές που εκτελούνται, \"ξεγελώντας\" τις υπάρχουσες εφαρμογές ώστε να συλλέξουν ιδιωτικά δεδομένα."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"τροποποίηση καθολικών ρυθμίσεων συστήματος"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Κακόβουλες εφαρμογές μπορούν να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"τροποποίηση ασφαλών ρυθμίσεων συστήματος"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τα δεδομένα ασφαλών ρυθμίσεων συστήματος. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"μετατροπή του χάρτη υπηρεσιών Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Επιτρέπει σε μια εφαρμογή την τροποποίηση του χάρτη υπηρεσιών Google. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"αυτόματη εκκίνηση κατά την εκκίνηση του υπολογιστή"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Επιτρέπει σε μια εφαρμογή να ξεκινήσει αυτόματα μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του τηλεφώνου και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του τηλεφώνου, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"αποστολή εκπομπής sticky"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Επιτρέπει σε μια εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Κακόβουλες εφαρμογές μπορούν να μειώσουν την ταχύτητα λειτουργίας του τηλεφώνου ή να την καταστήσουν ασταθή χρησιμοποιώντας πολύ μεγάλο ποσό μνήμης."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ανάγνωση δεδομένων επαφής"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Επιτρέπει σε μια εφαρμογή την ανάγνωση όλων των δεδομένων επαφής (διεύθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αποστείλουν τα δεδομένα σας σε τρίτους."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"εγγραφή δεδομένων επαφής"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τα δεδομένα επαφής (διεύθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν τα δεδομένα επαφών σας."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"εγγραφή δεδομένων κατόχου"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τα δεδομένα κατόχου τηλεφώνου στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να τροποποιήσουν τα δεδομένα κατόχου."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ανάγνωση δεδομένων κατόχου"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των δεδομένων κατόχου τηλεφώνου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για την ανάγνωση δεδομένων κατόχου τηλεφώνου."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ανάγνωση δεδομένων ημερολογίου"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Επιτρέπει σε μια εφαρμογή να αναγνώσει όλα τα συμβάντα ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αποστείλουν συμβάντα ημερολογίου σε άλλους χρήστες."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"εγγραφή δεδομένων ημερολογίου"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των συμβάντων ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν ή για να τροποποιήσουν τα δεδομένα ημερολογίου σας."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"δημιουργία ψευδών πηγών τοποθεσίας για δοκιμή"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Δημιουργία εικονικών πηγών τοποθεσίας για δοκιμή. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να παρακάμψουν την τοποθεσία και/ή την κατάσταση που βρίσκουν πραγματικές πηγές τοποθεσίας, όπως πάροχοι GPS ή πάροχοι δικτύου."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν ώστε να παρέμβουν στη λειτουργία του GPS ή άλλων πηγών τοποθεσίας."</string>
+ <string name="permlab_internalSystemWindow">"προβολή μη εξουσιοδοτημένων παραθύρων"</string>
+ <string name="permdesc_internalSystemWindow">"Επιτρέπει τη δημιουργία παραθύρων που πρόκειται να χρησιμοποιηθούν από την εσωτερική διεπαφή χρήστη του συστήματος. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
+ <string name="permlab_systemAlertWindow">"εμφάνιση ειδοποιήσεων επιπέδου συστήματος"</string>
+ <string name="permdesc_systemAlertWindow">"Επιτρέπει σε μια εφαρμογή την προβολή παραθύρων ειδοποίησης συστήματος. Κακόβουλες εφαρμογές μπορούν να εμφανιστούν σε ολόκληρη την οθόνη του τηλεφώνου."</string>
+ <string name="permlab_setAnimationScale">"τροποποίηση καθολικής ταχύτητας κίνησης εικόνας"</string>
+ <string name="permdesc_setAnimationScale">"Επιτρέπει σε μια εφαρμογή την αλλαγή της καθολικής ταχύτητας κίνησης εικόνας (ταχύτερη ή βραδύτερη κίνηση) οποιαδήποτε στιγμή."</string>
+ <string name="permlab_manageAppTokens">"διαχείριση αναγνωριστικών εφαρμογής"</string>
+ <string name="permdesc_manageAppTokens">"Επιτρέπει σε εφαρμογές τη δημιουργία και τη διαχείριση των δικών τους αναγνωριστικών, παρακάμπτοντας την κανονική διάταξη Z. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
+ <string name="permlab_injectEvents">"πάτημα πλήκτρων και κουμπιών ελέγχου"</string>
+ <string name="permdesc_injectEvents">"Επιτρέπει σε μια εφαρμογή την απόδοση των γεγονότων εισόδου της (πατήματα πλήκτρων κ.λπ.) σε άλλες εφαρμογές. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αναλάβουν τον έλεγχο του τηλεφώνου."</string>
+ <string name="permlab_readInputState">"καταγραφή των ενεργειών σας και των στοιχείων που πληκτρολογείτε"</string>
+ <string name="permdesc_readInputState">"Επιτρέπει σε εφαρμογές να παρακολουθούν τα πλήκτρα που πατάτε, ακόμη και σε μια άλλη εφαρμογή (όπως π.χ. η καταχώρηση ενός κωδικού πρόσβασης). Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
+ <string name="permlab_bindInputMethod">"δέσμευση σε μέθοδο εισόδου"</string>
+ <string name="permdesc_bindInputMethod">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
+ <string name="permlab_setOrientation">"αλλαγή προσανατολισμού οθόνης"</string>
+ <string name="permdesc_setOrientation">"Επιτρέπει σε μια εφαρμογή την αλλαγή της περιστροφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
+ <string name="permlab_signalPersistentProcesses">"αποστολή σημάτων Linux σε εφαρμογές"</string>
+ <string name="permdesc_signalPersistentProcesses">"Επιτρέπει σε μια εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string>
+ <string name="permlab_persistentActivity">"η εφαρμογή να εκτελείται συνεχώς"</string>
+ <string name="permdesc_persistentActivity">"Επιτρέπει σε μια εφαρμογή την μετατροπή τμημάτων της σε συνεχή, ώστε το σύστημα να μην μπορεί να τη χρησιμοποιήσει για άλλες εφαρμογές."</string>
+ <string name="permlab_deletePackages">"διαγραφή εφαρμογών"</string>
+ <string name="permdesc_deletePackages">"Επιτρέπει σε μια εφαρμογή τη διαγραφή πακέτων Android. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν σημαντικές εφαρμογές."</string>
+ <string name="permlab_clearAppUserData">"διαγραφή δεδομένων άλλων εφαρμογών"</string>
+ <string name="permdesc_clearAppUserData">"Επιτρέπει σε μια εφαρμογή να εκκαθαρίζει τα δεδομένα χρήστη."</string>
+ <string name="permlab_deleteCacheFiles">"διαγραφή προσωρινών μνημών άλλων εφαρμογών"</string>
+ <string name="permdesc_deleteCacheFiles">"Επιτρέπει σε μια εφαρμογή τη διαγραφή αρχείων προσωρινής μνήμης."</string>
+ <string name="permlab_getPackageSize">"μέτρηση αποθηκευτικού χώρου εφαρμογής"</string>
+ <string name="permdesc_getPackageSize">"Επιτρέπει σε μια εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
+ <string name="permlab_installPackages">"απευθείας εγκατάσταση εφαρμογών"</string>
+ <string name="permdesc_installPackages">"Επιτρέπει σε μια εφαρμογή την εγκατάσταση νέων ή ενημερωμένων πακέτων Android. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσθέσουν νέες εφαρμογές με πολλές αυθαίρετες άδειες."</string>
+ <string name="permlab_clearAppCache">"διαγραφή όλων των δεδομένων προσωρινής μνήμης εφαρμογής"</string>
+ <string name="permdesc_clearAppCache">"Επιτρέπει σε μια εφαρμογή να αυξήσει τον ελεύθερο χώρο αποθήκευσης του τηλεφώνου διαγράφοντας αρχεία από τον κατάλογο προσωρινής μνήμης της εφαρμογής. Η πρόσβαση είναι συνήθως πολύ περιορισμένη στη διαδικασία συστήματος."</string>
+ <string name="permlab_readLogs">"ανάγνωση αρχείων καταγραφής συστήματος"</string>
+ <string name="permdesc_readLogs">"Επιτρέπει σε μια εφαρμογή να αναγνώσει τα αρχεία καταγραφής του συστήματος. Έτσι μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, όμως δεν θα πρέπει να περιέχουν προσωπικές ή ιδιωτικές πληροφορίες."</string>
+ <string name="permlab_diagnostic">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
+ <string name="permdesc_diagnostic">"Επιτρέπει σε μια εφαρμογή την ανάγνωση και την εγγραφή σε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού του κατασκευαστή ή του χειριστή."</string>
+ <string name="permlab_changeComponentState">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
+ <string name="permdesc_changeComponentState">"Επιτρέπει σε μια εφαρμογή την επιλογή ενεργοποίησης ή μη ενός στοιχείου μιας άλλης εφαρμογής. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να απενεργοποιήσουν σημαντικές δυνατότητες του τηλεφώνου. Η χορήγηση άδειας πρέπει να γίνεται με προσοχή, καθώς είναι πιθανό τα στοιχεία μιας εφαρμογής να καταστούν ασυνεχή, ασταθή ή να είναι αδύνατον να χρησιμοποιηθούν."</string>
+ <string name="permlab_setPreferredApplications">"ορισμός προτιμώμενων εφαρμογών"</string>
+ <string name="permdesc_setPreferredApplications">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τις εφαρμογές που προτιμάτε. Αυτό ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαρμογές να αλλάξουν χωρίς ειδοποίηση τις εφαρμογές που εκτελούνται, \"ξεγελώντας\" τις υπάρχουσες εφαρμογές ώστε να συλλέξουν ιδιωτικά δεδομένα."</string>
+ <string name="permlab_writeSettings">"τροποποίηση καθολικών ρυθμίσεων συστήματος"</string>
+ <string name="permdesc_writeSettings">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των δεδομένων των ρυθμίσεων του συστήματος. Κακόβουλες εφαρμογές μπορούν να καταστρέψουν τη διαμόρφωση του συστήματός σας."</string>
+ <string name="permlab_writeSecureSettings">"τροποποίηση ασφαλών ρυθμίσεων συστήματος"</string>
+ <string name="permdesc_writeSecureSettings">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τα δεδομένα ασφαλών ρυθμίσεων συστήματος. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
+ <string name="permlab_writeGservices">"μετατροπή του χάρτη υπηρεσιών Google"</string>
+ <string name="permdesc_writeGservices">"Επιτρέπει σε μια εφαρμογή την τροποποίηση του χάρτη υπηρεσιών Google. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
+ <string name="permlab_receiveBootCompleted">"αυτόματη εκκίνηση κατά την εκκίνηση του υπολογιστή"</string>
+ <string name="permdesc_receiveBootCompleted">"Επιτρέπει σε μια εφαρμογή να ξεκινήσει αυτόματα μόλις ολοκληρωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστερήσει την εκκίνηση του τηλεφώνου και να προκαλέσει γενική μείωση της ταχύτητας λειτουργίας του τηλεφώνου, καθώς η εφαρμογή θα εκτελείται συνεχώς."</string>
+ <string name="permlab_broadcastSticky">"αποστολή εκπομπής sticky"</string>
+ <string name="permdesc_broadcastSticky">"Επιτρέπει σε μια εφαρμογή την αποστολή εκπομπών sticky, οι οποίες παραμένουν μετά το τέλος της εκπομπής. Κακόβουλες εφαρμογές μπορούν να μειώσουν την ταχύτητα λειτουργίας του τηλεφώνου ή να την καταστήσουν ασταθή χρησιμοποιώντας πολύ μεγάλο ποσό μνήμης."</string>
+ <string name="permlab_readContacts">"ανάγνωση δεδομένων επαφής"</string>
+ <string name="permdesc_readContacts">"Επιτρέπει σε μια εφαρμογή την ανάγνωση όλων των δεδομένων επαφής (διεύθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αποστείλουν τα δεδομένα σας σε τρίτους."</string>
+ <string name="permlab_writeContacts">"εγγραφή δεδομένων επαφής"</string>
+ <string name="permdesc_writeContacts">"Επιτρέπει σε μια εφαρμογή να τροποποιεί τα δεδομένα επαφής (διεύθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν ή να τροποποιήσουν τα δεδομένα επαφών σας."</string>
+ <string name="permlab_writeOwnerData">"εγγραφή δεδομένων κατόχου"</string>
+ <string name="permdesc_writeOwnerData">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τα δεδομένα κατόχου τηλεφώνου στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να τροποποιήσουν τα δεδομένα κατόχου."</string>
+ <string name="permlab_readOwnerData">"ανάγνωση δεδομένων κατόχου"</string>
+ <string name="permdesc_readOwnerData">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των δεδομένων κατόχου τηλεφώνου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για την ανάγνωση δεδομένων κατόχου τηλεφώνου."</string>
+ <string name="permlab_readCalendar">"ανάγνωση δεδομένων ημερολογίου"</string>
+ <string name="permdesc_readCalendar">"Επιτρέπει σε μια εφαρμογή να αναγνώσει όλα τα συμβάντα ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να αποστείλουν συμβάντα ημερολογίου σε άλλους χρήστες."</string>
+ <string name="permlab_writeCalendar">"εγγραφή δεδομένων ημερολογίου"</string>
+ <string name="permdesc_writeCalendar">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των συμβάντων ημερολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να διαγράψουν ή για να τροποποιήσουν τα δεδομένα ημερολογίου σας."</string>
+ <string name="permlab_accessMockLocation">"δημιουργία ψευδών πηγών τοποθεσίας για δοκιμή"</string>
+ <string name="permdesc_accessMockLocation">"Δημιουργία εικονικών πηγών τοποθεσίας για δοκιμή. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να παρακάμψουν την τοποθεσία και/ή την κατάσταση που βρίσκουν πραγματικές πηγές τοποθεσίας, όπως πάροχοι GPS ή πάροχοι δικτύου."</string>
+ <string name="permlab_accessLocationExtraCommands">"πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Πρόσβαση σε επιπλέον εντολές παρόχου τοποθεσίας. Κακόβουλες εφαρμογές ενδέχεται να το χρησιμοποιήσουν ώστε να παρέμβουν στη λειτουργία του GPS ή άλλων πηγών τοποθεσίας."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ακριβής τοποθεσία (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Πρόσβαση σε πηγές ακριβούς τοποθεσίας, όπως το Παγκόσμιο Σύστημα Εντοπισμού (GPS) στο τηλέφωνο, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσδιορίσουν τη θέση που βρίσκεστε και ενδέχεται να καταναλώσουν επιπλέον ισχύ μπαταρίας."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"κατά προσέγγιση (βασισμένη στο δίκτυο) τοποθεσία"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Πρόσβαση σε πηγές κατά προσέγγιση τοποθεσίας, όπως η βάση δεδομένων δικτύου κινητής τηλεφωνίας για τον κατά προσέγγιση προσδιορισμό της τοποθεσίας του τηλεφώνου, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσδιορίσουν κατά προσέγγιση τη θέση σας."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"πρόσβαση στο SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες SurfaceFlinger χαμηλού επιπέδου."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ανάγνωση προσωρινής μνήμης πλαισίου"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Επιτρέπει στην εφαρμογή να χρησιμοποιήσει και να αναγνώσει το περιεχόμενο της προσωρινής μνήμης πλαισίου."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλαγή των ρυθμίσεων ήχου"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει καθολικές ρυθμίσεις ήχου όπως ένταση ήχου και δρομολόγηση ήχου."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγραφή ήχου"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Επιτρέπει σε μια εφαρμογή την πρόσβαση στη διαδρομή εγγραφής ήχου."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"λήψη φωτογραφιών"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Επιτρέπει σε μια εφαρμογή τη λήψη φωτογραφιών με την κάμερα. Αυτό επιτρέπει στην εφαρμογή να συλλέξει εικόνες, στις οποίες εστιάζει η κάμερα οποιαδήποτε στιγμή."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"μόνιμη απενεργοποίηση τηλεφώνου"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Επιτρέπει στην εφαρμογή τη μόνιμη απενεργοποίηση όλων των λειτουργιών του τηλεφώνου, το οποίο είναι εξαιρετικά επικίνδυνο."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"αναγκαστική επανεκκίνηση τηλεφώνου"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Επιτρέπει στην εφαρμογή να προκαλέσει αναγκαστική επανεκκίνηση του τηλεφώνου."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"σύνδεση και αποσύνδεση συστημάτων αρχείων"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Επιτρέπει στην εφαρμογή την προσάρτηση και αποπροσάρτηση συστημάτων αρχείων για αφαιρούμενο αποθηκευτικό χώρο."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"διαμόρφωση εξωτερικού αποθηκευτικού χώρου"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Επιτρέπει στην εφαρμογή τη διαμόρφωση αφαιρούμενου αποθηκευτικού χώρου."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"έλεγχος δόνησης"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Επιτρέπει στην εφαρμογή τον έλεγχο του δονητή."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"δοκιμή υλικού"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Επιτρέπει σε μια εφαρμογή τον έλεγχο διαφόρων περιφερειακών για την εκτέλεση δοκιμών υλικού."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Επιτρέπει σε μια εφαρμογή την κλήση τηλεφωνικών αριθμών χωρίς την παρέμβασή σας. Κακόβουλες εφαρμογές ενδέχεται να ευθύνονται για μη αναμενόμενες κλήσεις στον λογαριασμό τηλεφώνου σας. Λάβετε υπόψη ότι αυτό δεν επιτρέπει την κλήση αριθμών έκτακτης ανάγκης."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Επιτρέπει στην εφαρμογή την κλήση τηλεφωνικού αριθμού, συμπεριλαμβανομένων και αριθμών έκτακτης ανάγκης, χωρίς την παρέμβασή σας. Κακόβουλες εφαρμογές ενδέχεται να πραγματοποιήσουν μη αναγκαίες και παράνομες κλήσεις σε υπηρεσίες έκτακτης ανάγκης."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"έλεγχος ειδοποιήσεων ενημέρωσης τοποθεσίας"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Επιτρέπει την ενεργοποίηση/απενεργοποίηση ειδοποιήσεων ενημέρωσης τοποθεσίας από τον πομπό. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"πρόσβαση σε ιδιότητες ελέγχου εισόδου"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Επιτρέπει την πρόσβαση για ανάγνωση/εγγραφή σε ιδιότητες που έχουν μεταφορτωθεί από την υπηρεσία ελέγχου εισόδου. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"επιλογή γραφικών στοιχείων"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Επιτρέπει στην εφαρμογή να ορίσει στο σύστημα ποια γραφικά στοιχεία μπορεί να χρησιμοποιήσει κάθε εφαρμογή. Με αυτή την άδεια, οι εφαρμογές μπορούν να παρέχουν πρόσβαση σε προσωπικά δεδομένα σε άλλες εφαρμογές. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"τροποποίηση κατάστασης τηλεφώνου"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Επιτρέπει στην εφαρμογή τον έλεγχο των τηλεφωνικών δυνατοτήτων της συσκευής. Μια εφαρμογή με αυτήν την άδεια μπορεί να πραγματοποιήσει εναλλαγή μεταξύ δικτύων, να ενεργοποιήσει και να απενεργοποιήσει τον πομπό του τηλεφώνου κ.λπ. χωρίς να σας ειδοποιήσει."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Επιτρέπει σε μια εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ενεργοποίηση και απενεργοποίηση τηλεφώνου"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει ή να απενεργοποιήσει το τηλέφωνο."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"εκτέλεση σε λειτουργία εργοστασιακής δοκιμής"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Εκτέλεση ως χαμηλού επιπέδου δοκιμή κατασκευαστή, ώστε να επιτρέπεται πλήρης πρόσβαση στο υλικό του τηλεφώνου. Διαθέσιμο μόνο όταν το τηλέφωνο βρίσκεται σε λειτουργία δοκιμής κατασκευαστή."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"ορισμός ταπετσαρίας"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Επιτρέπει στην εφαρμογή τον ορισμό της ταπετσαρίας συστήματος."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"ορισμός συμβουλών μεγέθους ταπετσαρίας"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Επιτρέπει στην εφαρμογή τον ορισμό συμβουλών μεγέθους ταπετσαρίας συστήματος."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"επαναφορά συστήματος στις εργοστασιακές προεπιλογές"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Επιτρέπει σε μια εφαρμογή να επαναφέρει πλήρως το σύστημα στις εργοστασιακές ρυθμίσεις, διαγράφοντας όλα τα δεδομένα, τις διαμορφώσεις και τις εγκατεστημένες εφαρμογές."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"ορισμός ζώνης ώρας"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Επιτρέπει σε μια εφαρμογή την αλλαγή της ζώνης ώρας του τηλεφώνου."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"ανακάλυψη γνωστών λογαριασμών"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Επιτρέπει σε μια εφαρμογή να λάβει τη λίστα λογαριασμών του τηλεφώνου."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"προβολή κατάστασης δικτύου"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Επιτρέπει σε μια εφαρμογή την προβολή της κατάστασης όλων των δικτύων."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"πλήρης πρόσβαση στο Διαδίκτυο"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Επιτρέπει σε μια εφαρμογή τη δημιουργία υποδοχών δικτύου (sockets)."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"εγγραφή ρυθμίσεων Ονόματος σημείου πρόσβασης (APN)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τις ρυθμίσεις APN, όπως Διακομιστής μεσολάβησης και Θύρα για ένα APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλαγή συνδεσιμότητας δικτύου"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Επιτρέπει σε μια εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"αλλαγή ρύθμισης της χρήσης δεδομένων στο παρασκήνιο"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Επιτρέπει σε μια εφαρμογή την αλλαγή της ρύθμισης χρήσης δεδομένων φόντου."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"προβολή κατάστασης Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Επιτρέπει σε μια εφαρμογή την προβολή των πληροφοριών σχετικά με την κατάσταση του Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"αλλαγή κατάστασης Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Επιτρέπει σε μια εφαρμογή τη σύνδεση σε σημεία πρόσβασης Wi-Fi και την αποσύνδεση από αυτά, καθώς και την πραγματοποίηση αλλαγών σε διαμορφωμένα δίκτυα Wi-Fi."</string>
+ <string name="permlab_accessFineLocation">"ακριβής τοποθεσία (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Πρόσβαση σε πηγές ακριβούς τοποθεσίας, όπως το Παγκόσμιο Σύστημα Εντοπισμού (GPS) στο τηλέφωνο, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσδιορίσουν τη θέση που βρίσκεστε και ενδέχεται να καταναλώσουν επιπλέον ισχύ μπαταρίας."</string>
+ <string name="permlab_accessCoarseLocation">"κατά προσέγγιση (βασισμένη στο δίκτυο) τοποθεσία"</string>
+ <string name="permdesc_accessCoarseLocation">"Πρόσβαση σε πηγές κατά προσέγγιση τοποθεσίας, όπως η βάση δεδομένων δικτύου κινητής τηλεφωνίας για τον κατά προσέγγιση προσδιορισμό της τοποθεσίας του τηλεφώνου, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να προσδιορίσουν κατά προσέγγιση τη θέση σας."</string>
+ <string name="permlab_accessSurfaceFlinger">"πρόσβαση στο SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες SurfaceFlinger χαμηλού επιπέδου."</string>
+ <string name="permlab_readFrameBuffer">"ανάγνωση προσωρινής μνήμης πλαισίου"</string>
+ <string name="permdesc_readFrameBuffer">"Επιτρέπει στην εφαρμογή να χρησιμοποιήσει και να αναγνώσει το περιεχόμενο της προσωρινής μνήμης πλαισίου."</string>
+ <string name="permlab_modifyAudioSettings">"αλλαγή των ρυθμίσεων ήχου"</string>
+ <string name="permdesc_modifyAudioSettings">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει καθολικές ρυθμίσεις ήχου όπως ένταση ήχου και δρομολόγηση ήχου."</string>
+ <string name="permlab_recordAudio">"εγγραφή ήχου"</string>
+ <string name="permdesc_recordAudio">"Επιτρέπει σε μια εφαρμογή την πρόσβαση στη διαδρομή εγγραφής ήχου."</string>
+ <string name="permlab_camera">"λήψη φωτογραφιών"</string>
+ <string name="permdesc_camera">"Επιτρέπει σε μια εφαρμογή τη λήψη φωτογραφιών με την κάμερα. Αυτό επιτρέπει στην εφαρμογή να συλλέξει εικόνες, στις οποίες εστιάζει η κάμερα οποιαδήποτε στιγμή."</string>
+ <string name="permlab_brick">"μόνιμη απενεργοποίηση τηλεφώνου"</string>
+ <string name="permdesc_brick">"Επιτρέπει στην εφαρμογή τη μόνιμη απενεργοποίηση όλων των λειτουργιών του τηλεφώνου, το οποίο είναι εξαιρετικά επικίνδυνο."</string>
+ <string name="permlab_reboot">"αναγκαστική επανεκκίνηση τηλεφώνου"</string>
+ <string name="permdesc_reboot">"Επιτρέπει στην εφαρμογή να προκαλέσει αναγκαστική επανεκκίνηση του τηλεφώνου."</string>
+ <string name="permlab_mount_unmount_filesystems">"Προσάρτηση και αποπροσάρτηση συστημάτων αρχείων"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Επιτρέπει στην εφαρμογή την προσάρτηση και αποπροσάρτηση συστημάτων αρχείων για αφαιρούμενο αποθηκευτικό χώρο."</string>
+ <string name="permlab_mount_format_filesystems">"διαμόρφωση εξωτερικού αποθηκευτικού χώρου"</string>
+ <string name="permdesc_mount_format_filesystems">"Επιτρέπει στην εφαρμογή τη διαμόρφωση αφαιρούμενου αποθηκευτικού χώρου."</string>
+ <string name="permlab_vibrate">"έλεγχος δόνησης"</string>
+ <string name="permdesc_vibrate">"Επιτρέπει στην εφαρμογή τον έλεγχο του δονητή."</string>
+ <string name="permlab_flashlight">"έλεγχος φακού"</string>
+ <string name="permdesc_flashlight">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
+ <string name="permlab_hardware_test">"δοκιμή υλικού"</string>
+ <string name="permdesc_hardware_test">"Επιτρέπει σε μια εφαρμογή τον έλεγχο διαφόρων περιφερειακών για την εκτέλεση δοκιμών υλικού."</string>
+ <string name="permlab_callPhone">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
+ <string name="permdesc_callPhone">"Επιτρέπει σε μια εφαρμογή την κλήση τηλεφωνικών αριθμών χωρίς την παρέμβασή σας. Κακόβουλες εφαρμογές ενδέχεται να ευθύνονται για μη αναμενόμενες κλήσεις στον λογαριασμό τηλεφώνου σας. Λάβετε υπόψη ότι αυτό δεν επιτρέπει την κλήση αριθμών έκτακτης ανάγκης."</string>
+ <string name="permlab_callPrivileged">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
+ <string name="permdesc_callPrivileged">"Επιτρέπει στην εφαρμογή την κλήση τηλεφωνικού αριθμού, συμπεριλαμβανομένων και αριθμών έκτακτης ανάγκης, χωρίς την παρέμβασή σας. Κακόβουλες εφαρμογές ενδέχεται να πραγματοποιήσουν μη αναγκαίες και παράνομες κλήσεις σε υπηρεσίες έκτακτης ανάγκης."</string>
+ <string name="permlab_locationUpdates">"έλεγχος ειδοποιήσεων ενημέρωσης τοποθεσίας"</string>
+ <string name="permdesc_locationUpdates">"Επιτρέπει την ενεργοποίηση/απενεργοποίηση ειδοποιήσεων ενημέρωσης τοποθεσίας από τον πομπό. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
+ <string name="permlab_checkinProperties">"πρόσβαση σε ιδιότητες ελέγχου εισόδου"</string>
+ <string name="permdesc_checkinProperties">"Επιτρέπει την πρόσβαση για ανάγνωση/εγγραφή σε ιδιότητες που έχουν μεταφορτωθεί από την υπηρεσία ελέγχου εισόδου. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
+ <string name="permlab_bindGadget">"επιλογή γραφικών στοιχείων"</string>
+ <string name="permdesc_bindGadget">"Επιτρέπει στην εφαρμογή να ορίσει στο σύστημα ποια γραφικά στοιχεία μπορεί να χρησιμοποιήσει κάθε εφαρμογή. Με αυτή την άδεια, οι εφαρμογές μπορούν να παρέχουν πρόσβαση σε προσωπικά δεδομένα σε άλλες εφαρμογές. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
+ <string name="permlab_modifyPhoneState">"τροποποίηση κατάστασης τηλεφώνου"</string>
+ <string name="permdesc_modifyPhoneState">"Επιτρέπει στην εφαρμογή τον έλεγχο των τηλεφωνικών δυνατοτήτων της συσκευής. Μια εφαρμογή με αυτήν την άδεια μπορεί να πραγματοποιήσει εναλλαγή μεταξύ δικτύων, να ενεργοποιήσει και να απενεργοποιήσει τον πομπό του τηλεφώνου κ.λπ. χωρίς να σας ειδοποιήσει."</string>
+ <string name="permlab_readPhoneState">"ανάγνωση κατάστασης τηλεφώνου"</string>
+ <string name="permdesc_readPhoneState">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Μια εφαρμογή με αυτή την άδεια μπορεί να προσδιορίσει τον τηλεφωνικό αριθμό του τηλεφώνου, αν μια κλήση είναι ενεργή ή όχι, τον τηλεφωνικό αριθμό της κλήσης κ.λπ.."</string>
+ <string name="permlab_wakeLock">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
+ <string name="permdesc_wakeLock">"Επιτρέπει σε μια εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
+ <string name="permlab_devicePower">"ενεργοποίηση και απενεργοποίηση τηλεφώνου"</string>
+ <string name="permdesc_devicePower">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει ή να απενεργοποιήσει το τηλέφωνο."</string>
+ <string name="permlab_factoryTest">"εκτέλεση σε λειτουργία εργοστασιακής δοκιμής"</string>
+ <string name="permdesc_factoryTest">"Εκτέλεση ως χαμηλού επιπέδου δοκιμή κατασκευαστή, ώστε να επιτρέπεται πλήρης πρόσβαση στο υλικό του τηλεφώνου. Διαθέσιμο μόνο όταν το τηλέφωνο βρίσκεται σε λειτουργία δοκιμής κατασκευαστή."</string>
+ <string name="permlab_setWallpaper">"ορισμός ταπετσαρίας"</string>
+ <string name="permdesc_setWallpaper">"Επιτρέπει στην εφαρμογή τον ορισμό της ταπετσαρίας συστήματος."</string>
+ <string name="permlab_setWallpaperHints">"ορισμός συμβουλών μεγέθους ταπετσαρίας"</string>
+ <string name="permdesc_setWallpaperHints">"Επιτρέπει στην εφαρμογή τον ορισμό συμβουλών μεγέθους ταπετσαρίας συστήματος."</string>
+ <string name="permlab_masterClear">"επαναφορά συστήματος στις εργοστασιακές προεπιλογές"</string>
+ <string name="permdesc_masterClear">"Επιτρέπει σε μια εφαρμογή να επαναφέρει πλήρως το σύστημα στις εργοστασιακές ρυθμίσεις, διαγράφοντας όλα τα δεδομένα, τις διαμορφώσεις και τις εγκατεστημένες εφαρμογές."</string>
+ <string name="permlab_setTimeZone">"ορισμός ζώνης ώρας"</string>
+ <string name="permdesc_setTimeZone">"Επιτρέπει σε μια εφαρμογή την αλλαγή της ζώνης ώρας του τηλεφώνου."</string>
+ <string name="permlab_getAccounts">"ανακάλυψη γνωστών λογαριασμών"</string>
+ <string name="permdesc_getAccounts">"Επιτρέπει σε μια εφαρμογή να λάβει τη λίστα λογαριασμών του τηλεφώνου."</string>
+ <string name="permlab_accessNetworkState">"προβολή κατάστασης δικτύου"</string>
+ <string name="permdesc_accessNetworkState">"Επιτρέπει σε μια εφαρμογή την προβολή της κατάστασης όλων των δικτύων."</string>
+ <string name="permlab_createNetworkSockets">"πλήρης πρόσβαση στο Διαδίκτυο"</string>
+ <string name="permdesc_createNetworkSockets">"Επιτρέπει σε μια εφαρμογή τη δημιουργία υποδοχών δικτύου (sockets)."</string>
+ <string name="permlab_writeApnSettings">"εγγραφή ρυθμίσεων Ονόματος σημείου πρόσβασης (APN)"</string>
+ <string name="permdesc_writeApnSettings">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τις ρυθμίσεις APN, όπως Διακομιστής μεσολάβησης και Θύρα για ένα APN."</string>
+ <string name="permlab_changeNetworkState">"αλλαγή συνδεσιμότητας δικτύου"</string>
+ <string name="permdesc_changeNetworkState">"Επιτρέπει σε μια εφαρμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτύου."</string>
+ <string name="permlab_changeBackgroundDataSetting">"αλλαγή ρύθμισης της χρήσης δεδομένων στο παρασκήνιο"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Επιτρέπει σε μια εφαρμογή την αλλαγή της ρύθμισης χρήσης δεδομένων φόντου."</string>
+ <string name="permlab_accessWifiState">"προβολή κατάστασης Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Επιτρέπει σε μια εφαρμογή την προβολή των πληροφοριών σχετικά με την κατάσταση του Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"αλλαγή κατάστασης Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Επιτρέπει σε μια εφαρμογή τη σύνδεση σε σημεία πρόσβασης Wi-Fi και την αποσύνδεση από αυτά, καθώς και την πραγματοποίηση αλλαγών σε διαμορφωμένα δίκτυα Wi-Fi."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"διαχείριση Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Επιτρέπει σε μια εφαρμογή τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και την ανακάλυψη και σύζευξη με απομακρυσμένες συσκευές."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"δημιουργία συνδέσεων Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Επιτρέπει σε μια εφαρμογή να προβάλει τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και επίσης να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"απενεργοποίηση κλειδώματος πληκτρολογίου"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Επιτρέπει σε μια εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, η απενεργοποίηση του κλειδώματος πληκτρολογίου όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και η επανενεργοποίηση του κλειδώματος πληκτρολογίου όταν η κλήση τερματιστεί."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού, όπως π.χ. εάν ο συγχρονισμός είναι ενεργοποιημένος για τις Επαφές."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"καταγραφή ρυθμίσεων συγχρονισμού"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των ρυθμίσεων συγχρονισμού (π.χ. εάν ο συγχρονισμός είναι ενεργοποιημένος για τις Επαφές)."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ανάγνωση στατιστικών συγχρονισμού"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των στατιστικών συγχρονισμού (π.χ. το ιστορικό των συγχρονισμών που έχουν πραγματοποιηθεί)."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ανάγνωση ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Επιτρέπει σε μια εφαρμογή τη λήψη λεπτομερειών σχετικά με τις τρέχουσες συγχρονισμένες ροές δεδομένων."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"εγγραφή ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τις ροές δεδομένων, με τις οποίες είστε συγχρονισμένοι αυτή τη στιγμή. Αυτό θα μπορούσε να δώσει τη δυνατότητα σε μια κακόβουλη εφαρμογή να αλλάξει τις συγχρονισμένες ροές δεδομένων σας."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ανάγνωση καθορισμένου από το χρήστη λεξικού"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Επιτρέπει σε μια εφαρμογή να αναγνώσει ιδιωτικές λέξεις και φράσεις και ιδιωτικά ονόματα, τα οποία ο χρήστης ενδέχεται να έχει αποθηκεύσει στο λεξικό χρήστη."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"εγγραφή σε καθορισμένο από τον χρήστη λεξικό"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Επιτρέπει σε μια εφαρμογή την εγγραφή νέων λέξεων στο λεξικό χρήστη."</string>
+ <string name="permlab_bluetoothAdmin">"διαχείριση bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Επιτρέπει σε μια εφαρμογή τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και την ανακάλυψη και σύζευξη με απομακρυσμένες συσκευές."</string>
+ <string name="permlab_bluetooth">"δημιουργία συνδέσεων Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Επιτρέπει σε μια εφαρμογή να προβάλει τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και επίσης να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
+ <string name="permlab_disableKeyguard">"απενεργοποίηση κλειδώματος πληκτρολογίου"</string>
+ <string name="permdesc_disableKeyguard">"Επιτρέπει σε μια εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, η απενεργοποίηση του κλειδώματος πληκτρολογίου όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και η επανενεργοποίηση του κλειδώματος πληκτρολογίου όταν η κλήση τερματιστεί."</string>
+ <string name="permlab_readSyncSettings">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
+ <string name="permdesc_readSyncSettings">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού, όπως π.χ. εάν ο συγχρονισμός είναι ενεργοποιημένος για τις Επαφές."</string>
+ <string name="permlab_writeSyncSettings">"καταγραφή ρυθμίσεων συγχρονισμού"</string>
+ <string name="permdesc_writeSyncSettings">"Επιτρέπει σε μια εφαρμογή την τροποποίηση των ρυθμίσεων συγχρονισμού (π.χ. εάν ο συγχρονισμός είναι ενεργοποιημένος για τις Επαφές)."</string>
+ <string name="permlab_readSyncStats">"ανάγνωση στατιστικών συγχρονισμού"</string>
+ <string name="permdesc_readSyncStats">"Επιτρέπει σε μια εφαρμογή την ανάγνωση των στατιστικών συγχρονισμού (π.χ. το ιστορικό των συγχρονισμών που έχουν πραγματοποιηθεί)."</string>
+ <string name="permlab_subscribedFeedsRead">"ανάγνωση ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
+ <string name="permdesc_subscribedFeedsRead">"Επιτρέπει σε μια εφαρμογή τη λήψη λεπτομερειών σχετικά με τις τρέχουσες συγχρονισμένες ροές δεδομένων."</string>
+ <string name="permlab_subscribedFeedsWrite">"εγγραφή ροών δεδομένων στις οποίες έχετε εγγραφεί"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Επιτρέπει σε μια εφαρμογή να τροποποιήσει τις ροές δεδομένων, με τις οποίες είστε συγχρονισμένοι αυτή τη στιγμή. Αυτό θα μπορούσε να δώσει τη δυνατότητα σε μια κακόβουλη εφαρμογή να αλλάξει τις συγχρονισμένες ροές δεδομένων σας."</string>
+ <string name="permlab_readDictionary">"ανάγνωση καθορισμένου από τον χρήστη λεξικού"</string>
+ <string name="permdesc_readDictionary">"Επιτρέπει σε μια εφαρμογή να αναγνώσει ιδιωτικές λέξεις και φράσεις και ιδιωτικά ονόματα, τα οποία ο χρήστης ενδέχεται να έχει αποθηκεύσει στο λεξικό χρήστη."</string>
+ <string name="permlab_writeDictionary">"εγγραφή σε καθορισμένο από τον χρήστη λεξικό"</string>
+ <string name="permdesc_writeDictionary">"Επιτρέπει σε μια εφαρμογή την εγγραφή νέων λέξεων στο λεξικό χρήστη."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Οικία"</item>
- <item msgid="869923650527136615">"Κινητό"</item>
- <item msgid="7897544654242874543">"Εργασία"</item>
- <item msgid="1103601433382158155">"Φαξ εργασίας"</item>
- <item msgid="1735177144948329370">"Φαξ οικίας"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Άλλο"</item>
- <item msgid="9192514806975898961">"Προσαρμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"Κινητό"</item>
+ <item>"Εργασία"</item>
+ <item>"Φαξ εργασίας"</item>
+ <item>"Φαξ οικίας"</item>
+ <item>"Pager"</item>
+ <item>"Άλλο"</item>
+ <item>"Προσαρμοσμένο"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Οικία"</item>
- <item msgid="7084237356602625604">"Εργασία"</item>
- <item msgid="1112044410659011023">"Άλλο"</item>
- <item msgid="2374913952870110618">"Προσαρμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"Εργασία"</item>
+ <item>"Άλλο"</item>
+ <item>"Προσαρμοσμένο"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Κινητό"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Οικία"</item>
- <item msgid="5629153956045109251">"Εργασία"</item>
- <item msgid="4966604264500343469">"Άλλο"</item>
- <item msgid="4932682847595299369">"Προσαρμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"Εργασία"</item>
+ <item>"Άλλο"</item>
+ <item>"Προσαρμοσμένο"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Οικία"</item>
- <item msgid="1359644565647383708">"Εργασία"</item>
- <item msgid="7868549401053615677">"Άλλο"</item>
- <item msgid="3145118944639869809">"Προσαρμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"Εργασία"</item>
+ <item>"Άλλο"</item>
+ <item>"Προσαρμοσμένο"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Εργασία"</item>
- <item msgid="4378074129049520373">"Άλλο"</item>
- <item msgid="3455047468583965104">"Προσαρμοσμένο"</item>
+ <item>"Εργασία"</item>
+ <item>"Άλλο"</item>
+ <item>"Προσαρμοσμένο"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Εσφαλμένος κωδικός αριθμός PIN!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Για ξεκλείδωμα, πατήστε το πλήκτρο Menu και, στη συνέχεια, το πλήκτρο 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Αριθμός έκτακτης ανάγκης"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Καμία υπηρεσία)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Η οθόνη κλειδώθηκε."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Κλήση έκτακτης ανάγκης"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Σωστό!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Προσπαθήστε αργότερα"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Φόρτιση (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Εσφαλμένος κωδικός αριθμός PIN!"</string>
+ <string name="keyguard_label_text">"Για ξεκλείδωμα, πατήστε το πλήκτρο Menu και, στη συνέχεια, το πλήκτρο 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Αριθμός έκτακτης ανάγκης"</string>
+ <string name="lockscreen_carrier_default">"(Καμία υπηρεσία)"</string>
+ <string name="lockscreen_screen_locked">"Η οθόνη κλειδώθηκε."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
+ <string name="lockscreen_pattern_instructions">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
+ <string name="lockscreen_emergency_call">"Κλήση έκτακτης ανάγκης"</string>
+ <string name="lockscreen_pattern_correct">"Σωστό!"</string>
+ <string name="lockscreen_pattern_wrong">"Προσπαθήστε αργότερα"</string>
+ <string name="lockscreen_plugged_in">"Φόρτιση (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Συνδέστε τον φορτιστή."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Δεν υπάρχει κάρτα SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Τοποθετήστε μια κάρτα SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Το δίκτυο κλειδώθηκε"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Η κάρτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Ανατρέξτε στον οδηγό χρήσης ή επικοινωνήστε με την εξυπηρέτηση πελατών."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Η κάρτα SIM είναι κλειδωμένη."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ξεκλείδωμα κάρτας SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση της σύνδεσής σας Google."\n\n" Προσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> \nδευτερόλεπτα."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Προσπαθήστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ξεχάσατε το μοτίβο;"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Πάρα πολλές προσπάθειες μοτίβου!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Για ξεκλείδωμα, συνδεθείτε με τον λογαριασμό σας Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Όνομα χρήστη (διεύθυνση ηλεκτρονικού ταχυδρομείου)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Κωδικός πρόσβασης"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Σύνδεση"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Συνδέστε τον φορτιστή."</string>
+ <string name="lockscreen_missing_sim_message_short">"Δεν υπάρχει κάρτα SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
+ <string name="lockscreen_missing_sim_instructions">"Τοποθετήστε μια κάρτα SIM."</string>
+ <string name="lockscreen_network_locked_message">"Το δίκτυο κλειδώθηκε"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Η κάρτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Ανατρέξτε στον οδηγό χρήσης ή επικοινωνήστε με την εξυπηρέτηση πελατών."</string>
+ <string name="lockscreen_sim_locked_message">"Η κάρτα SIM είναι κλειδωμένη."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Ξεκλείδωμα κάρτας SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση της σύνδεσής σας Google."\n\n" Προσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> \nδευτερόλεπτα."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Προσπαθήστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Ξεχάσατε το μοτίβο;"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Πάρα πολλές προσπάθειες μοτίβου!"</string>
+ <string name="lockscreen_glogin_instructions">"Για ξεκλείδωμα, συνδεθείτε με τον λογαριασμό σας Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Όνομα χρήστη (διεύθυνση ηλεκτρονικού ταχυδρομείου)"</string>
+ <string name="lockscreen_glogin_password_hint">"Κωδικός πρόσβασης"</string>
+ <string name="lockscreen_glogin_submit_button">"Σύνδεση"</string>
+ <string name="lockscreen_glogin_invalid_input">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάρχουν ειδοποιήσεις"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Φόρτιση..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Συνδέστε τον φορτιστή"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"απομένουν λιγότερο από <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="status_bar_no_notifications_title">"Δεν υπάρχουν ειδοποιήσεις"</string>
+ <string name="status_bar_ongoing_events_title">"Εν εξελίξει"</string>
+ <string name="status_bar_latest_events_title">"Ειδοποιήσεις"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Φόρτιση..."</string>
+ <string name="battery_low_title">"Συνδέστε τον φορτιστή"</string>
+ <string name="battery_low_subtitle">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string>
+ <string name="battery_low_percent_format">"απομένουν λιγότερο από <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Η εργοστασιακή δοκιμή απέτυχε"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Η ενέργεια FACTORY_TEST υποστηρίζεται μόνο για πακέτα που είναι εγκατεστημένα στον κατάλογο /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Δεν βρέθηκε πακέτο που να παρέχει την ενέργεια FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Επανεκκίνηση"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Η σελίδα στο \'<xliff:g id="TITLE">%s</xliff:g>\' λέει:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Απομάκρυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Επιλέξτε OK για συνέχεια, ή Ακύρωση για παραμονή στην τρέχουσα σελίδα."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
+ <string name="factorytest_failed">"Η εργοστασιακή δοκιμή απέτυχε"</string>
+ <string name="factorytest_not_system">"Η ενέργεια FACTORY_TEST υποστηρίζεται μόνο για πακέτα που είναι εγκατεστημένα στον κατάλογο /system/app."</string>
+ <string name="factorytest_no_action">"Δεν βρέθηκε πακέτο που να παρέχει την ενέργεια FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Επανεκκίνηση"</string>
+ <string name="js_dialog_title">"Η σελίδα στο \'<xliff:g id="TITLE">%s</xliff:g>\' λέει:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Απομάκρυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Επιλέξτε OK για συνέχεια, ή Ακύρωση για παραμονή στην τρέχουσα σελίδα."</string>
+ <string name="save_password_label">"Επιβεβαίωση"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Ποτέ"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Δεν έχετε άδεια για να ανοίξετε αυτή τη σελίδα."</string>
- <string name="text_copied" msgid="4985729524670131385">"Το κείμενο αντιγράφηκε στο πρόχειρο."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Περισσότερα"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Πλήκτρο Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"διάστημα"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"εισαγωγή"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"διαγραφή"</string>
- <string name="search_go" msgid="8298016669822141719">"Αναζήτηση"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
+ <string name="save_password_message">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
+ <string name="save_password_notnow">"Να μην γίνει τώρα"</string>
+ <string name="save_password_remember">"Διατήρηση"</string>
+ <string name="save_password_never">"Ποτέ"</string>
+ <string name="open_permission_deny">"Δεν έχετε άδεια για να ανοίξετε αυτή τη σελίδα."</string>
+ <string name="text_copied">"Το κείμενο αντιγράφηκε στο πρόχειρο."</string>
+ <string name="more_item_label">"Περισσότερα"</string>
+ <string name="prepend_shortcut_label">"Πλήκτρο Menu+"</string>
+ <string name="menu_space_shortcut_label">"διάστημα"</string>
+ <string name="menu_enter_shortcut_label">"εισαγωγή"</string>
+ <string name="menu_delete_shortcut_label">"διαγραφή"</string>
+ <string name="search_go">"Αναζήτηση"</string>
+ <string name="oneMonthDurationPast">"πριν από 1 μήνα"</string>
+ <string name="beforeOneMonthDurationPast">"Παλαιότερα από 1 μήνα"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"πριν από 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="3903706804349556379">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
+ <item quantity="one">"πριν από 1 δευτερόλεπτο"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"πριν από 1 λεπτό"</item>
- <item quantity="other" msgid="2176942008915455116">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"πριν από 1 λεπτό"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"πριν από 1 ώρα"</item>
- <item quantity="other" msgid="2467273239587587569">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
+ <item quantity="one">"πριν από 1 ώρα"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"χθες"</item>
- <item quantity="other" msgid="2479586466153314633">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
+ <item quantity="one">"χθες"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"σε 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="1241926116443974687">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
+ <item quantity="one">"σε 1 δευτερόλεπτο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="3330713936399448749">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"σε 1 λεπτό"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"σε 1 ώρα"</item>
- <item quantity="other" msgid="547290677353727389">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
+ <item quantity="one">"σε 1 ώρα"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"αύριο"</item>
- <item quantity="other" msgid="5109449375100953247">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
+ <item quantity="one">"αύριο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"πριν από 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="3699169366650930415">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
+ <item quantity="one">"πριν από 1 δευτερόλεπτο"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"πριν από 1 λεπτό"</item>
- <item quantity="other" msgid="851164968597150710">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"πριν από 1 λεπτό"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"πριν από 1 ώρα"</item>
- <item quantity="other" msgid="6889970745748538901">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
+ <item quantity="one">"πριν από 1 ώρα"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"χθες"</item>
- <item quantity="other" msgid="3453342639616481191">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
+ <item quantity="one">"χθες"</item>
+ <item quantity="other">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"σε 1 δευτερόλεπτο"</item>
- <item quantity="other" msgid="5495880108825805108">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
+ <item quantity="one">"σε 1 δευτερόλεπτο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="4216113292706568726">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"σε 1 λεπτό"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"σε 1 ώρα"</item>
- <item quantity="other" msgid="3705373766798013406">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
+ <item quantity="one">"σε 1 ώρα"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"αύριο"</item>
- <item quantity="other" msgid="2973062968038355991">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
+ <item quantity="one">"αύριο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"σε %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"στο %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"σε %s"</string>
- <string name="day" msgid="8144195776058119424">"ημέρα"</string>
- <string name="days" msgid="4774547661021344602">"ημέρες"</string>
- <string name="hour" msgid="2126771916426189481">"ώρα"</string>
- <string name="hours" msgid="894424005266852993">"ώρες"</string>
- <string name="minute" msgid="9148878657703769868">"λεπτά"</string>
- <string name="minutes" msgid="5646001005827034509">"λεπτά"</string>
- <string name="second" msgid="3184235808021478">"δευτερόλεπτο"</string>
- <string name="seconds" msgid="3161515347216589235">"δευτερόλεπτα"</string>
- <string name="week" msgid="5617961537173061583">"εβδομάδα"</string>
- <string name="weeks" msgid="6509623834583944518">"εβδομάδες"</string>
- <string name="year" msgid="4001118221013892076">"έτος"</string>
- <string name="years" msgid="6881577717993213522">"έτη"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Καθημερινές (Δευ-Παρ)"</string>
- <string name="daily" msgid="5738949095624133403">"Καθημερινά"</string>
- <string name="weekly" msgid="983428358394268344">"Κάθε εβδομάδα στο <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Μηνιαία"</string>
- <string name="yearly" msgid="1519577999407493836">"Ετήσια"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Δεν είναι δυνατή η αναπαραγωγή βίντεο"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτή τη συσκευή."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Δεν είναι δυνατή η προβολή αυτού του βίντεο."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"μεσημέρι"</string>
- <string name="Noon" msgid="3342127745230013127">"Μεσημέρι"</string>
- <string name="midnight" msgid="7166259508850457595">"μεσάνυχτα"</string>
- <string name="Midnight" msgid="5630806906897892201">"Μεσάνυχτα"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string>
- <string name="selectText" msgid="3889149123626888637">"Επιλογή κειμένου"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Διακοπή επιλογής κειμένου"</string>
- <string name="cut" msgid="3092569408438626261">"Αποκοπή"</string>
- <string name="cutAll" msgid="2436383270024931639">"Αποκοπή όλων"</string>
- <string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string>
- <string name="copyAll" msgid="2590829068100113057">"Αντιγραφή όλων"</string>
- <string name="paste" msgid="5629880836805036433">"Επικόλληση"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Αντιγραφή διεύθυνσης URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Μέθοδος εισόδου"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Προσθήκη \"%s\" στο λεξικό"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Επεξεργασία κειμένου"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Απομένει λίγος ελεύθερος χώρος"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Έχει απομείνει λίγος ελεύθερος αποθηκευτικός χώρος στο τηλέφωνο."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Ακύρωση"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Προσοχή"</string>
- <string name="capital_on" msgid="1544682755514494298">"Ενεργοποιημένο"</string>
- <string name="capital_off" msgid="6815870386972805832">"Απενεργοποίηση"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Εκκαθάριση προεπιλεγμένων σε Ρυθμίσεις αρχικής σελίδας > Εφαρμογές > Διαχείριση εφαρμογών."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Επιλέξτε μια ενέργεια"</string>
- <string name="noApplications" msgid="1691104391758345586">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
- <string name="aerr_title" msgid="653922989522758100">"Λυπούμαστε!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Υπήρξε μη αναμενόμενη διακοπή της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). Προσπαθήστε ξανά."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Υπήρξε μη αναμενόμενη διακοπή της διαδικασίας <xliff:g id="PROCESS">%1$s</xliff:g>. Προσπαθήστε αργότερα."</string>
- <string name="anr_title" msgid="3100070910664756057">"Λυπούμαστε!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>) δεν αποκρίνεται."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκρίνεται."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκρίνεται."</string>
- <string name="anr_process" msgid="1246866008169975783">"Η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν αποκρίνεται."</string>
- <string name="force_close" msgid="3653416315450806396">"Αναγκαστικό κλείσιμο"</string>
+ <string name="preposition_for_date">"σε %s"</string>
+ <string name="preposition_for_time">"στο %s"</string>
+ <string name="preposition_for_year">"σε %s"</string>
+ <string name="day">"ημέρα"</string>
+ <string name="days">"ημέρες"</string>
+ <string name="hour">"ώρα"</string>
+ <string name="hours">"ώρες"</string>
+ <string name="minute">"λεπτά"</string>
+ <string name="minutes">"λεπτά"</string>
+ <string name="second">"δευτερόλεπτο"</string>
+ <string name="seconds">"δευτερόλεπτα"</string>
+ <string name="week">"εβδομάδα"</string>
+ <string name="weeks">"εβδομάδες"</string>
+ <string name="year">"έτος"</string>
+ <string name="years">"έτη"</string>
+ <string name="every_weekday">"Καθημερινές (Δευ-Παρ)"</string>
+ <string name="daily">"Καθημερινά"</string>
+ <string name="weekly">"Κάθε εβδομάδα στο <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Μηνιαία"</string>
+ <string name="yearly">"Ετήσια"</string>
+ <string name="VideoView_error_title">"Δεν είναι δυνατή η αναπαραγωγή βίντεο"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτή τη συσκευή."</string>
+ <string name="VideoView_error_text_unknown">"Δεν είναι δυνατή η προβολή αυτού του βίντεο."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"μεσημέρι"</string>
+ <string name="Noon">"Μεσημέρι"</string>
+ <string name="midnight">"μεσάνυχτα"</string>
+ <string name="Midnight">"Μεσάνυχτα"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Επιλογή όλων"</string>
+ <string name="selectText">"Επιλογή κειμένου"</string>
+ <string name="stopSelectingText">"Διακοπή επιλογής κειμένου"</string>
+ <string name="cut">"Αποκοπή"</string>
+ <string name="cutAll">"Αποκοπή όλων"</string>
+ <string name="copy">"Αντιγραφή"</string>
+ <string name="copyAll">"Αντιγραφή όλων"</string>
+ <string name="paste">"Επικόλληση"</string>
+ <string name="copyUrl">"Αντιγραφή διεύθυνσης URL"</string>
+ <string name="inputMethod">"Μέθοδος εισόδου"</string>
+ <string name="addToDictionary">"Προσθήκη \"%s\" στο λεξικό"</string>
+ <string name="editTextMenuTitle">"Επεξεργασία κειμένου"</string>
+ <string name="low_internal_storage_view_title">"Απομένει λίγος ελεύθερος χώρος"</string>
+ <string name="low_internal_storage_view_text">"Έχει απομείνει λίγος ελεύθερος αποθηκευτικός χώρος στο τηλέφωνο."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Ακύρωση"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Ακύρωση"</string>
+ <string name="dialog_alert_title">"Προσοχή"</string>
+ <string name="capital_on">"Ενεργοποιημένο"</string>
+ <string name="capital_off">"Απενεργοποίηση"</string>
+ <string name="whichApplication">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
+ <string name="alwaysUse">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
+ <string name="clearDefaultHintMsg">"Εκκαθάριση προεπιλεγμένων σε Ρυθμίσεις αρχικής σελίδας > Εφαρμογές > Διαχείριση εφαρμογών."</string>
+ <string name="chooseActivity">"Επιλέξτε μια ενέργεια"</string>
+ <string name="noApplications">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
+ <string name="aerr_title">"Λυπούμαστε!"</string>
+ <string name="aerr_application">"Υπήρξε μη αναμενόμενη διακοπή της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). Προσπαθήστε ξανά."</string>
+ <string name="aerr_process">"Υπήρξε μη αναμενόμενη διακοπή της διαδικασίας <xliff:g id="PROCESS">%1$s</xliff:g>. Προσπαθήστε αργότερα."</string>
+ <string name="anr_title">"Λυπούμαστε!"</string>
+ <string name="anr_activity_application">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>) δεν αποκρίνεται."</string>
+ <string name="anr_activity_process">"Η δραστηριότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκρίνεται."</string>
+ <string name="anr_application_process">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκρίνεται."</string>
+ <string name="anr_process">"Η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν αποκρίνεται."</string>
+ <string name="force_close">"Αναγκαστικό κλείσιμο"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Αναμονή"</string>
- <string name="debug" msgid="9103374629678531849">"Εντοπισμός σφαλμάτων"</string>
- <string name="sendText" msgid="5132506121645618310">"Επιλέξτε μια ενέργεια για το κείμενο"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ένταση ειδοποίησης ήχου"</string>
- <string name="volume_music" msgid="5421651157138628171">"Ένταση ήχου πολυμέσων"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Αναπαραγωγή μέσω Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Ένταση ήχου κλήσης"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Ένταση ήχου για εισερχόμενη κληση μέσω Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Ένταση ήχου ξυπνητηριού"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Ένταση ήχου ειδοποίησης"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Ένταση ήχου"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Προεπιλεγμένος ήχος κλήσης"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Προεπιλεγμένος ήχος κλήσης (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Σίγαση"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Άγνωστος ήχος κλήσης"</string>
+ <string name="wait">"Αναμονή"</string>
+ <string name="debug">"Εντοπισμός σφαλμάτων"</string>
+ <string name="sendText">"Επιλέξτε μια ενέργεια για το κείμενο"</string>
+ <string name="volume_ringtone">"Ένταση ειδοποίησης ήχου"</string>
+ <string name="volume_music">"Ένταση ήχου πολυμέσων"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Αναπαραγωγή μέσω Bluetooth"</string>
+ <string name="volume_call">"Ένταση ήχου κλήσης"</string>
+ <string name="volume_bluetooth_call">"Ένταση ήχου για εισερχόμενη κληση μέσω Bluetooth"</string>
+ <string name="volume_alarm">"Ένταση ήχου ξυπνητηριού"</string>
+ <string name="volume_notification">"Ένταση ήχου ειδοποίησης"</string>
+ <string name="volume_unknown">"Ένταση ήχου"</string>
+ <string name="ringtone_default">"Προεπιλεγμένος ήχος κλήσης"</string>
+ <string name="ringtone_default_with_actual">"Προεπιλεγμένος ήχος κλήσης (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Σίγαση"</string>
+ <string name="ringtone_picker_title">"Ήχοι κλήσης"</string>
+ <string name="ringtone_unknown">"Άγνωστος ήχος κλήσης"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Υπάρχει διαθέσιμο δίκτυο Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"Υπάρχουν διαθέσιμα δίκτυα Wi-Fi"</item>
+ <item quantity="one">"Υπάρχει διαθέσιμο δίκτυο Wi-Fi"</item>
+ <item quantity="other">"Υπάρχουν διαθέσιμα δίκτυα Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item>
+ <item quantity="one">"Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item>
+ <item quantity="other">"Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Άγνωστη εφαρμογή"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Αποστέλλεται μεγάλος αριθμός μηνυμάτων SMS. Επιλέξτε \"OK\" για συνέχεια, ή \"Ακύρωση\" για διακοπή αποστολής."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Ακύρωση"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ορισμός"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Προεπιλεγμένο"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Απόκρυψη"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Εμφάνιση όλων"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Φόρτωση..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Το USB είναι συνδεδεμένο"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε \"Προσάρτηση\" αν θέλετε να αντιγράψετε αρχεία μεταξύ του υπολογιστή και της κάρτας SD του τηλεφώνου."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Προσάρτηση"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Να μην γίνει προσάρτηση"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Παρουσιάστηκε ένα πρόβλημα στη χρήση της κάρτας SD ως αποθηκευτικό χώρο USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Το USB είναι συνδεδεμένο"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Επιλέξτε για αντιγραφή προς/από τον υπολογιστή σας."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Απενεργοποίηση αποθηκευτικού χώρου USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Επιλογή για απενεργοποίηση αποθηκευτικού χώρου USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Απενεργοποίηση αποθηκευτικού χώρου USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Πριν από την απενεργοποίηση του αποθηκευτικού χώρου USB, βεβαιωθείτε ότι έχετε αποπροσαρτήσει την υποδοχή USB. Επιλέξτε \"Απενεργοποίηση\" για να απενεργοποιήσετε τον αποθηκευτικό χώρο USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Απενεργοποίηση"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Ακύρωση"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Παρουσιάστηκε ένα πρόβλημα κατά την απενεργοποίηση του αποθηκευτικού χώρου USB. Βεβαιωθείτε ότι έχετε αποπροσαρτήσει την υποδοχή USB και προσπαθήστε ξανά."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Διαμόρφωση κάρτας SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Είστε βέβαιοι ότι θέλετε να διαμορφώσετε την κάρτα SD; Όλα τα δεδομένα στην κάρτα σας θα χαθούν."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Διαμόρφωση"</string>
+ <string name="select_character">"Εισαγωγή χαρακτήρα"</string>
+ <string name="sms_control_default_app_name">"Άγνωστη εφαρμογή"</string>
+ <string name="sms_control_title">"Αποστολή μηνυμάτων SMS"</string>
+ <string name="sms_control_message">"Αποστέλλεται μεγάλος αριθμός μηνυμάτων SMS. Επιλέξτε \"OK\" για συνέχεια, ή \"Ακύρωση\" για διακοπή αποστολής."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Ακύρωση"</string>
+ <string name="date_time_set">"Ορισμός"</string>
+ <string name="default_permission_group">"Προεπιλεγμένο"</string>
+ <string name="no_permissions">"Δεν απαιτούνται άδειες"</string>
+ <string name="perms_hide"><b>"Απόκρυψη"</b></string>
+ <string name="perms_show_all"><b>"Εμφάνιση όλων"</b></string>
+ <string name="googlewebcontenthelper_loading">"Φόρτωση..."</string>
+ <string name="usb_storage_title">"Το USB είναι συνδεδεμένο"</string>
+ <string name="usb_storage_message">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε \"Προσάρτηση\" αν θέλετε να αντιγράψετε αρχεία μεταξύ του υπολογιστή και της κάρτας SD του τηλεφώνου."</string>
+ <string name="usb_storage_button_mount">"Προσάρτηση"</string>
+ <string name="usb_storage_button_unmount">"Να μην γίνει προσάρτηση"</string>
+ <string name="usb_storage_error_message">"Παρουσιάστηκε ένα πρόβλημα στη χρήση της κάρτας SD ως αποθηκευτικό χώρο USB."</string>
+ <string name="usb_storage_notification_title">"Το USB είναι συνδεδεμένο"</string>
+ <string name="usb_storage_notification_message">"Επιλέξτε για αντιγραφή προς/από τον υπολογιστή σας."</string>
+ <string name="usb_storage_stop_notification_title">"Απενεργοποίηση αποθηκευτικού χώρου USB"</string>
+ <string name="usb_storage_stop_notification_message">"Επιλογή για απενεργοποίηση αποθηκευτικού χώρου USB."</string>
+ <string name="usb_storage_stop_title">"Απενεργοποίηση αποθηκευτικού χώρου USB"</string>
+ <string name="usb_storage_stop_message">"Πριν από την απενεργοποίηση του αποθηκευτικού χώρου USB, βεβαιωθείτε ότι έχετε αποπροσαρτήσει την υποδοχή USB. Επιλέξτε \"Απενεργοποίηση\" για να απενεργοποιήσετε τον αποθηκευτικό χώρο USB."</string>
+ <string name="usb_storage_stop_button_mount">"Απενεργοποίηση"</string>
+ <string name="usb_storage_stop_button_unmount">"Ακύρωση"</string>
+ <string name="usb_storage_stop_error_message">"Παρουσιάστηκε ένα πρόβλημα κατά την απενεργοποίηση του αποθηκευτικού χώρου USB. Βεβαιωθείτε ότι έχετε αποπροσαρτήσει την υποδοχή USB και προσπαθήστε ξανά."</string>
+ <string name="extmedia_format_title">"Διαμόρφωση κάρτας SD"</string>
+ <string name="extmedia_format_message">"Είστε βέβαιοι ότι θέλετε να διαμορφώσετε την κάρτα SD; Όλα τα δεδομένα στην κάρτα σας θα χαθούν."</string>
+ <string name="extmedia_format_button_format">"Διαμόρφωση"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Επιλογή μεθόδου εισόδου"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Προετοιμασία κάρτας SD"</string>
+ <string name="select_input_method">"Επιλογή μεθόδου εισόδου"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"υποψήφιοι"</u></string>
+ <string name="ext_media_checking_notification_title">"Προετοιμασία κάρτας SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Κενή κάρτα SD"</string>
+ <string name="ext_media_nofs_notification_title">"Κενή κάρτα SD"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Κατεστραμμένη κάρτα SD"</string>
+ <string name="ext_media_unmountable_notification_title">"Κατεστραμμένη κάρτα SD"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Μη αναμενόμενη αφαίρεση κάρτας SD"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Αποπροσαρτήστε την κάρτα SD πριν την αφαιρέσετε για την αποφυγή απώλειας δεδομένων."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Η κάρτα SD μπορεί να αφαιρεθεί με ασφάλεια"</string>
+ <string name="ext_media_badremoval_notification_title">"Μη αναμενόμενη αφαίρεση κάρτας SD"</string>
+ <string name="ext_media_badremoval_notification_message">"Αποπροσαρτήστε την κάρτα SD πριν την αφαιρέσετε για την αποφυγή απώλειας δεδομένων."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Η κάρτα SD μπορεί να αφαιρεθεί με ασφάλεια"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Η κάρτα SD αφαιρέθηκε"</string>
+ <string name="ext_media_nomedia_notification_title">"Η κάρτα SD αφαιρέθηκε"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Δεν βρέθηκαν δραστηριότητες που να αντιστοιχούν"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"ενημέρωση στατιστικών χρήσης στοιχείου"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Επιτρέπει την τροποποίηση στατιστικών χρήσης στοιχείων που έχουν συλλεχθεί. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Σφάλμα αύξησης μεγέθους γραφικού στοιχείου"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Μετάβαση"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Αναζήτηση"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Αποστολή"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Επόμενο"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Τέλος"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Εκτέλεση"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Κλήση αριθμού"\n"με τη χρήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Δημιουργία επαφής"\n"με τη χρήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Δεν βρέθηκαν δραστηριότητες που να αντιστοιχούν"</string>
+ <string name="permlab_pkgUsageStats">"ενημέρωση στατιστικών χρήσης στοιχείου"</string>
+ <string name="permdesc_pkgUsageStats">"Επιτρέπει την τροποποίηση στατιστικών χρήσης στοιχείων που έχουν συλλεχθεί. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Πατήστε δύο φορές για έλεγχο εστίασης"</string>
+ <string name="gadget_host_error_inflating">"Σφάλμα αύξησης μεγέθους γραφικού στοιχείου"</string>
+ <string name="ime_action_go">"Μετάβαση"</string>
+ <string name="ime_action_search">"Αναζήτηση"</string>
+ <string name="ime_action_send">"Αποστολή"</string>
+ <string name="ime_action_next">"Επόμενο"</string>
+ <string name="ime_action_done">"Ολοκληρώθηκε"</string>
+ <string name="ime_action_default">"Εκτέλεση"</string>
+ <string name="dial_number_using">"Κλήση αριθμού"\n"με τη χρήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Δημιουργία επαφής"\n"με τη χρήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
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-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f34adcb..ee28403 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<sin título>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(No hay número de teléfono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconocida)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de conexión o código incorrecto de MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Se ha activado el servicio."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Se activó el servicio para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Se ha desactivado el servicio."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"El registro se ha realizado correctamente."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Se ha borrado correctamente."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Contraseña incorrecta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completa."</string>
- <string name="badPin" msgid="5085454289896032547">"El PIN anterior que escribiste no es correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"La PUK que escribiste no es correcta."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Los PIN que has ingresado no coinciden."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Escribir un PIN que contenga entre 4 y 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"Tu tarjeta SIM está bloqueada con PUK. Escribe el código PUK para desbloquearla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Identificador de llamadas entrantes"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Identificador de llamadas salientes"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desvío de llamadas"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Llamada en espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Restricción de llamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Cambio de contraseña"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Cambio de PIN"</string>
+ <string name="untitled">"<sin título>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(No hay número de teléfono)"</string>
+ <string name="unknownName">"(Desconocida)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correo de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de conexión o código incorrecto de MMI."</string>
+ <string name="serviceEnabled">"Se ha activado el servicio."</string>
+ <string name="serviceEnabledFor">"Se activó el servicio para:"</string>
+ <string name="serviceDisabled">"Se ha desactivado el servicio."</string>
+ <string name="serviceRegistered">"El registro se ha realizado correctamente."</string>
+ <string name="serviceErased">"Se ha borrado correctamente."</string>
+ <string name="passwordIncorrect">"Contraseña incorrecta."</string>
+ <string name="mmiComplete">"MMI completa."</string>
+ <string name="badPin">"El PIN anterior que escribiste no es correcto."</string>
+ <string name="badPuk">"La PUK que escribiste no es correcta."</string>
+ <string name="mismatchPin">"Los PIN que has ingresado no coinciden."</string>
+ <string name="invalidPin">"Escribir un PIN que contenga entre 4 y 8 números."</string>
+ <string name="needPuk">"Tu tarjeta SIM está bloqueada con PUK. Escribe el código PUK para desbloquearla."</string>
+ <string name="needPuk2">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
+ <string name="ClipMmi">"Identificador de llamadas entrantes"</string>
+ <string name="ClirMmi">"Identificador de llamadas salientes"</string>
+ <string name="CfMmi">"Desvío de llamadas"</string>
+ <string name="CwMmi">"Llamada en espera"</string>
+ <string name="BaMmi">"Restricción de llamadas"</string>
+ <string name="PwdMmi">"Cambio de contraseña"</string>
+ <string name="PinMmi">"Cambio de PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"El identificador de llamadas está predeterminado en restringido. Llamada siguiente: restringida"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"El Identificador de llamadas está predeterminado en restringido. Llamada siguiente: no restringido"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"El identificador de llamadas está predeterminado en no restringido. Llamada siguiente: restringida"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servicio no suministrado."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"La configuración del identificador de llamadas no se puede cambiar."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Se ha cambiado el acceso restringido"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencias está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"El servicio de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos los servicios de voz/SMS están bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Datos"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Datos asíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"El identificador de llamadas está predeterminado en restringido. Llamada siguiente: restringida"</string>
+ <string name="CLIRDefaultOnNextCallOff">"El Identificador de llamadas está predeterminado en restringido. Llamada siguiente: no restringido"</string>
+ <string name="CLIRDefaultOffNextCallOn">"El identificador de llamadas está predeterminado en no restringido. Llamada siguiente: restringida"</string>
+ <string name="CLIRDefaultOffNextCallOff">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
+ <string name="serviceNotProvisioned">"Servicio no suministrado."</string>
+ <string name="CLIRPermanent">"La configuración del identificador de llamadas no se puede cambiar."</string>
+ <string name="RestrictedChangedTitle">"Se ha cambiado el acceso restringido"</string>
+ <string name="RestrictedOnData">"El servicio de datos está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"El servicio de emergencias está bloqueado."</string>
+ <string name="RestrictedOnNormal">"El servicio de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos los servicios de voz/SMS están bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Datos"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Datos asíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronización"</string>
+ <string name="serviceClassPacket">"Paquete"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
- <string name="httpError" msgid="2567300624552921790">"La página web contiene un error."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"No se ha podido encontrar la URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"No se admite el programa de autenticación del sitio."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"La autenticación no se ha realizado correctamente."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"La autenticación a través del servidor proxy no se ha realizado correctamente."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"La conexión al servidor no se ha realizado correctamente."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"El servidor no envía comunicaciones. Vuelve a intentarlo más tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Se ha agotado el tiempo de espera para la conexión al servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La página contiene demasiados redireccionamientos de servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"No se admite el protocolo."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"No se ha podido establecer una conexión segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"No se ha podido abrir la página debido a que la URL es incorrecta."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"No se ha podido acceder al archivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"No se ha encontrado el archivo solicitado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
- <string name="low_memory" msgid="6632412458436461203">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
- <string name="me" msgid="6545696007631404292">"Yo"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opciones de teléfono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Encender el teléfono inalámbrico"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Apagar el teléfono inalámbrico"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
- <string name="power_off" msgid="4266614107412865048">"Apagar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Tu teléfono se apagará."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"No hay aplicaciones recientes."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opciones de teléfono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Apagado"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Encendido"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Encendido"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Apagado"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Androide"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Admite aplicaciones que realizan actividades que te pueden costar dinero."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lee y escribe tu SMS, mensaje de correo electrónico y otros mensajes."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Controla tu ubicación física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Admite aplicaciones que acceden a varias funciones de red."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Tus cuentas de Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acceder a las cuentas disponibles de Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el teléfono."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas telefónicas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, grabar y procesar llamadas telefónicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acceso y control de nivel más bajo del sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Herramientas de desarrollo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Las funciones sólo son necesarias para los desarrolladores de aplicaciones."</string>
+ <string name="httpErrorOk">"Aceptar"</string>
+ <string name="httpError">"La página web contiene un error."</string>
+ <string name="httpErrorLookup">"No se ha podido encontrar la URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"No se admite el programa de autenticación del sitio."</string>
+ <string name="httpErrorAuth">"La autenticación no se ha realizado correctamente."</string>
+ <string name="httpErrorProxyAuth">"La autenticación a través del servidor proxy no se ha realizado correctamente."</string>
+ <string name="httpErrorConnect">"La conexión al servidor no se ha realizado correctamente."</string>
+ <string name="httpErrorIO">"El servidor no envía comunicaciones. Vuelve a intentarlo más tarde."</string>
+ <string name="httpErrorTimeout">"Se ha agotado el tiempo de espera para la conexión al servidor."</string>
+ <string name="httpErrorRedirectLoop">"La página contiene demasiados redireccionamientos de servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"No se admite el protocolo."</string>
+ <string name="httpErrorFailedSslHandshake">"No se ha podido establecer una conexión segura."</string>
+ <string name="httpErrorBadUrl">"No se ha podido abrir la página debido a que la URL es incorrecta."</string>
+ <string name="httpErrorFile">"No se ha podido acceder al archivo."</string>
+ <string name="httpErrorFileNotFound">"No se ha encontrado el archivo solicitado."</string>
+ <string name="httpErrorTooManyRequests">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
+ <string name="contentServiceSync">"Sincronización"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronización"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
+ <string name="low_memory">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
+ <string name="me">"Yo"</string>
+ <string name="power_dialog">"Opciones de teléfono"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Encender el teléfono inalámbrico"</string>
+ <string name="turn_off_radio">"Apagar el teléfono inalámbrico"</string>
+ <string name="screen_lock">"Bloqueo de pantalla"</string>
+ <string name="power_off">"Apagar"</string>
+ <string name="shutdown_progress">"Apagando…"</string>
+ <string name="shutdown_confirm">"Tu teléfono se apagará."</string>
+ <string name="no_recent_tasks">"No hay aplicaciones recientes."</string>
+ <string name="global_actions">"Opciones de teléfono"</string>
+ <string name="global_action_lock">"Bloqueo de pantalla"</string>
+ <string name="global_action_power_off">"Apagar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"El sonido está Apagado"</string>
+ <string name="global_action_silent_mode_off_status">"El sonido está Encendido"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo avión"</string>
+ <string name="global_actions_airplane_mode_on_status">"El modo avión está Encendido"</string>
+ <string name="global_actions_airplane_mode_off_status">"El modo avión está Apagado"</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Androide"</string>
+ <string name="permgrouplab_costMoney">"Servicios que te cuestan dinero"</string>
+ <string name="permgroupdesc_costMoney">"Admite aplicaciones que realizan actividades que te pueden costar dinero."</string>
+ <string name="permgrouplab_messages">"Tus mensajes"</string>
+ <string name="permgroupdesc_messages">"Lee y escribe tu SMS, mensaje de correo electrónico y otros mensajes."</string>
+ <string name="permgrouplab_personalInfo">"Tu información personal"</string>
+ <string name="permgroupdesc_personalInfo">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
+ <string name="permgrouplab_location">"Tu ubicación"</string>
+ <string name="permgroupdesc_location">"Controla tu ubicación física"</string>
+ <string name="permgrouplab_network">"Comunicación de red"</string>
+ <string name="permgroupdesc_network">"Admite aplicaciones que acceden a varias funciones de red."</string>
+ <string name="permgrouplab_accounts">"Tus cuentas de Google"</string>
+ <string name="permgroupdesc_accounts">"Acceder a las cuentas disponibles de Google."</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acceso directo al hardware en el teléfono."</string>
+ <string name="permgrouplab_phoneCalls">"Llamadas telefónicas"</string>
+ <string name="permgroupdesc_phoneCalls">"Controlar, grabar y procesar llamadas telefónicas."</string>
+ <string name="permgrouplab_systemTools">"Herramientas del sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acceso y control de nivel más bajo del sistema."</string>
+ <string name="permgrouplab_developmentTools">"Herramientas de desarrollo"</string>
+ <string name="permgroupdesc_developmentTools">"Las funciones sólo son necesarias para los desarrolladores de aplicaciones."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Admite que la aplicación desactive la barra de estado, o agregue y elimine íconos del sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir o reducir la barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Admite que la aplicación expanda o reduzca la barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Admite que la aplicación procese las llamadas salientes y cambie el número que se debe marcar. Las aplicaciones maliciosas pueden controlar, redireccionar o prevenir llamadas salientes."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"recibir SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Admite que la aplicación reciba y procese mensajes SMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"recibir MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Admite que la aplicación reciba y procese mensajes MMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensajes SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Admite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas te pueden costar dinero si envías mensajes sin su confirmación."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Admite que la aplicación reciba y procese mensajes WAP. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicaciones en ejecución"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Admite que la aplicación recupere información sobre tareas en ejecución actuales y recientes. Puede permitir que las aplicaciones maliciosas descubran información privada sobre otras aplicaciones."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Admite una aplicación que mueve tareas hacia el frente y el fondo. Las aplicaciones maliciosas pueden provocar su propio movimiento hacia el frente sin tu control."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"activar la depuración de la aplicación"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Admite una aplicación que activa la depuración en otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir otras aplicaciones."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Admite una aplicación para cambiar la configuración actual, como el tamaño de fuente local o general."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar otras aplicaciones"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Admite una aplicación que reinicia otras aplicaciones por la fuerza."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"provocar que la aplicación se acerque"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Admite una aplicación que provoca que cualquier actividad del fondo se acerque y vuelva a alejarse. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar el estado interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Admite que la aplicación recupere el estado interno del sistema. Las aplicaciones maliciosas pueden recuperar una gran variedad de información privada y segura que normalmente nunca necesitaría."</string>
+ <string name="permlab_statusBar">"desactivar o modificar la barra de estado"</string>
+ <string name="permdesc_statusBar">"Admite que la aplicación desactive la barra de estado, o agregue y elimine íconos del sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir o reducir la barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Admite que la aplicación expanda o reduzca la barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar llamadas salientes"</string>
+ <string name="permdesc_processOutgoingCalls">"Admite que la aplicación procese las llamadas salientes y cambie el número que se debe marcar. Las aplicaciones maliciosas pueden controlar, redireccionar o prevenir llamadas salientes."</string>
+ <string name="permlab_receiveSms">"recibir SMS"</string>
+ <string name="permdesc_receiveSms">"Admite que la aplicación reciba y procese mensajes SMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_receiveMms">"recibir MMS"</string>
+ <string name="permdesc_receiveMms">"Admite que la aplicación reciba y procese mensajes MMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_sendSms">"enviar mensajes SMS"</string>
+ <string name="permdesc_sendSms">"Admite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas te pueden costar dinero si envías mensajes sin su confirmación."</string>
+ <string name="permlab_readSms">"leer SMS o MMS"</string>
+ <string name="permdesc_readSms">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+ <string name="permlab_writeSms">"editar SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
+ <string name="permlab_receiveWapPush">"recibir WAP"</string>
+ <string name="permdesc_receiveWapPush">"Admite que la aplicación reciba y procese mensajes WAP. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_getTasks">"recuperar aplicaciones en ejecución"</string>
+ <string name="permdesc_getTasks">"Admite que la aplicación recupere información sobre tareas en ejecución actuales y recientes. Puede permitir que las aplicaciones maliciosas descubran información privada sobre otras aplicaciones."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicaciones en ejecución"</string>
+ <string name="permdesc_reorderTasks">"Admite una aplicación que mueve tareas hacia el frente y el fondo. Las aplicaciones maliciosas pueden provocar su propio movimiento hacia el frente sin tu control."</string>
+ <string name="permlab_setDebugApp">"activar la depuración de la aplicación"</string>
+ <string name="permdesc_setDebugApp">"Admite una aplicación que activa la depuración en otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir otras aplicaciones."</string>
+ <string name="permlab_changeConfiguration">"cambiar tu configuración de la interfaz de usuario"</string>
+ <string name="permdesc_changeConfiguration">"Admite una aplicación para cambiar la configuración actual, como el tamaño de fuente local o general."</string>
+ <string name="permlab_restartPackages">"reiniciar otras aplicaciones"</string>
+ <string name="permdesc_restartPackages">"Admite una aplicación que reinicia otras aplicaciones por la fuerza."</string>
+ <string name="permlab_forceBack">"provocar que la aplicación se acerque"</string>
+ <string name="permdesc_forceBack">"Admite una aplicación que provoca que cualquier actividad del fondo se acerque y vuelva a alejarse. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_dump">"recuperar el estado interno del sistema"</string>
+ <string name="permdesc_dump">"Admite que la aplicación recupere el estado interno del sistema. Las aplicaciones maliciosas pueden recuperar una gran variedad de información privada y segura que normalmente nunca necesitaría."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"verificar y controlar todos los lanzamientos de actividades"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Admite una aplicación que verifica y controla el lanzamiento de actividades por parte del sistema. Las aplicaciones maliciosas pueden comprometer totalmente al sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del teléfono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión de paquete eliminado"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Admite una aplicación que emite una notificación acerca de que se ha eliminado un paquete de aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir cualquier otra aplicación en ejecución."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar emisiones de SMS recibidos"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Admite una aplicación que envía una notificación acerca de que se ha recibido un mensaje SMS. Las aplicaciones maliciosas pueden utilizarlo para falsificar los mensajes SMS entrantes."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisiones WAP-PUSH-recibido"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Admite una aplicación que emite una notificación acerca de que se ha recibido un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizarlo para falsificar la recepción de mensajes MMS o para reemplazar silenciosamente el contenido de cualquier página web con variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar la cantidad de procesos en ejecución"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Admite una aplicación que controla la cantidad máxima de procesos que se ejecutarán. No se utiliza nunca en aplicaciones normales."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"cerrar todas las aplicaciones del fondo"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Admite una aplicación que controla si las actividades siempre finalizan cuando van al fondo. No se utiliza nunca en aplicaciones normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar la estadística de la batería"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Admite la modificación de estadísticas recopiladas sobre la batería. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_runSetActivityWatcher">"verificar y controlar todos los lanzamientos de actividades"</string>
+ <string name="permdesc_runSetActivityWatcher">"Admite una aplicación que verifica y controla el lanzamiento de actividades por parte del sistema. Las aplicaciones maliciosas pueden comprometer totalmente al sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del teléfono."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar emisión de paquete eliminado"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Admite una aplicación que emite una notificación acerca de que se ha eliminado un paquete de aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir cualquier otra aplicación en ejecución."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar emisiones de SMS recibidos"</string>
+ <string name="permdesc_broadcastSmsReceived">"Admite una aplicación que envía una notificación acerca de que se ha recibido un mensaje SMS. Las aplicaciones maliciosas pueden utilizarlo para falsificar los mensajes SMS entrantes."</string>
+ <string name="permlab_broadcastWapPush">"enviar emisiones WAP-PUSH-recibido"</string>
+ <string name="permdesc_broadcastWapPush">"Admite una aplicación que emite una notificación acerca de que se ha recibido un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizarlo para falsificar la recepción de mensajes MMS o para reemplazar silenciosamente el contenido de cualquier página web con variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"limitar la cantidad de procesos en ejecución"</string>
+ <string name="permdesc_setProcessLimit">"Admite una aplicación que controla la cantidad máxima de procesos que se ejecutarán. No se utiliza nunca en aplicaciones normales."</string>
+ <string name="permlab_setAlwaysFinish">"cerrar todas las aplicaciones del fondo"</string>
+ <string name="permdesc_setAlwaysFinish">"Admite una aplicación que controla si las actividades siempre finalizan cuando van al fondo. No se utiliza nunca en aplicaciones normales."</string>
+ <string name="permlab_batteryStats">"modificar la estadística de la batería"</string>
+ <string name="permdesc_batteryStats">"Admite la modificación de estadísticas recopiladas sobre la batería. Las aplicaciones normales no deben utilizarlo."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas que la interfaz interna del usuario del sistema pretenda utilizar. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas a nivel del sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Admite una aplicación que muestra ventanas de alerta del sistema. Las aplicaciones maliciosas pueden tomar el control de toda la pantalla del teléfono."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar la velocidad de la animación global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Admite una aplicación que cambia la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrar tokens de aplicación"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Admite que las aplicaciones creen y administren sus propios tokens y desvíen su curva normal de llenado del espacio. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"presionar teclas y botones de control"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"grabar tu tipo y las medidas que tomes"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Admite que las aplicaciones observen las teclas que presionas, incluso al interactuar con otra aplicación (como el ingreso de una contraseña). Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales de Linux a las aplicaciones"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que siempre se ejecute la aplicación"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Admite una aplicación que hace continuas sus propias partes, de modo que el sistema no puede utilizarla para otras aplicaciones."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicaciones"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Admite una aplicación que borra paquetes Android. Las aplicaciones maliciosas pueden utilizarlo para eliminar aplicaciones importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar los datos de otras aplicaciones"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Admite una aplicación que borra los datos del usuario."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar las memorias caché de otras aplicaciones"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Admite una aplicación que borra archivos de memoria caché."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir el espacio de almacenamiento de la aplicación"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Admite una aplicación que recupera su código, datos y tamaños de memoria caché"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de memoria caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Admite una aplicación que cambia si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"establecer aplicaciones preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Admite una aplicación que modifica tus aplicaciones preferidas. Puede admitir aplicaciones maliciosas que cambien silenciosamente las aplicaciones que se ejecutan e imiten tus aplicaciones existentes para recopilar tus datos privados."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Admite una aplicación que modifica los datos de configuración del sistema. Las aplicaciones maliciosas pueden corromper la configuración de tu sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuración segura del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Admite una aplicación que modifica los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de servicios de Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automáticamente durante la inicialización"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escribir datos del propietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Admite una aplicación que modifica los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos del propietario."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"leer datos del propietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Admite una aplicación que lee los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para leer los datos del propietario del teléfono."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"leer datos de calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escribir datos de calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Admite una aplicación que modifica los eventos de calendario guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos de calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"crear fuentes de ubicación de prueba"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crea fuentes de ubicación de prueba. Las aplicaciones maliciosas pueden utilizarlo para invalidar la ubicación o el estado que arrojen las fuentes de ubicación real, como GPS o proveedores de red."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionales del proveedor del lugar"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Accede a comandos adicionales del proveedor del lugar. Las aplicaciones maliciosas pueden utilizarlo para interferir en la operación del GPS u otras fuentes de ubicación."</string>
+ <string name="permlab_internalSystemWindow">"mostrar ventanas no autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas que la interfaz interna del usuario del sistema pretenda utilizar. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_systemAlertWindow">"mostrar alertas a nivel del sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Admite una aplicación que muestra ventanas de alerta del sistema. Las aplicaciones maliciosas pueden tomar el control de toda la pantalla del teléfono."</string>
+ <string name="permlab_setAnimationScale">"modificar la velocidad de la animación global"</string>
+ <string name="permdesc_setAnimationScale">"Admite una aplicación que cambia la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
+ <string name="permlab_manageAppTokens">"administrar tokens de aplicación"</string>
+ <string name="permdesc_manageAppTokens">"Admite que las aplicaciones creen y administren sus propios tokens y desvíen su curva normal de llenado del espacio. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_injectEvents">"presionar teclas y botones de control"</string>
+ <string name="permdesc_injectEvents">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
+ <string name="permlab_readInputState">"grabar tu tipo y las medidas que tomes"</string>
+ <string name="permdesc_readInputState">"Admite que las aplicaciones observen las teclas que presionas, incluso al interactuar con otra aplicación (como el ingreso de una contraseña). Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_bindInputMethod">"vincular a un método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_setOrientation">"cambiar la orientación de la pantalla"</string>
+ <string name="permdesc_setOrientation">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar señales de Linux a las aplicaciones"</string>
+ <string name="permdesc_signalPersistentProcesses">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string>
+ <string name="permlab_persistentActivity">"hacer que siempre se ejecute la aplicación"</string>
+ <string name="permdesc_persistentActivity">"Admite una aplicación que hace continuas sus propias partes, de modo que el sistema no puede utilizarla para otras aplicaciones."</string>
+ <string name="permlab_deletePackages">"eliminar aplicaciones"</string>
+ <string name="permdesc_deletePackages">"Admite una aplicación que borra paquetes Android. Las aplicaciones maliciosas pueden utilizarlo para eliminar aplicaciones importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar los datos de otras aplicaciones"</string>
+ <string name="permdesc_clearAppUserData">"Admite una aplicación que borra los datos del usuario."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar las memorias caché de otras aplicaciones"</string>
+ <string name="permdesc_deleteCacheFiles">"Admite una aplicación que borra archivos de memoria caché."</string>
+ <string name="permlab_getPackageSize">"medir el espacio de almacenamiento de la aplicación"</string>
+ <string name="permdesc_getPackageSize">"Admite una aplicación que recupera su código, datos y tamaños de memoria caché"</string>
+ <string name="permlab_installPackages">"instalar aplicaciones directamente"</string>
+ <string name="permdesc_installPackages">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos los datos de memoria caché de la aplicación"</string>
+ <string name="permdesc_clearAppCache">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+ <string name="permlab_readLogs">"leer archivos de registro del sistema"</string>
+ <string name="permdesc_readLogs">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string>
+ <string name="permlab_diagnostic">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
+ <string name="permdesc_diagnostic">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
+ <string name="permlab_changeComponentState">"activar o desactivar componentes de la aplicación"</string>
+ <string name="permdesc_changeComponentState">"Admite una aplicación que cambia si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
+ <string name="permlab_setPreferredApplications">"establecer aplicaciones preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Admite una aplicación que modifica tus aplicaciones preferidas. Puede admitir aplicaciones maliciosas que cambien silenciosamente las aplicaciones que se ejecutan e imiten tus aplicaciones existentes para recopilar tus datos privados."</string>
+ <string name="permlab_writeSettings">"modificar la configuración global del sistema"</string>
+ <string name="permdesc_writeSettings">"Admite una aplicación que modifica los datos de configuración del sistema. Las aplicaciones maliciosas pueden corromper la configuración de tu sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar la configuración segura del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Admite una aplicación que modifica los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_writeGservices">"modificar el mapa de servicios de Google"</string>
+ <string name="permdesc_writeGservices">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automáticamente durante la inicialización"</string>
+ <string name="permdesc_receiveBootCompleted">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
+ <string name="permlab_broadcastSticky">"enviar emisiones pegajosas"</string>
+ <string name="permdesc_broadcastSticky">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
+ <string name="permlab_readContacts">"leer datos de contacto"</string>
+ <string name="permdesc_readContacts">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeContacts">"escribir datos de contacto"</string>
+ <string name="permdesc_writeContacts">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
+ <string name="permlab_writeOwnerData">"escribir datos del propietario"</string>
+ <string name="permdesc_writeOwnerData">"Admite una aplicación que modifica los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos del propietario."</string>
+ <string name="permlab_readOwnerData">"leer datos del propietario"</string>
+ <string name="permdesc_readOwnerData">"Admite una aplicación que lee los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para leer los datos del propietario del teléfono."</string>
+ <string name="permlab_readCalendar">"leer datos de calendario"</string>
+ <string name="permdesc_readCalendar">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeCalendar">"escribir datos de calendario"</string>
+ <string name="permdesc_writeCalendar">"Admite una aplicación que modifica los eventos de calendario guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos de calendario."</string>
+ <string name="permlab_accessMockLocation">"crear fuentes de ubicación de prueba"</string>
+ <string name="permdesc_accessMockLocation">"Crea fuentes de ubicación de prueba. Las aplicaciones maliciosas pueden utilizarlo para invalidar la ubicación o el estado que arrojen las fuentes de ubicación real, como GPS o proveedores de red."</string>
+ <string name="permlab_accessLocationExtraCommands">"acceder a comandos adicionales del proveedor del lugar"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Accede a comandos adicionales del proveedor del lugar. Las aplicaciones maliciosas pueden utilizarlo para interferir en la operación del GPS u otras fuentes de ubicación."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ubicación precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación aproximada (basada en la red)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Admite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Admite que la aplicación que se utilizará lea el contenido del búfer de marco."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar tu configuración de audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Admite que la aplicación modifique la configuración global de audio, como el volumen y el enrutamiento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Admite que la aplicación acceda a la ruta de grabación de audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tomar fotografías"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Admite una aplicación que toma fotografías con la cámara. Esto permite que la aplicación en cualquier momento recopile imágenes que esté viendo la cámara."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desactivar teléfono de manera permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"provocar el reinicio del teléfono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Admite que la aplicación formatee el espacio de almacenamiento extraíble."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"vibrador de control"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Admite que la aplicación controle el vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Admite que la aplicación controle la linterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"probar el hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Admite que la aplicación controle diversos periféricos con el fin de probar el hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Admite que la aplicación llame a ciertos números de teléfono sin tu permiso. Las aplicaciones maliciosas pueden ocasionar llamadas imprevistas en tu factura telefónica. Ten en cuenta que esto no admite que la aplicación llame a los números de emergencia."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a las propiedades de protección"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Admite el acceso de lectura y escritura a las propiedades subidas por el servicio de protección. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"elegir controles"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del teléfono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Admite que la aplicación controle las funciones telefónicas del dispositivo. Una aplicación con este permiso puede cambiar las redes, encender y apagar la radio del teléfono y funciones similares sin notificarte en ningún momento."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"evitar que el teléfono entre en estado de inactividad"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"apagar o encender el teléfono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Admite que la aplicación encienda o apague el teléfono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en el modo de prueba de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer papel tapiz"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Admite que la aplicación establezca el papel tapiz del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer sugerencias de tamaño del papel tapiz"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Admite que la aplicación establezca las sugerencias de tamaño del papel tapiz del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"restablecer el sistema a las configuraciones predeterminadas de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Admite una aplicación que restablece el sistema completamente con su configuración de fábrica, y borra todos los datos, las configuraciones y las aplicaciones instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descubrir cuentas conocidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado de la red"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Admite una aplicación que ve el estado de todas las redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acceso total a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Admite una aplicación que crea conectores de red."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escribir configuración del Nombre del punto de acceso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Admite una aplicación que modifica la configuración de APN, como el proxy y el puerto de cualquier APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de la red"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Admite una aplicación que cambia la conectividad de red del estado."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar la configuración del uso de datos del fondo"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver el estado de Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Admite una aplicación que observa la información sobre el estado de Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"cambiar el estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Admite una aplicación que se conecta y desconecta de los puntos de acceso de Wi-Fi y que hace cambios en las redes de Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"ubicación precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
+ <string name="permlab_accessCoarseLocation">"ubicación aproximada (basada en la red)"</string>
+ <string name="permdesc_accessCoarseLocation">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
+ <string name="permlab_accessSurfaceFlinger">"acceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Admite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"leer el búfer de tramas"</string>
+ <string name="permdesc_readFrameBuffer">"Admite que la aplicación que se utilizará lea el contenido del búfer de marco."</string>
+ <string name="permlab_modifyAudioSettings">"cambiar tu configuración de audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Admite que la aplicación modifique la configuración global de audio, como el volumen y el enrutamiento."</string>
+ <string name="permlab_recordAudio">"grabar audio"</string>
+ <string name="permdesc_recordAudio">"Admite que la aplicación acceda a la ruta de grabación de audio."</string>
+ <string name="permlab_camera">"tomar fotografías"</string>
+ <string name="permdesc_camera">"Admite una aplicación que toma fotografías con la cámara. Esto permite que la aplicación en cualquier momento recopile imágenes que esté viendo la cámara."</string>
+ <string name="permlab_brick">"desactivar teléfono de manera permanente"</string>
+ <string name="permdesc_brick">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
+ <string name="permlab_reboot">"provocar el reinicio del teléfono"</string>
+ <string name="permdesc_reboot">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar y desmontar filesystems"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
+ <string name="permlab_mount_format_filesystems">"espacio de almacenamiento externo del formato"</string>
+ <string name="permdesc_mount_format_filesystems">"Admite que la aplicación formatee el espacio de almacenamiento extraíble."</string>
+ <string name="permlab_vibrate">"vibrador de control"</string>
+ <string name="permdesc_vibrate">"Admite que la aplicación controle el vibrador."</string>
+ <string name="permlab_flashlight">"controlar linterna"</string>
+ <string name="permdesc_flashlight">"Admite que la aplicación controle la linterna."</string>
+ <string name="permlab_hardware_test">"probar el hardware"</string>
+ <string name="permdesc_hardware_test">"Admite que la aplicación controle diversos periféricos con el fin de probar el hardware."</string>
+ <string name="permlab_callPhone">"llamar directamente a números de teléfono"</string>
+ <string name="permdesc_callPhone">"Admite que la aplicación llame a ciertos números de teléfono sin tu permiso. Las aplicaciones maliciosas pueden ocasionar llamadas imprevistas en tu factura telefónica. Ten en cuenta que esto no admite que la aplicación llame a los números de emergencia."</string>
+ <string name="permlab_callPrivileged">"llamar directamente a cualquier número de teléfono"</string>
+ <string name="permdesc_callPrivileged">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
+ <string name="permlab_locationUpdates">"controlar las notificaciones de actualización de ubicación"</string>
+ <string name="permdesc_locationUpdates">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_checkinProperties">"acceder a las propiedades de protección"</string>
+ <string name="permdesc_checkinProperties">"Admite el acceso de lectura y escritura a las propiedades subidas por el servicio de protección. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_bindGadget">"elegir controles"</string>
+ <string name="permdesc_bindGadget">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_modifyPhoneState">"modificar el estado del teléfono"</string>
+ <string name="permdesc_modifyPhoneState">"Admite que la aplicación controle las funciones telefónicas del dispositivo. Una aplicación con este permiso puede cambiar las redes, encender y apagar la radio del teléfono y funciones similares sin notificarte en ningún momento."</string>
+ <string name="permlab_readPhoneState">"leer estado del teléfono"</string>
+ <string name="permdesc_readPhoneState">"Admite que la aplicación acceda a las funciones telefónicas del dispositivo. Una aplicación con este permiso puede determinar el número de este teléfono, si una llamada está activa, el número al cual está conectado esa llamada y funciones similares."</string>
+ <string name="permlab_wakeLock">"evitar que el teléfono entre en estado de inactividad"</string>
+ <string name="permdesc_wakeLock">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
+ <string name="permlab_devicePower">"apagar o encender el teléfono"</string>
+ <string name="permdesc_devicePower">"Admite que la aplicación encienda o apague el teléfono."</string>
+ <string name="permlab_factoryTest">"ejecutar en el modo de prueba de fábrica"</string>
+ <string name="permdesc_factoryTest">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
+ <string name="permlab_setWallpaper">"establecer papel tapiz"</string>
+ <string name="permdesc_setWallpaper">"Admite que la aplicación establezca el papel tapiz del sistema."</string>
+ <string name="permlab_setWallpaperHints">"establecer sugerencias de tamaño del papel tapiz"</string>
+ <string name="permdesc_setWallpaperHints">"Admite que la aplicación establezca las sugerencias de tamaño del papel tapiz del sistema."</string>
+ <string name="permlab_masterClear">"restablecer el sistema a las configuraciones predeterminadas de fábrica"</string>
+ <string name="permdesc_masterClear">"Admite una aplicación que restablece el sistema completamente con su configuración de fábrica, y borra todos los datos, las configuraciones y las aplicaciones instaladas."</string>
+ <string name="permlab_setTimeZone">"establecer zona horaria"</string>
+ <string name="permdesc_setTimeZone">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
+ <string name="permlab_getAccounts">"descubrir cuentas conocidas"</string>
+ <string name="permdesc_getAccounts">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
+ <string name="permlab_accessNetworkState">"ver estado de la red"</string>
+ <string name="permdesc_accessNetworkState">"Admite una aplicación que ve el estado de todas las redes."</string>
+ <string name="permlab_createNetworkSockets">"acceso total a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Admite una aplicación que crea conectores de red."</string>
+ <string name="permlab_writeApnSettings">"escribir configuración del Nombre del punto de acceso"</string>
+ <string name="permdesc_writeApnSettings">"Admite una aplicación que modifica la configuración de APN, como el proxy y el puerto de cualquier APN."</string>
+ <string name="permlab_changeNetworkState">"cambiar la conectividad de la red"</string>
+ <string name="permdesc_changeNetworkState">"Admite una aplicación que cambia la conectividad de red del estado."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiar la configuración del uso de datos del fondo"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
+ <string name="permlab_accessWifiState">"ver el estado de Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Admite una aplicación que observa la información sobre el estado de Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"cambiar el estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Admite una aplicación que se conecta y desconecta de los puntos de acceso de Wi-Fi y que hace cambios en las redes de Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueo"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Admite una aplicación que desactiva el bloqueo y cualquier seguridad con contraseña relacionada. Un ejemplo legítimo de esto es el bloqueo desactivado por el teléfono cuando recibe una llamada telefónica entrante, y luego la reactivación del bloqueo cuando finaliza la llamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Admite una aplicación que lee la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Admite una aplicación que modifica la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"leer estadística de sincronización"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Admite una aplicación que lee la estadística de sincronización; por ejemplo, el historial de sincronizaciones que se han producido."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leer canales suscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Admite una aplicación que obtiene detalles sobre los canales actualmente sincronizados."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escribir canales suscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Admite una aplicación que modifica tus canales actualmente sincronizados, lo cual podría permitir que una aplicación maliciosa también lo haga."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"leer diccionario definido por el usuario"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Admite una aplicación para leer palabras, nombres y frases privadas que posiblemente el usuario haya almacenado en el diccionario del usuario."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escribir al diccionario definido por el usuario"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Admite una aplicación que escribe palabras nuevas en el diccionario del usuario."</string>
+ <string name="permlab_bluetoothAdmin">"administración de bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"crear conexiones de Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
+ <string name="permlab_disableKeyguard">"desactivar el bloqueo"</string>
+ <string name="permdesc_disableKeyguard">"Admite una aplicación que desactiva el bloqueo y cualquier seguridad con contraseña relacionada. Un ejemplo legítimo de esto es el bloqueo desactivado por el teléfono cuando recibe una llamada telefónica entrante, y luego la reactivación del bloqueo cuando finaliza la llamada."</string>
+ <string name="permlab_readSyncSettings">"leer la configuración de sincronización"</string>
+ <string name="permdesc_readSyncSettings">"Admite una aplicación que lee la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
+ <string name="permlab_writeSyncSettings">"escribir configuración de sincronización"</string>
+ <string name="permdesc_writeSyncSettings">"Admite una aplicación que modifica la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
+ <string name="permlab_readSyncStats">"leer estadística de sincronización"</string>
+ <string name="permdesc_readSyncStats">"Admite una aplicación que lee la estadística de sincronización; por ejemplo, el historial de sincronizaciones que se han producido."</string>
+ <string name="permlab_subscribedFeedsRead">"leer canales suscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Admite una aplicación que obtiene detalles sobre los canales actualmente sincronizados."</string>
+ <string name="permlab_subscribedFeedsWrite">"escribir canales suscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Admite una aplicación que modifica tus canales actualmente sincronizados, lo cual podría permitir que una aplicación maliciosa también lo haga."</string>
+ <string name="permlab_readDictionary">"leer diccionario definido por el usuario"</string>
+ <string name="permdesc_readDictionary">"Admite una aplicación para leer palabras, nombres y frases privadas que posiblemente el usuario haya almacenado en el diccionario del usuario."</string>
+ <string name="permlab_writeDictionary">"escribir al diccionario definido por el usuario"</string>
+ <string name="permdesc_writeDictionary">"Admite una aplicación que escribe palabras nuevas en el diccionario del usuario."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Página principal"</item>
- <item msgid="869923650527136615">"Celular"</item>
- <item msgid="7897544654242874543">"Trabajo"</item>
- <item msgid="1103601433382158155">"Fax laboral"</item>
- <item msgid="1735177144948329370">"Fax residencial"</item>
- <item msgid="603878674477207394">"Localizador"</item>
- <item msgid="1650824275177931637">"Otros"</item>
- <item msgid="9192514806975898961">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Celular"</item>
+ <item>"Trabajo"</item>
+ <item>"Fax laboral"</item>
+ <item>"Fax residencial"</item>
+ <item>"Localizador"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Página principal"</item>
- <item msgid="7084237356602625604">"Trabajo"</item>
- <item msgid="1112044410659011023">"Otros"</item>
- <item msgid="2374913952870110618">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Celular"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Página principal"</item>
- <item msgid="5629153956045109251">"Trabajo"</item>
- <item msgid="4966604264500343469">"Otros"</item>
- <item msgid="4932682847595299369">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Pág. ppal."</item>
- <item msgid="1359644565647383708">"Trabajo"</item>
- <item msgid="7868549401053615677">"Otros"</item>
- <item msgid="3145118944639869809">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabajo"</item>
- <item msgid="4378074129049520373">"Otros"</item>
- <item msgid="3455047468583965104">"Personalización"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ingresar el código de PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"¡Código de PIN incorrecto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sin servicio)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Extraer el patrón para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Lo sentimos, vuelve a intentarlo"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Ingresar el código de PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"¡Código de PIN incorrecto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, presiona el menú y luego 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
+ <string name="lockscreen_carrier_default">"(Sin servicio)"</string>
+ <string name="lockscreen_screen_locked">"Pantalla bloqueada."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Presionar Menú para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Extraer el patrón para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
+ <string name="lockscreen_pattern_correct">"Correcto"</string>
+ <string name="lockscreen_pattern_wrong">"Lo sentimos, vuelve a intentarlo"</string>
+ <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"No hay tarjeta SIM en el teléfono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserta una tarjeta SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Red bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La tarjeta SIM está bloqueada."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Olvidaste el patrón?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Demasiados intentos de patrón."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, regístrate en tu cuenta de Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia sesión"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña incorrecta."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Conecta tu cargador."</string>
+ <string name="lockscreen_missing_sim_message_short">"No hay tarjeta SIM."</string>
+ <string name="lockscreen_missing_sim_message">"No hay tarjeta SIM en el teléfono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserta una tarjeta SIM."</string>
+ <string name="lockscreen_network_locked_message">"Red bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La tarjeta SIM está bloqueada con PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
+ <string name="lockscreen_sim_locked_message">"La tarjeta SIM está bloqueada."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando tarjeta SIM…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"¿Olvidaste el patrón?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Demasiados intentos de patrón."</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, regístrate en tu cuenta de Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nombre de usuario (correo electrónico)"</string>
+ <string name="lockscreen_glogin_password_hint">"Contraseña"</string>
+ <string name="lockscreen_glogin_submit_button">"Inicia sesión"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nombre de usuario o contraseña incorrecta."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Cargando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Hay poca batería:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restante."</string>
+ <string name="status_bar_no_notifications_title">"No hay notificaciones"</string>
+ <string name="status_bar_ongoing_events_title">"Continuo"</string>
+ <string name="status_bar_latest_events_title">"Notificaciones"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Cargando..."</string>
+ <string name="battery_low_title">"Conecta el cargador"</string>
+ <string name="battery_low_subtitle">"Hay poca batería:"</string>
+ <string name="battery_low_percent_format">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restante."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Error en la prueba de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"La acción FACTORY_TEST se admite solamente en paquetes instalados en /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST ."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La página en \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"Error en la prueba de fábrica"</string>
+ <string name="factorytest_not_system">"La acción FACTORY_TEST se admite solamente en paquetes instalados en /system/app."</string>
+ <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST ."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"La página en \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"No dispones de permiso para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado en el portapapeles."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Más"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menú+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espacio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ingresar"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"borrar"</string>
- <string name="search_go" msgid="8298016669822141719">"Buscar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
+ <string name="save_password_message">"¿Quieres recordar esta contraseña en el navegador?"</string>
+ <string name="save_password_notnow">"Ahora no."</string>
+ <string name="save_password_remember">"Recuerda"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"No dispones de permiso para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado en el portapapeles."</string>
+ <string name="more_item_label">"Más"</string>
+ <string name="prepend_shortcut_label">"Menú+"</string>
+ <string name="menu_space_shortcut_label">"espacio"</string>
+ <string name="menu_enter_shortcut_label">"ingresar"</string>
+ <string name="menu_delete_shortcut_label">"borrar"</string>
+ <string name="search_go">"Buscar"</string>
+ <string name="oneMonthDurationPast">"hace 1 mes"</string>
+ <string name="beforeOneMonthDurationPast">"Anterior a 1 mes atrás"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"hace 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 minuto"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"en 1 segundo"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"en 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"en 1 minuto"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"en 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"en 1 hora"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 min"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"en 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"en 1 segundo"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"en 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"en 1 minuto"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"en 1 hora"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"en %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"en %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"día"</string>
- <string name="days" msgid="4774547661021344602">"días"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"mins"</string>
- <string name="second" msgid="3184235808021478">"segundo"</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"año"</string>
- <string name="years" msgid="6881577717993213522">"años"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Los días de semana (lunes a viernes)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente el día <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensual"</string>
- <string name="yearly" msgid="1519577999407493836">"Anual"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"No se puede reproducir el video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Lo sentimos, este video no es válido para las transmisiones a este dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Lo sentimos, no se puede reproducir este video."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Aceptar"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mediodía"</string>
- <string name="Noon" msgid="3342127745230013127">"Mediodía"</string>
- <string name="midnight" msgid="7166259508850457595">"medianoche"</string>
- <string name="Midnight" msgid="5630806906897892201">"Medianoche"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener la selección de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar llamada"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar todo"</string>
- <string name="paste" msgid="5629880836805036433">"Pegar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Agregar \"%s\" al diccionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio de almacenamiento"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el teléfono."</string>
- <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
- <string name="capital_on" msgid="1544682755514494298">"Encendido"</string>
- <string name="capital_off" msgid="6815870386972805832">"APAGADO"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completar la acción mediante"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar la predeterminación en Configuración de la página principal > Aplicaciones > Administrar aplicaciones."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
- <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
- <string name="aerr_title" msgid="653922989522758100">"¡Lo sentimos!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
- <string name="aerr_process" msgid="1551785535966089511">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
- <string name="anr_title" msgid="3100070910664756057">"¡Lo sentimos!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g>) no responde."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
- <string name="anr_process" msgid="1246866008169975783">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."</string>
- <string name="force_close" msgid="3653416315450806396">"Provocar acercamiento"</string>
+ <string name="preposition_for_date">"en %s"</string>
+ <string name="preposition_for_time">"en %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"día"</string>
+ <string name="days">"días"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"mins"</string>
+ <string name="second">"segundo"</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"año"</string>
+ <string name="years">"años"</string>
+ <string name="every_weekday">"Los días de semana (lunes a viernes)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente el día <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensual"</string>
+ <string name="yearly">"Anual"</string>
+ <string name="VideoView_error_title">"No se puede reproducir el video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Lo sentimos, este video no es válido para las transmisiones a este dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Lo sentimos, no se puede reproducir este video."</string>
+ <string name="VideoView_error_button">"Aceptar"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mediodía"</string>
+ <string name="Noon">"Mediodía"</string>
+ <string name="midnight">"medianoche"</string>
+ <string name="Midnight">"Medianoche"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar todos"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Detener la selección de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar llamada"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar todo"</string>
+ <string name="paste">"Pegar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Agregar \"%s\" al diccionario"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Poco espacio de almacenamiento"</string>
+ <string name="low_internal_storage_view_text">"Hay poco espacio de almacenamiento en el teléfono."</string>
+ <string name="ok">"Aceptar"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"Aceptar"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atención"</string>
+ <string name="capital_on">"Encendido"</string>
+ <string name="capital_off">"APAGADO"</string>
+ <string name="whichApplication">"Completar la acción mediante"</string>
+ <string name="alwaysUse">"Utilizar de manera predeterminada en esta acción."</string>
+ <string name="clearDefaultHintMsg">"Borrar la predeterminación en Configuración de la página principal > Aplicaciones > Administrar aplicaciones."</string>
+ <string name="chooseActivity">"Seleccionar una acción"</string>
+ <string name="noApplications">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="aerr_title">"¡Lo sentimos!"</string>
+ <string name="aerr_application">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
+ <string name="aerr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
+ <string name="anr_title">"¡Lo sentimos!"</string>
+ <string name="anr_activity_application">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_activity_process">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_application_process">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."</string>
+ <string name="force_close">"Provocar acercamiento"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Espera"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecciona una acción para el texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volumen de los medios"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduciendo a través de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volumen de llamadas entrantes"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen en llamada de Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volumen de la alarma"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volumen de notificación"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volumen"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Tono de llamada predeterminado"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
+ <string name="wait">"Espera"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Selecciona una acción para el texto"</string>
+ <string name="volume_ringtone">"Volumen del timbre"</string>
+ <string name="volume_music">"Volumen de los medios"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
+ <string name="volume_call">"Volumen de llamadas entrantes"</string>
+ <string name="volume_bluetooth_call">"Volumen en llamada de Bluetooth"</string>
+ <string name="volume_alarm">"Volumen de la alarma"</string>
+ <string name="volume_notification">"Volumen de notificación"</string>
+ <string name="volume_unknown">"Volumen"</string>
+ <string name="ringtone_default">"Tono de llamada predeterminado"</string>
+ <string name="ringtone_default_with_actual">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Tonos de llamada"</string>
+ <string name="ringtone_unknown">"Tono de llamada desconocido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Red disponible de Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"redes disponibles de Wi-Fi"</item>
+ <item quantity="one">"Red disponible de Wi-Fi"</item>
+ <item quantity="other">"redes disponibles de Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Abrir red disponible de Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Abrir redes disponibles de Wi-Fi"</item>
+ <item quantity="one">"Abrir red disponible de Wi-Fi"</item>
+ <item quantity="other">"Abrir redes disponibles de Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicación desconocida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Se envía una gran cantidad de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
- <string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Cargando…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"conectado al USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Has conectado tu teléfono a tu computadora a través de USB. Selecciona \"Montar\" si deseas copiar archivos entre tu computadora y la tarjeta SD de tu teléfono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"No montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Hay un problema para utilizar tu tarjeta SD en el almacenamiento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"conectado al USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleccionar para copiar archivos desde o hacia tu computadora."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Apagar el almacenamiento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleccionar para desactivar el almacenamiento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Apagar el almacenamiento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar el almacenamiento USB, asegúrate de haberlo desmontado en el servidor USB al seleccionar \"Desactivar\"."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Apagar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Se ha producido un problema al desactivar el almacenamiento USB. Verifica para asegurarte de haber desmontado el servidor USB, luego vuelve a intentarlo."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de tu tarjeta."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
+ <string name="select_character">"Insertar caracteres"</string>
+ <string name="sms_control_default_app_name">"Aplicación desconocida"</string>
+ <string name="sms_control_title">"Enviando mensajes SMS"</string>
+ <string name="sms_control_message">"Se envía una gran cantidad de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
+ <string name="sms_control_yes">"Aceptar"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Establecer"</string>
+ <string name="default_permission_group">"Predeterminado"</string>
+ <string name="no_permissions">"No se requieren permisos"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todos"</b></string>
+ <string name="googlewebcontenthelper_loading">"Cargando…"</string>
+ <string name="usb_storage_title">"conectado al USB"</string>
+ <string name="usb_storage_message">"Has conectado tu teléfono a tu computadora a través de USB. Selecciona \"Montar\" si deseas copiar archivos entre tu computadora y la tarjeta SD de tu teléfono."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"No montar"</string>
+ <string name="usb_storage_error_message">"Hay un problema para utilizar tu tarjeta SD en el almacenamiento USB."</string>
+ <string name="usb_storage_notification_title">"conectado al USB"</string>
+ <string name="usb_storage_notification_message">"Seleccionar para copiar archivos desde o hacia tu computadora."</string>
+ <string name="usb_storage_stop_notification_title">"Apagar el almacenamiento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleccionar para desactivar el almacenamiento USB."</string>
+ <string name="usb_storage_stop_title">"Apagar el almacenamiento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar el almacenamiento USB, asegúrate de haberlo desmontado en el servidor USB al seleccionar \"Desactivar\"."</string>
+ <string name="usb_storage_stop_button_mount">"Apagar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Se ha producido un problema al desactivar el almacenamiento USB. Verifica para asegurarte de haber desmontado el servidor USB, luego vuelve a intentarlo."</string>
+ <string name="extmedia_format_title">"Formatear tarjeta SD"</string>
+ <string name="extmedia_format_message">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de tu tarjeta."</string>
+ <string name="extmedia_format_button_format">"Formato"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparación de la tarjeta SD"</string>
+ <string name="select_input_method">"Seleccionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparación de la tarjeta SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tarjeta SD vacía"</string>
+ <string name="ext_media_nofs_notification_title">"Tarjeta SD vacía"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Tarjeta SD dañada"</string>
+ <string name="ext_media_unmountable_notification_title">"Tarjeta SD dañada"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Tarjeta SD extraída de forma imprevista"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Tarjeta SD fácil de extraer"</string>
+ <string name="ext_media_badremoval_notification_title">"Tarjeta SD extraída de forma imprevista"</string>
+ <string name="ext_media_badremoval_notification_message">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Tarjeta SD fácil de extraer"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
+ <string name="ext_media_nomedia_notification_title">"Tarjeta SD extraída"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"No se encontraron actividades coincidentes"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar la estadística de uso de los componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Presiona dos veces para obtener el control del zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Error al aumentar el control"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Buscar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Siguiente"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hecho"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar el número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crear contacto "\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"No se encontraron actividades coincidentes"</string>
+ <string name="permlab_pkgUsageStats">"actualizar la estadística de uso de los componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Presiona dos veces para obtener el control del zoom"</string>
+ <string name="gadget_host_error_inflating">"Error al aumentar el control"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Buscar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Siguiente"</string>
+ <string name="ime_action_done">"Finalizado"</string>
+ <string name="ime_action_default">"Ejecutar"</string>
+ <string name="dial_number_using">"Marcar el número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crear contacto "\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f9fd376..f3ff316 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<sin título>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Sin número de teléfono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"Desconocido"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Buzón de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Se ha producido un problema de conexión o el código MMI no es válido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"El servicio se ha habilitado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Se ha habilitado el servicio para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"El servicio se ha inhabilitado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"El registro se ha realizado correctamente."</string>
- <string name="serviceErased" msgid="1288584695297200972">"El elemento se ha borrado correctamente."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Contraseña incorrecta"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completo"</string>
- <string name="badPin" msgid="5085454289896032547">"El PIN antiguo que has introducido no es correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"El código PUK que has introducido no es correcto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Los códigos PIN introducidos no coinciden."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
- <string name="needPuk" msgid="919668385956251611">"La tarjeta SIM está bloqueada con el código PUK. Introduce el código PUK para desbloquearla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID de emisor de llamada entrante"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID de emisor de llamada saliente"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desvío de llamada"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Llamada en espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Bloqueo de llamada"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Cambio de contraseña"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Cambio de PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Número de llamada entrante presente"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Número de llamada entrante restringido"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Llamada a tres"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rechazo de llamadas molestas no deseadas"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Entrega de número de llamada entrante"</string>
- <string name="DndMmi" msgid="1265478932418334331">"No molestar"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: Restringido"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: No restringido"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: Restringido"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"El servicio no se suministra."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"El ID de emisor no se puede modificar."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"El acceso restringido se ha modificado."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencia está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"El servicio de voz y SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos los servicios de voz y SMS están bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Datos"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicador de itinerancia activado"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicador de itinerancia desactivado"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicador de itinerancia parpadeante"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Fuera del vecindario"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Fuera del edificio"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Itinerancia: sistema preferido"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Itinerancia: sistema disponible"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Itinerancia: partner de alianza"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Itinerancia: partner de gran calidad"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Itinerancia: funcionalidad de servicio completa"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Itinerancia: funcionalidad de servicio parcial"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner de itinerancia activado"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner de itinerancia desactivado"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Código de función completo"</string>
- <string name="fcError" msgid="3327560126588500777">"Se ha producido un problema de conexión o el código de la función no es válido."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
- <string name="httpError" msgid="2567300624552921790">"La página web contiene un error."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"No se ha podido encontrar la URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"No se admite el esquema de autenticación del sitio."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"La autenticación no se ha realizado correctamente."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"La autenticación mediante el servidor proxy no se ha realizado correctamente."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"La conexión al servidor no se ha realizado correctamente."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"El servidor no ha podido establecer la comunicación. Vuelve a intentarlo más tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Se ha agotado el tiempo de espera de conexión al servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La página contiene demasiados redireccionamientos de servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protocolo no admitido"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"No se ha podido establecer una conexión segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"La página no se ha podido abrir porque la URL no es válida."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"No se ha podido acceder al archivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"No se ha encontrado el archivo solicitado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
- <string name="low_memory" msgid="6632412458436461203">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
- <string name="me" msgid="6545696007631404292">"Yo"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opciones del teléfono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencio"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar conexión inalámbrica"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar función inalámbrica"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
- <string name="power_off" msgid="4266614107412865048">"Apagar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"El teléfono se apagará."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"No hay aplicaciones recientes"</string>
- <string name="global_actions" msgid="2406416831541615258">"Opciones del teléfono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencio"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está desactivado. Activar."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está activado. Desactivar."</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión desactivado. Activar."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar."</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios por los que tienes que pagar"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite que las aplicaciones realicen acciones por las que puede que tengas que pagar."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leer y escribir SMS, mensajes de correo electrónico y otros mensajes"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acceso directo al calendario y a los contactos almacenados en el teléfono"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Controlar su ubicación física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite que las aplicaciones accedan a distintas funciones de red."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Tus cuentas de Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acceder a las cuentas de Google disponibles"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware del móvil"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas de teléfono"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, registrar y procesar llamadas telefónicas"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acceso de nivel inferior y control del sistema"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Herramientas de desarrollo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funciones necesarias sólo para desarrolladores de aplicaciones"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Almacenamiento"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Acceder a la tarjeta SD"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite que las aplicaciones inhabiliten la barra de estado, o añadan y eliminen iconos del sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/contraer la barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite que la aplicación expanda y contraiga la barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite que la aplicación procese llamadas salientes y cambie el número que se va a marcar. Las aplicaciones malintencionadas pueden controlar, redirigir o impedir las llamadas salientes."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"recibir SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite que la aplicación reciba y procese mensajes SMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"recibir MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite que la aplicación reciba y procese mensajes MMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensajes SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite que la aplicación envíe mensajes SMS. Es posible que tengas que pagar si las aplicaciones malintencionadas envían mensajes sin tu confirmación."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite que la aplicación lea mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite que la aplicación escriba en mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicaciones en ejecución"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Puede permitir que las aplicaciones malintencionadas vean información privada sobre otras aplicaciones."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que una aplicación mueva tareas a segundo plano y a primer plano. Las aplicaciones malintencionadas pueden aparecer en primer plano sin su control."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"habilitar depuración de aplicación"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar otras aplicaciones"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite que una aplicación reinicie de forma forzosa otras aplicaciones."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forzar el cierre de la aplicación"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite que una aplicación fuerce a cualquier actividad en segundo plano a cerrarse y volver a la pantalla anterior. No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar estado interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite que la aplicación recupere el estado interno del sistema. Las aplicaciones malintencionadas pueden recuperar una amplia variedad de información protegida y privada que normalmente no deberían necesitar."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Evita que el usuario cambie a otra aplicación."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite que una aplicación supervise y controle la ejecución de las actividades por parte del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso sólo es necesario para tareas de desarrollo, nunca para el uso habitual del teléfono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión eliminada de paquete"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para interrumpir la ejecución de cualquier otra aplicación."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar una emisión recibida mediante SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje SMS. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar de forma silenciosa el contenido de cualquier página web con variantes malintencionadas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el número de procesos en ejecución"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite que una aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"hacer que se cierren todas las aplicaciones en segundo plano"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite que una aplicación controle si las actividades finalizan siempre en cuanto pasan a segundo plano. No es necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estadísticas de la batería"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite la modificación de estadísticas recopiladas sobre la batería. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_backup" msgid="470013022865453920">"controlar las copias de seguridad y las restauraciones del sistema"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas de nivel del sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite que una aplicación muestre ventanas de alerta del sistema. Las aplicaciones malintencionadas pueden controlar toda la pantalla del teléfono."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidad de animación global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrar tokens de aplicación"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite que las aplicaciones creen y administren sus propios tokens, ignorando su orden z normal. Nunca debería ser necesario para las aplicaciones normales."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"pulsar teclas y botones de control"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el teléfono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrar lo que se escribe y las acciones que se realizan"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite que las aplicaciones observen las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"enlazar con un método de introducción de texto"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite enlazar con la interfaz de nivel superior de un método de introducción de texto. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales Linux a aplicaciones"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que la aplicación se ejecute siempre"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite que una aplicación vuelva persistentes algunas de sus partes, de forma que el sistema no la pueda utilizar para otras aplicaciones."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicaciones"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite que una aplicación elimine paquetes Android. Las aplicaciones malintencionadas pueden utilizar este permiso para eliminar aplicaciones importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar los datos de otras aplicaciones"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite que una aplicación borre los datos de usuario."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar las cachés de otras aplicaciones"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite que una aplicación elimine archivos de caché."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir el espacio de almacenamiento de la aplicación"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite que la aplicación recupere su código, sus datos y los tamaños de caché."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite que una aplicación instale paquetes Android nuevos o actualizados. Las aplicaciones malintencionadas pueden utilizar este permiso para añadir aplicaciones nuevas con permisos arbitrariamente potentes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"habilitar o inhabilitar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. El permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inutilizables, inconsistentes o inestables."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"establecer aplicaciones preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite que una aplicación modifique las aplicaciones preferidas del usuario. De esta forma, las aplicaciones malintencionadas pueden cambiar de forma silenciosa las aplicaciones que se están ejecutando, falsificando las aplicaciones existentes para recopilar datos privados del usuario."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite que una aplicación modifique los datos de configuración del sistema. Las aplicaciones malintencionadas pueden dañar la configuración del sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuración segura del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite que una aplicación modifique los datos de configuración segura del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar la asignación de servicios de Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite que una aplicación modifique la asignación de servicios de Google. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede provocar que el teléfono tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del teléfono al ejecutarse continuamente."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisión persistente"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite que una aplicación envíe emisiones persistentes, que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el teléfono o volverlo inestable al hacer que emplee demasiada memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"leer los datos de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de contacto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escribir datos de propietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite que una aplicación modifique los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del propietario."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"leer datos del propietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite que una aplicación lea los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para leer los datos del propietario del teléfono."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"leer datos de calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite que una aplicación lea todos los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escribir datos de calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite que una aplicación modifique los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"simular fuentes de ubicación para prueba"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos de proveedor de ubicación adicional"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Acceder a comandos de proveedor de ubicación adicional. Las aplicaciones malintencionadas podrían utilizar este permiso para interferir en el funcionamiento del sistema GPS o de otras fuentes de ubicación."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"permiso para instalar un proveedor de ubicación"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS, o para controlar y notificar tu ubicación a una fuente externa."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"precisar la ubicación (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permite precisar las fuentes de ubicación como, por ejemplo, el sistema de posicionamiento global, en el teléfono, en los casos en que estén disponibles. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde se encuentra en usuario y pueden consumir batería adicional."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación común (basada en red)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de red de un teléfono móvil, para determinar una ubicación telefónica aproximada, en los casos en que esté disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde te encuentras aproximadamente."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite que la aplicación utilice funciones de SurfaceFlinger de nivel inferior."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer memoria de almacenamiento intermedio"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite que la aplicación que se va a utilizar lea el contenido de la memoria de almacenamiento intermedio."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar la configuración de audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite que la aplicación modifique la configuración de audio global como, por ejemplo, el volumen y la salida."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar sonido"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"realizar fotografías"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite que la aplicación realice fotografías con la cámara. De esta forma, la aplicación puede recopilar en cualquier momento las imágenes que ve la cámara."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"inhabilitar el teléfono de forma permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"activar y desactivar sistemas de archivos"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatear almacenamiento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite a la aplicación formatear un almacenamiento extraíble."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar vibración"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que la aplicación controle la función de vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que la aplicación controle la función de linterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"probar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que la aplicación controle distintos periféricos con fines de prueba del hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite que la aplicación llame a números de teléfono sin la intervención del usuario. Las aplicaciones malintencionadas pueden originar llamadas inesperadas en la factura telefónica. Ten en cuenta que con este permiso la aplicación no puede realizar llamadas a números de emergencia."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de la ubicación"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a propiedades de registro"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"seleccionar widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite que una aplicación indique al sistema los widgets que puede utilizar cada aplicación. Se trata de un permiso que no pueden utilizar las aplicaciones normales y que permite que una aplicación conceda acceso a datos personales a otras aplicaciones."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado del teléfono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite que una aplicación impida que el teléfono entre en modo de suspensión."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"encender o apagar el teléfono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite que la aplicación active o desactive el teléfono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en modo de prueba de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Ejecutar como prueba de fabricante de nivel inferior, permitiendo un acceso íntegro al hardware del teléfono. Sólo está disponible cuando un teléfono se está ejecutando en modo de prueba."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer fondo de pantalla"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer el tamaño del fondo de pantalla"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permite que la aplicación establezca el tamaño del fondo de pantalla del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"restablecer el sistema a los valores predeterminados de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite que una aplicación restablezca por completo el sistema a su configuración de fábrica, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite que una aplicación cambie la zona horaria del teléfono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"ver cuentas reconocidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado de la red"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite que una aplicación vea el estado de todas las redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acceso íntegro a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite que una aplicación cree sockets de red."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escribir la configuración de nombre de punto de acceso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite que una aplicación modifique los valores de configuración de un APN como, por ejemplo, el proxy y el puerto de cualquier APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de red"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite que una aplicación cambie la conectividad de red de estado."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de datos de referencia"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite a una aplicación cambiar la configuración de uso de los datos de referencia."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver estado de la conectividad Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite que una aplicación vea la información sobre el estado de la conectividad Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"cambiar estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que una aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos, y realice modificaciones en las redes Wi-Fi configuradas."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"inhabilitar bloqueo del teclado"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que una aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo legítimo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado cuando recibe una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite que una aplicación lea la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite que una aplicación modifique la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"leer estadísticas de sincronización"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite que una aplicación lea las estadísticas de sincronización como, por ejemplo, el historial de sincronizaciones que se han realizado."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leer feeds a los que está suscrito el usuario"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escribir feeds a los que está suscrito el usuario"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"leer diccionario definido por el usuario"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite a una aplicación leer cualquier frase, palabra o nombre privado que el usuario haya almacenado en su diccionario."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escribir en el diccionario definido por el usuario"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite a una aplicación escribir palabras nuevas en el diccionario del usuario."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modificar/eliminar contenido de la tarjeta SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Permite que una aplicación escriba en la tarjeta SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<sin título>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Sin número de teléfono)"</string>
+ <string name="unknownName">"Desconocido"</string>
+ <string name="defaultVoiceMailAlphaTag">"Buzón de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Se ha producido un problema de conexión o el código MMI no es válido."</string>
+ <string name="serviceEnabled">"El servicio se ha habilitado."</string>
+ <string name="serviceEnabledFor">"Se ha habilitado el servicio para:"</string>
+ <string name="serviceDisabled">"El servicio se ha inhabilitado."</string>
+ <string name="serviceRegistered">"El registro se ha realizado correctamente."</string>
+ <string name="serviceErased">"El elemento se ha borrado correctamente."</string>
+ <string name="passwordIncorrect">"Contraseña incorrecta"</string>
+ <string name="mmiComplete">"MMI completo"</string>
+ <string name="badPin">"El PIN antiguo que has introducido no es correcto."</string>
+ <string name="badPuk">"El código PUK que has introducido no es correcto."</string>
+ <string name="mismatchPin">"Los códigos PIN introducidos no coinciden."</string>
+ <string name="invalidPin">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
+ <string name="needPuk">"La tarjeta SIM está bloqueada con el código PUK. Introduce el código PUK para desbloquearla."</string>
+ <string name="needPuk2">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
+ <string name="ClipMmi">"ID de emisor de llamada entrante"</string>
+ <string name="ClirMmi">"ID de emisor de llamada saliente"</string>
+ <string name="CfMmi">"Desvío de llamada"</string>
+ <string name="CwMmi">"Llamada en espera"</string>
+ <string name="BaMmi">"Bloqueo de llamada"</string>
+ <string name="PwdMmi">"Cambio de contraseña"</string>
+ <string name="PinMmi">"Cambio de PIN"</string>
+ <string name="CnipMmi">"Número de llamada entrante presente"</string>
+ <string name="CnirMmi">"Número de llamada entrante restringido"</string>
+ <string name="ThreeWCMmi">"Llamada a tres"</string>
+ <string name="RuacMmi">"Rechazo de llamadas molestas no deseadas"</string>
+ <string name="CndMmi">"Entrega de número de llamada entrante"</string>
+ <string name="DndMmi">"No molestar"</string>
+ <string name="CLIRDefaultOnNextCallOn">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: Restringido"</string>
+ <string name="CLIRDefaultOnNextCallOff">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: No restringido"</string>
+ <string name="CLIRDefaultOffNextCallOn">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: Restringido"</string>
+ <string name="CLIRDefaultOffNextCallOff">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
+ <string name="serviceNotProvisioned">"El servicio no se suministra."</string>
+ <string name="CLIRPermanent">"El ID de emisor no se puede modificar."</string>
+ <string name="RestrictedChangedTitle">"El acceso restringido se ha modificado."</string>
+ <string name="RestrictedOnData">"El servicio de datos está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"El servicio de emergencia está bloqueado."</string>
+ <string name="RestrictedOnNormal">"El servicio de voz y SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos los servicios de voz y SMS están bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Datos"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronización"</string>
+ <string name="serviceClassPacket">"Paquete"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicador de itinerancia activado"</string>
+ <string name="roamingText1">"Indicador de itinerancia desactivado"</string>
+ <string name="roamingText2">"Indicador de itinerancia parpadeante"</string>
+ <string name="roamingText3">"Fuera del vecindario"</string>
+ <string name="roamingText4">"Fuera del edificio"</string>
+ <string name="roamingText5">"Itinerancia: sistema preferido"</string>
+ <string name="roamingText6">"Itinerancia: sistema disponible"</string>
+ <string name="roamingText7">"Itinerancia: partner de alianza"</string>
+ <string name="roamingText8">"Itinerancia: partner de gran calidad"</string>
+ <string name="roamingText9">"Itinerancia: funcionalidad de servicio completa"</string>
+ <string name="roamingText10">"Itinerancia: funcionalidad de servicio parcial"</string>
+ <string name="roamingText11">"Banner de itinerancia activado"</string>
+ <string name="roamingText12">"Banner de itinerancia desactivado"</string>
+ <string name="roamingTextSearching">"Buscando servicio"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="fcComplete">"Código de función completo"</string>
+ <string name="fcError">"Se ha producido un problema de conexión o el código de la función no es válido."</string>
+ <string name="httpErrorOk">"Aceptar"</string>
+ <string name="httpError">"La página web contiene un error."</string>
+ <string name="httpErrorLookup">"No se ha podido encontrar la URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"No se admite el esquema de autenticación del sitio."</string>
+ <string name="httpErrorAuth">"La autenticación no se ha realizado correctamente."</string>
+ <string name="httpErrorProxyAuth">"La autenticación mediante el servidor proxy no se ha realizado correctamente."</string>
+ <string name="httpErrorConnect">"La conexión al servidor no se ha realizado correctamente."</string>
+ <string name="httpErrorIO">"El servidor no ha podido establecer la comunicación. Vuelve a intentarlo más tarde."</string>
+ <string name="httpErrorTimeout">"Se ha agotado el tiempo de espera de conexión al servidor."</string>
+ <string name="httpErrorRedirectLoop">"La página contiene demasiados redireccionamientos de servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"Protocolo no admitido"</string>
+ <string name="httpErrorFailedSslHandshake">"No se ha podido establecer una conexión segura."</string>
+ <string name="httpErrorBadUrl">"La página no se ha podido abrir porque la URL no es válida."</string>
+ <string name="httpErrorFile">"No se ha podido acceder al archivo."</string>
+ <string name="httpErrorFileNotFound">"No se ha encontrado el archivo solicitado."</string>
+ <string name="httpErrorTooManyRequests">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
+ <string name="contentServiceSync">"Sincronización"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronización"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
+ <string name="low_memory">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+ <string name="me">"Yo"</string>
+ <string name="power_dialog">"Opciones del teléfono"</string>
+ <string name="silent_mode">"Modo silencio"</string>
+ <string name="turn_on_radio">"Activar conexión inalámbrica"</string>
+ <string name="turn_off_radio">"Desactivar función inalámbrica"</string>
+ <string name="screen_lock">"Bloqueo de pantalla"</string>
+ <string name="power_off">"Apagar"</string>
+ <string name="shutdown_progress">"Apagando..."</string>
+ <string name="shutdown_confirm">"El teléfono se apagará."</string>
+ <string name="no_recent_tasks">"No hay aplicaciones recientes"</string>
+ <string name="global_actions">"Opciones del teléfono"</string>
+ <string name="global_action_lock">"Bloqueo de pantalla"</string>
+ <string name="global_action_power_off">"Apagar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencio"</string>
+ <string name="global_action_silent_mode_on_status">"El sonido está desactivado. Activar."</string>
+ <string name="global_action_silent_mode_off_status">"El sonido está activado. Desactivar."</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo avión"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modo avión desactivado. Activar."</string>
+ <string name="global_actions_airplane_mode_off_status">"Modo avión desactivado. Activar."</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Servicios por los que tienes que pagar"</string>
+ <string name="permgroupdesc_costMoney">"Permite que las aplicaciones realicen acciones por las que puede que tengas que pagar."</string>
+ <string name="permgrouplab_messages">"Tus mensajes"</string>
+ <string name="permgroupdesc_messages">"Leer y escribir SMS, mensajes de correo electrónico y otros mensajes"</string>
+ <string name="permgrouplab_personalInfo">"Tu información personal"</string>
+ <string name="permgroupdesc_personalInfo">"Acceso directo al calendario y a los contactos almacenados en el teléfono"</string>
+ <string name="permgrouplab_location">"Tu ubicación"</string>
+ <string name="permgroupdesc_location">"Controlar su ubicación física"</string>
+ <string name="permgrouplab_network">"Comunicación de red"</string>
+ <string name="permgroupdesc_network">"Permite que las aplicaciones accedan a distintas funciones de red."</string>
+ <string name="permgrouplab_accounts">"Tus cuentas de Google"</string>
+ <string name="permgroupdesc_accounts">"Acceder a las cuentas de Google disponibles"</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acceso directo al hardware del móvil"</string>
+ <string name="permgrouplab_phoneCalls">"Llamadas de teléfono"</string>
+ <string name="permgroupdesc_phoneCalls">"Controlar, registrar y procesar llamadas telefónicas"</string>
+ <string name="permgrouplab_systemTools">"Herramientas del sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acceso de nivel inferior y control del sistema"</string>
+ <string name="permgrouplab_developmentTools">"Herramientas de desarrollo"</string>
+ <string name="permgroupdesc_developmentTools">"Funciones necesarias sólo para desarrolladores de aplicaciones"</string>
+ <string name="permgrouplab_storage">"Almacenamiento"</string>
+ <string name="permgroupdesc_storage">"Acceder a la tarjeta SD"</string>
+ <string name="permlab_statusBar">"inhabilitar o modificar la barra de estado"</string>
+ <string name="permdesc_statusBar">"Permite que las aplicaciones inhabiliten la barra de estado, o añadan y eliminen iconos del sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/contraer la barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Permite que la aplicación expanda y contraiga la barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar llamadas salientes"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite que la aplicación procese llamadas salientes y cambie el número que se va a marcar. Las aplicaciones malintencionadas pueden controlar, redirigir o impedir las llamadas salientes."</string>
+ <string name="permlab_receiveSms">"recibir SMS"</string>
+ <string name="permdesc_receiveSms">"Permite que la aplicación reciba y procese mensajes SMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_receiveMms">"recibir MMS"</string>
+ <string name="permdesc_receiveMms">"Permite que la aplicación reciba y procese mensajes MMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_sendSms">"enviar mensajes SMS"</string>
+ <string name="permdesc_sendSms">"Permite que la aplicación envíe mensajes SMS. Es posible que tengas que pagar si las aplicaciones malintencionadas envían mensajes sin tu confirmación."</string>
+ <string name="permlab_readSms">"leer SMS o MMS"</string>
+ <string name="permdesc_readSms">"Permite que la aplicación lea mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
+ <string name="permlab_writeSms">"editar SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Permite que la aplicación escriba en mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
+ <string name="permlab_receiveWapPush">"recibir WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_getTasks">"recuperar aplicaciones en ejecución"</string>
+ <string name="permdesc_getTasks">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Puede permitir que las aplicaciones malintencionadas vean información privada sobre otras aplicaciones."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicaciones en ejecución"</string>
+ <string name="permdesc_reorderTasks">"Permite que una aplicación mueva tareas a segundo plano y a primer plano. Las aplicaciones malintencionadas pueden aparecer en primer plano sin su control."</string>
+ <string name="permlab_setDebugApp">"habilitar depuración de aplicación"</string>
+ <string name="permdesc_setDebugApp">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
+ <string name="permlab_changeConfiguration">"cambiar la configuración de la interfaz de usuario"</string>
+ <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string>
+ <string name="permlab_restartPackages">"reiniciar otras aplicaciones"</string>
+ <string name="permdesc_restartPackages">"Permite que una aplicación reinicie de forma forzosa otras aplicaciones."</string>
+ <string name="permlab_forceBack">"forzar el cierre de la aplicación"</string>
+ <string name="permdesc_forceBack">"Permite que una aplicación fuerce a cualquier actividad en segundo plano a cerrarse y volver a la pantalla anterior. No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_dump">"recuperar estado interno del sistema"</string>
+ <string name="permdesc_dump">"Permite que la aplicación recupere el estado interno del sistema. Las aplicaciones malintencionadas pueden recuperar una amplia variedad de información protegida y privada que normalmente no deberían necesitar."</string>
+ <string name="permlab_shutdown">"cierre parcial"</string>
+ <string name="permdesc_shutdown">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
+ <string name="permlab_stopAppSwitches">"evitar cambios de aplicación"</string>
+ <string name="permdesc_stopAppSwitches">"Evita que el usuario cambie a otra aplicación."</string>
+ <string name="permlab_runSetActivityWatcher">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite que una aplicación supervise y controle la ejecución de las actividades por parte del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso sólo es necesario para tareas de desarrollo, nunca para el uso habitual del teléfono."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar emisión eliminada de paquete"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para interrumpir la ejecución de cualquier otra aplicación."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar una emisión recibida mediante SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje SMS. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
+ <string name="permlab_broadcastWapPush">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar de forma silenciosa el contenido de cualquier página web con variantes malintencionadas."</string>
+ <string name="permlab_setProcessLimit">"limitar el número de procesos en ejecución"</string>
+ <string name="permdesc_setProcessLimit">"Permite que una aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_setAlwaysFinish">"hacer que se cierren todas las aplicaciones en segundo plano"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite que una aplicación controle si las actividades finalizan siempre en cuanto pasan a segundo plano. No es necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_batteryStats">"modificar estadísticas de la batería"</string>
+ <string name="permdesc_batteryStats">"Permite la modificación de estadísticas recopiladas sobre la batería. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_backup">"controlar las copias de seguridad y las restauraciones del sistema"</string>
+ <string name="permdesc_backup">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
+ <string name="permlab_internalSystemWindow">"mostrar ventanas no autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_systemAlertWindow">"mostrar alertas de nivel del sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite que una aplicación muestre ventanas de alerta del sistema. Las aplicaciones malintencionadas pueden controlar toda la pantalla del teléfono."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidad de animación global"</string>
+ <string name="permdesc_setAnimationScale">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
+ <string name="permlab_manageAppTokens">"administrar tokens de aplicación"</string>
+ <string name="permdesc_manageAppTokens">"Permite que las aplicaciones creen y administren sus propios tokens, ignorando su orden z normal. Nunca debería ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_injectEvents">"pulsar teclas y botones de control"</string>
+ <string name="permdesc_injectEvents">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el teléfono."</string>
+ <string name="permlab_readInputState">"registrar lo que se escribe y las acciones que se realizan"</string>
+ <string name="permdesc_readInputState">"Permite que las aplicaciones observen las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_bindInputMethod">"enlazar con un método de introducción de texto"</string>
+ <string name="permdesc_bindInputMethod">"Permite enlazar con la interfaz de nivel superior de un método de introducción de texto. No debe ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_setOrientation">"cambiar orientación de la pantalla"</string>
+ <string name="permdesc_setOrientation">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar señales Linux a aplicaciones"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
+ <string name="permlab_persistentActivity">"hacer que la aplicación se ejecute siempre"</string>
+ <string name="permdesc_persistentActivity">"Permite que una aplicación vuelva persistentes algunas de sus partes, de forma que el sistema no la pueda utilizar para otras aplicaciones."</string>
+ <string name="permlab_deletePackages">"eliminar aplicaciones"</string>
+ <string name="permdesc_deletePackages">"Permite que una aplicación elimine paquetes Android. Las aplicaciones malintencionadas pueden utilizar este permiso para eliminar aplicaciones importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar los datos de otras aplicaciones"</string>
+ <string name="permdesc_clearAppUserData">"Permite que una aplicación borre los datos de usuario."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar las cachés de otras aplicaciones"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite que una aplicación elimine archivos de caché."</string>
+ <string name="permlab_getPackageSize">"medir el espacio de almacenamiento de la aplicación"</string>
+ <string name="permdesc_getPackageSize">"Permite que la aplicación recupere su código, sus datos y los tamaños de caché."</string>
+ <string name="permlab_installPackages">"instalar aplicaciones directamente"</string>
+ <string name="permdesc_installPackages">"Permite que una aplicación instale paquetes Android nuevos o actualizados. Las aplicaciones malintencionadas pueden utilizar este permiso para añadir aplicaciones nuevas con permisos arbitrariamente potentes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos los datos de caché de la aplicación"</string>
+ <string name="permdesc_clearAppCache">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
+ <string name="permlab_readLogs">"leer archivos de registro del sistema"</string>
+ <string name="permdesc_readLogs">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string>
+ <string name="permlab_diagnostic">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
+ <string name="permdesc_diagnostic">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
+ <string name="permlab_changeComponentState">"habilitar o inhabilitar componentes de la aplicación"</string>
+ <string name="permdesc_changeComponentState">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. El permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inutilizables, inconsistentes o inestables."</string>
+ <string name="permlab_setPreferredApplications">"establecer aplicaciones preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Permite que una aplicación modifique las aplicaciones preferidas del usuario. De esta forma, las aplicaciones malintencionadas pueden cambiar de forma silenciosa las aplicaciones que se están ejecutando, falsificando las aplicaciones existentes para recopilar datos privados del usuario."</string>
+ <string name="permlab_writeSettings">"modificar la configuración global del sistema"</string>
+ <string name="permdesc_writeSettings">"Permite que una aplicación modifique los datos de configuración del sistema. Las aplicaciones malintencionadas pueden dañar la configuración del sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar la configuración segura del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Permite que una aplicación modifique los datos de configuración segura del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_writeGservices">"modificar la asignación de servicios de Google"</string>
+ <string name="permdesc_writeGservices">"Permite que una aplicación modifique la asignación de servicios de Google. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_receiveBootCompleted">"ejecutar automáticamente al iniciar"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede provocar que el teléfono tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del teléfono al ejecutarse continuamente."</string>
+ <string name="permlab_broadcastSticky">"enviar emisión persistente"</string>
+ <string name="permdesc_broadcastSticky">"Permite que una aplicación envíe emisiones persistentes, que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el teléfono o volverlo inestable al hacer que emplee demasiada memoria."</string>
+ <string name="permlab_readContacts">"leer los datos de contacto"</string>
+ <string name="permdesc_readContacts">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
+ <string name="permlab_writeContacts">"escribir datos de contacto"</string>
+ <string name="permdesc_writeContacts">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de contacto."</string>
+ <string name="permlab_writeOwnerData">"escribir datos de propietario"</string>
+ <string name="permdesc_writeOwnerData">"Permite que una aplicación modifique los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del propietario."</string>
+ <string name="permlab_readOwnerData">"leer datos del propietario"</string>
+ <string name="permdesc_readOwnerData">"Permite que una aplicación lea los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para leer los datos del propietario del teléfono."</string>
+ <string name="permlab_readCalendar">"leer datos de calendario"</string>
+ <string name="permdesc_readCalendar">"Permite que una aplicación lea todos los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeCalendar">"escribir datos de calendario"</string>
+ <string name="permdesc_writeCalendar">"Permite que una aplicación modifique los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de calendario."</string>
+ <string name="permlab_accessMockLocation">"simular fuentes de ubicación para prueba"</string>
+ <string name="permdesc_accessMockLocation">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS."</string>
+ <string name="permlab_accessLocationExtraCommands">"acceder a comandos de proveedor de ubicación adicional"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Acceder a comandos de proveedor de ubicación adicional. Las aplicaciones malintencionadas podrían utilizar este permiso para interferir en el funcionamiento del sistema GPS o de otras fuentes de ubicación."</string>
+ <string name="permlab_installLocationProvider">"permiso para instalar un proveedor de ubicación"</string>
+ <string name="permdesc_installLocationProvider">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS, o para controlar y notificar tu ubicación a una fuente externa."</string>
+ <string name="permlab_accessFineLocation">"precisar la ubicación (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Permite precisar las fuentes de ubicación como, por ejemplo, el sistema de posicionamiento global, en el teléfono, en los casos en que estén disponibles. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde se encuentra en usuario y pueden consumir batería adicional."</string>
+ <string name="permlab_accessCoarseLocation">"ubicación común (basada en red)"</string>
+ <string name="permdesc_accessCoarseLocation">"Acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de red de un teléfono móvil, para determinar una ubicación telefónica aproximada, en los casos en que esté disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde te encuentras aproximadamente."</string>
+ <string name="permlab_accessSurfaceFlinger">"acceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite que la aplicación utilice funciones de SurfaceFlinger de nivel inferior."</string>
+ <string name="permlab_readFrameBuffer">"leer memoria de almacenamiento intermedio"</string>
+ <string name="permdesc_readFrameBuffer">"Permite que la aplicación que se va a utilizar lea el contenido de la memoria de almacenamiento intermedio."</string>
+ <string name="permlab_modifyAudioSettings">"cambiar la configuración de audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite que la aplicación modifique la configuración de audio global como, por ejemplo, el volumen y la salida."</string>
+ <string name="permlab_recordAudio">"grabar sonido"</string>
+ <string name="permdesc_recordAudio">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
+ <string name="permlab_camera">"realizar fotografías"</string>
+ <string name="permdesc_camera">"Permite que la aplicación realice fotografías con la cámara. De esta forma, la aplicación puede recopilar en cualquier momento las imágenes que ve la cámara."</string>
+ <string name="permlab_brick">"inhabilitar el teléfono de forma permanente"</string>
+ <string name="permdesc_brick">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
+ <string name="permlab_reboot">"forzar reinicio del teléfono"</string>
+ <string name="permdesc_reboot">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
+ <string name="permlab_mount_unmount_filesystems">"activar y desactivar sistemas de archivos"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
+ <string name="permlab_mount_format_filesystems">"formatear almacenamiento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite a la aplicación formatear un almacenamiento extraíble."</string>
+ <string name="permlab_vibrate">"controlar vibración"</string>
+ <string name="permdesc_vibrate">"Permite que la aplicación controle la función de vibración."</string>
+ <string name="permlab_flashlight">"controlar linterna"</string>
+ <string name="permdesc_flashlight">"Permite que la aplicación controle la función de linterna."</string>
+ <string name="permlab_hardware_test">"probar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite que la aplicación controle distintos periféricos con fines de prueba del hardware."</string>
+ <string name="permlab_callPhone">"llamar directamente a números de teléfono"</string>
+ <string name="permdesc_callPhone">"Permite que la aplicación llame a números de teléfono sin la intervención del usuario. Las aplicaciones malintencionadas pueden originar llamadas inesperadas en la factura telefónica. Ten en cuenta que con este permiso la aplicación no puede realizar llamadas a números de emergencia."</string>
+ <string name="permlab_callPrivileged">"llamar directamente a cualquier número de teléfono"</string>
+ <string name="permdesc_callPrivileged">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
+ <string name="permlab_locationUpdates">"controlar las notificaciones de actualización de la ubicación"</string>
+ <string name="permdesc_locationUpdates">"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_checkinProperties">"acceder a propiedades de registro"</string>
+ <string name="permdesc_checkinProperties">"Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_bindGadget">"seleccionar widgets"</string>
+ <string name="permdesc_bindGadget">"Permite que una aplicación indique al sistema los widgets que puede utilizar cada aplicación. Se trata de un permiso que no pueden utilizar las aplicaciones normales y que permite que una aplicación conceda acceso a datos personales a otras aplicaciones."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado del teléfono"</string>
+ <string name="permdesc_modifyPhoneState">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."</string>
+ <string name="permlab_readPhoneState">"leer el estado del teléfono"</string>
+ <string name="permdesc_readPhoneState">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono de este teléfono, si una llamada está activa, el número al que está vinculado esa llamada, etc."</string>
+ <string name="permlab_wakeLock">"impedir que el teléfono entre en modo de suspensión"</string>
+ <string name="permdesc_wakeLock">"Permite que una aplicación impida que el teléfono entre en modo de suspensión."</string>
+ <string name="permlab_devicePower">"encender o apagar el teléfono"</string>
+ <string name="permdesc_devicePower">"Permite que la aplicación active o desactive el teléfono."</string>
+ <string name="permlab_factoryTest">"ejecutar en modo de prueba de fábrica"</string>
+ <string name="permdesc_factoryTest">"Ejecutar como prueba de fabricante de nivel inferior, permitiendo un acceso íntegro al hardware del teléfono. Sólo está disponible cuando un teléfono se está ejecutando en modo de prueba."</string>
+ <string name="permlab_setWallpaper">"establecer fondo de pantalla"</string>
+ <string name="permdesc_setWallpaper">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
+ <string name="permlab_setWallpaperHints">"establecer el tamaño del fondo de pantalla"</string>
+ <string name="permdesc_setWallpaperHints">"Permite que la aplicación establezca el tamaño del fondo de pantalla del sistema."</string>
+ <string name="permlab_masterClear">"restablecer el sistema a los valores predeterminados de fábrica"</string>
+ <string name="permdesc_masterClear">"Permite que una aplicación restablezca por completo el sistema a su configuración de fábrica, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
+ <string name="permlab_setTimeZone">"establecer zona horaria"</string>
+ <string name="permdesc_setTimeZone">"Permite que una aplicación cambie la zona horaria del teléfono."</string>
+ <string name="permlab_getAccounts">"ver cuentas reconocidas"</string>
+ <string name="permdesc_getAccounts">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
+ <string name="permlab_accessNetworkState">"ver estado de la red"</string>
+ <string name="permdesc_accessNetworkState">"Permite que una aplicación vea el estado de todas las redes."</string>
+ <string name="permlab_createNetworkSockets">"acceso íntegro a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite que una aplicación cree sockets de red."</string>
+ <string name="permlab_writeApnSettings">"escribir la configuración de nombre de punto de acceso"</string>
+ <string name="permdesc_writeApnSettings">"Permite que una aplicación modifique los valores de configuración de un APN como, por ejemplo, el proxy y el puerto de cualquier APN."</string>
+ <string name="permlab_changeNetworkState">"cambiar la conectividad de red"</string>
+ <string name="permdesc_changeNetworkState">"Permite que una aplicación cambie la conectividad de red de estado."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiar configuración de uso de datos de referencia"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite a una aplicación cambiar la configuración de uso de los datos de referencia."</string>
+ <string name="permlab_accessWifiState">"ver estado de la conectividad Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite que una aplicación vea la información sobre el estado de la conectividad Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"cambiar estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite que una aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos, y realice modificaciones en las redes Wi-Fi configuradas."</string>
+ <string name="permlab_changeWifiMulticastState">"permitir recepción multidifusión Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
+ <string name="permlab_bluetoothAdmin">"administración de Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
+ <string name="permlab_bluetooth">"crear conexiones de Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
+ <string name="permlab_disableKeyguard">"inhabilitar bloqueo del teclado"</string>
+ <string name="permdesc_disableKeyguard">"Permite que una aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo legítimo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado cuando recibe una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
+ <string name="permlab_readSyncSettings">"leer la configuración de sincronización"</string>
+ <string name="permdesc_readSyncSettings">"Permite que una aplicación lea la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
+ <string name="permlab_writeSyncSettings">"escribir configuración de sincronización"</string>
+ <string name="permdesc_writeSyncSettings">"Permite que una aplicación modifique la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
+ <string name="permlab_readSyncStats">"leer estadísticas de sincronización"</string>
+ <string name="permdesc_readSyncStats">"Permite que una aplicación lea las estadísticas de sincronización como, por ejemplo, el historial de sincronizaciones que se han realizado."</string>
+ <string name="permlab_subscribedFeedsRead">"leer feeds a los que está suscrito el usuario"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
+ <string name="permlab_subscribedFeedsWrite">"escribir feeds a los que está suscrito el usuario"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"leer diccionario definido por el usuario"</string>
+ <string name="permdesc_readDictionary">"Permite a una aplicación leer cualquier frase, palabra o nombre privado que el usuario haya almacenado en su diccionario."</string>
+ <string name="permlab_writeDictionary">"escribir en el diccionario definido por el usuario"</string>
+ <string name="permdesc_writeDictionary">"Permite a una aplicación escribir palabras nuevas en el diccionario del usuario."</string>
+ <string name="permlab_sdcardWrite">"modificar/eliminar contenido de la tarjeta SD"</string>
+ <string name="permdesc_sdcardWrite">"Permite que una aplicación escriba en la tarjeta SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Casa"</item>
- <item msgid="869923650527136615">"Móvil"</item>
- <item msgid="7897544654242874543">"Trabajo"</item>
- <item msgid="1103601433382158155">"Fax del trabajo"</item>
- <item msgid="1735177144948329370">"Fax de casa"</item>
- <item msgid="603878674477207394">"Buscapersonas"</item>
- <item msgid="1650824275177931637">"Otro"</item>
- <item msgid="9192514806975898961">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Móvil"</item>
+ <item>"Trabajo"</item>
+ <item>"Fax del trabajo"</item>
+ <item>"Fax de casa"</item>
+ <item>"Buscapersonas"</item>
+ <item>"Otro"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Personal"</item>
- <item msgid="7084237356602625604">"Trabajo"</item>
- <item msgid="1112044410659011023">"Otra"</item>
- <item msgid="2374913952870110618">"Personalizar"</item>
+ <item>"Personal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Móvil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Casa"</item>
- <item msgid="5629153956045109251">"Trabajo"</item>
- <item msgid="4966604264500343469">"Otra"</item>
- <item msgid="4932682847595299369">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Casa"</item>
- <item msgid="1359644565647383708">"Trabajo"</item>
- <item msgid="7868549401053615677">"Otro"</item>
- <item msgid="3145118944639869809">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Trabajo"</item>
+ <item>"Otro"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabajo"</item>
- <item msgid="4378074129049520373">"Otra"</item>
- <item msgid="3455047468583965104">"Personalizar"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo!"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo!"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduce el código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"El código PIN es incorrecto."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sin cobertura)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dibujar patrón de desbloqueo"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Inténtalo de nuevo"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Cargado"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Falta la tarjeta SIM"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserta una tarjeta SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Bloqueada para la red"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con el código PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta la guía del usuario o ponte en contacto con el servicio de atención al cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Introduce el código PIN."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Has olvidado el patrón?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Se han realizado demasiados intentos incorrectos de creación del patrón."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear el teléfono, accede a tu cuenta de Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Acceder"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña no válido"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Cargando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Se está agotando la batería:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos del <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"¿Por qué?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Fallo en la prueba de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona \"Aceptar\" para continuar o \"Cancelar\" para permanecer en la página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer información de marcadores y del historial del navegador"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir en marcadores y en el historial del navegador"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
- <string name="save_password_message" msgid="767344687139195790">"¿Deseas que el navegador recuerde esta contraseña?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"No dispones de permiso para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado al portapapeles."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Más"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espacio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"intro"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"suprimir"</string>
- <string name="search_go" msgid="8298016669822141719">"Buscar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
+ <string name="keyguard_password_enter_pin_code">"Introduce el código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"El código PIN es incorrecto."</string>
+ <string name="keyguard_label_text">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
+ <string name="lockscreen_carrier_default">"(Sin cobertura)"</string>
+ <string name="lockscreen_screen_locked">"Pantalla bloqueada"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
+ <string name="lockscreen_pattern_instructions">"Dibujar patrón de desbloqueo"</string>
+ <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
+ <string name="lockscreen_pattern_correct">"Correcto"</string>
+ <string name="lockscreen_pattern_wrong">"Inténtalo de nuevo"</string>
+ <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Conecta el cargador"</string>
+ <string name="lockscreen_missing_sim_message_short">"Falta la tarjeta SIM"</string>
+ <string name="lockscreen_missing_sim_message">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserta una tarjeta SIM."</string>
+ <string name="lockscreen_network_locked_message">"Bloqueada para la red"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La tarjeta SIM está bloqueada con el código PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta la guía del usuario o ponte en contacto con el servicio de atención al cliente."</string>
+ <string name="lockscreen_sim_locked_message">"Introduce el código PIN."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando tarjeta SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"¿Has olvidado el patrón?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Se han realizado demasiados intentos incorrectos de creación del patrón."</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear el teléfono, accede a tu cuenta de Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nombre de usuario (correo electrónico)"</string>
+ <string name="lockscreen_glogin_password_hint">"Contraseña"</string>
+ <string name="lockscreen_glogin_submit_button">"Acceder"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nombre de usuario o contraseña no válido"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"No tienes notificaciones"</string>
+ <string name="status_bar_ongoing_events_title">"Entrante"</string>
+ <string name="status_bar_latest_events_title">"Notificaciones"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Cargando..."</string>
+ <string name="battery_low_title">"Conecta el cargador"</string>
+ <string name="battery_low_subtitle">"Se está agotando la batería:"</string>
+ <string name="battery_low_percent_format">"menos del <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
+ <string name="battery_low_why">"¿Por qué?"</string>
+ <string name="factorytest_failed">"Fallo en la prueba de fábrica"</string>
+ <string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
+ <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona \"Aceptar\" para continuar o \"Cancelar\" para permanecer en la página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
+ <string name="permlab_readHistoryBookmarks">"leer información de marcadores y del historial del navegador"</string>
+ <string name="permdesc_readHistoryBookmarks">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
+ <string name="permlab_writeHistoryBookmarks">"escribir en marcadores y en el historial del navegador"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
+ <string name="save_password_message">"¿Deseas que el navegador recuerde esta contraseña?"</string>
+ <string name="save_password_notnow">"Ahora no"</string>
+ <string name="save_password_remember">"Recordar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"No dispones de permiso para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado al portapapeles."</string>
+ <string name="more_item_label">"Más"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"espacio"</string>
+ <string name="menu_enter_shortcut_label">"intro"</string>
+ <string name="menu_delete_shortcut_label">"suprimir"</string>
+ <string name="search_go">"Buscar"</string>
+ <string name="oneMonthDurationPast">"Hace un mes"</string>
+ <string name="beforeOneMonthDurationPast">"Hace más de un mes"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"Hace 1 segundo"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"Hace 1 minuto"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Hace 1 hora"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"dentro de 1 segundo"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"dentro de 1 minuto"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dentro de 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"dentro de 1 hora"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 minuto"</item>
- <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 minuto"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"dentro de 1 segundo"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"dentro de 1 minuto"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dentro de 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"dentro de 1 hora"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"el %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"a las %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"día"</string>
- <string name="days" msgid="4774547661021344602">"días"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minutos"</string>
- <string name="second" msgid="3184235808021478">"segundos"</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"año"</string>
- <string name="years" msgid="6881577717993213522">"años"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos los días laborables (Lun-Vie)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente, el <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensualmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"No se puede reproducir el vídeo."</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Este vídeo no se puede transmitir al dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Este vídeo no se puede reproducir."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Aceptar"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mediodía"</string>
- <string name="Noon" msgid="3342127745230013127">"Mediodía"</string>
- <string name="midnight" msgid="7166259508850457595">"medianoche"</string>
- <string name="Midnight" msgid="5630806906897892201">"Medianoche"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener selección de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar todo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar todo"</string>
- <string name="paste" msgid="5629880836805036433">"Pegar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de introducción de texto"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Añadir \"%s\" al diccionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Se está agotando el espacio de almacenamiento del teléfono."</string>
- <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
- <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desconectado"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completar acción utilizando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de forma predeterminada para esta acción"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono > Aplicaciones > Administrar aplicaciones\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
- <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
- <string name="aerr_title" msgid="653922989522758100">"Lo sentimos."</string>
- <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
- <string name="aerr_process" msgid="1551785535966089511">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
- <string name="anr_title" msgid="3100070910664756057">"Lo sentimos."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="APPLICATION">%2$s</xliff:g> en aplicación) no está respondiendo."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
- <string name="anr_process" msgid="1246866008169975783">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no está respondiendo."</string>
- <string name="force_close" msgid="3653416315450806396">"Forzar cierre"</string>
- <string name="report" msgid="4060218260984795706">"Informe"</string>
- <string name="wait" msgid="7147118217226317732">"Esperar"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Seleccionar la opción para compartir"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volumen multimedia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduciendo a través de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volumen de la llamada"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen de la llamada de Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volumen de alarma"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volumen de notificaciones"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volumen"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencio"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Tono desconocido"</string>
+ <string name="preposition_for_date">"el %s"</string>
+ <string name="preposition_for_time">"a las %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"día"</string>
+ <string name="days">"días"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minutos"</string>
+ <string name="second">"segundos"</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"año"</string>
+ <string name="years">"años"</string>
+ <string name="every_weekday">"Todos los días laborables (Lun-Vie)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente, el <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensualmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"No se puede reproducir el vídeo."</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Este vídeo no se puede transmitir al dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Este vídeo no se puede reproducir."</string>
+ <string name="VideoView_error_button">"Aceptar"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mediodía"</string>
+ <string name="Noon">"Mediodía"</string>
+ <string name="midnight">"medianoche"</string>
+ <string name="Midnight">"Medianoche"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar todo"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Detener selección de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar todo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar todo"</string>
+ <string name="paste">"Pegar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de introducción de texto"</string>
+ <string name="addToDictionary">"Añadir \"%s\" al diccionario"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Poco espacio"</string>
+ <string name="low_internal_storage_view_text">"Se está agotando el espacio de almacenamiento del teléfono."</string>
+ <string name="ok">"Aceptar"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"Aceptar"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atención"</string>
+ <string name="capital_on">"Activado"</string>
+ <string name="capital_off">"Desconectado"</string>
+ <string name="whichApplication">"Completar acción utilizando"</string>
+ <string name="alwaysUse">"Utilizar de forma predeterminada para esta acción"</string>
+ <string name="clearDefaultHintMsg">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono > Aplicaciones > Administrar aplicaciones\"."</string>
+ <string name="chooseActivity">"Seleccionar una acción"</string>
+ <string name="noApplications">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="aerr_title">"Lo sentimos."</string>
+ <string name="aerr_application">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
+ <string name="aerr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
+ <string name="anr_title">"Lo sentimos."</string>
+ <string name="anr_activity_application">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="APPLICATION">%2$s</xliff:g> en aplicación) no está respondiendo."</string>
+ <string name="anr_activity_process">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
+ <string name="anr_application_process">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
+ <string name="anr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no está respondiendo."</string>
+ <string name="force_close">"Forzar cierre"</string>
+ <string name="report">"Informe"</string>
+ <string name="wait">"Esperar"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Seleccionar la opción para compartir"</string>
+ <string name="volume_ringtone">"Volumen del timbre"</string>
+ <string name="volume_music">"Volumen multimedia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
+ <string name="volume_call">"Volumen de la llamada"</string>
+ <string name="volume_bluetooth_call">"Volumen de la llamada de Bluetooth"</string>
+ <string name="volume_alarm">"Volumen de alarma"</string>
+ <string name="volume_notification">"Volumen de notificaciones"</string>
+ <string name="volume_unknown">"Volumen"</string>
+ <string name="ringtone_default">"Tono predeterminado"</string>
+ <string name="ringtone_default_with_actual">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencio"</string>
+ <string name="ringtone_picker_title">"Tonos"</string>
+ <string name="ringtone_unknown">"Tono desconocido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Red Wi-Fi disponible"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponibles"</item>
+ <item quantity="one">"Red Wi-Fi disponible"</item>
+ <item quantity="other">"Redes Wi-Fi disponibles"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Red Wi-Fi abierta disponible"</item>
- <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abiertas disponibles"</item>
+ <item quantity="one">"Red Wi-Fi abierta disponible"</item>
+ <item quantity="other">"Redes Wi-Fi abiertas disponibles"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicación desconocida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Se ha enviado un número elevado de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para interrumpir el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
- <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Cargando..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Activar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Activar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"No activar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Se ha producido un problema al intentar utilizar la tarjeta SD para el almacenamiento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Conectado por USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Para copiar archivos al/desde el equipo"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar almacenamiento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleccionar para desactivar USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desactivar almacenamiento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar el almacenamiento USB, asegúrate de haber desactivado el host USB. Selecciona \"Desactivar\" para desactivar el almacenamiento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desactivar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Se ha producido un problema al desactivar el almacenamiento USB. Asegúrate de que has desactivado el host USB e inténtalo de nuevo."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de la tarjeta."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Dispositivo de depuración USB conectado"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Hay un equipo conectado al teléfono."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de introducción de texto"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparando tarjeta SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Comprobando errores..."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tarjeta SD vacía"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"La tarjeta SD está vacía o su sistema de archivos es incompatible."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Tarjeta SD dañada"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"La tarjeta SD está dañada. Es posible que sea necesario volver a formatearla."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"La tarjeta SD se ha extraído inesperadamente."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desactiva la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Es seguro extraer la tarjeta SD."</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Puedes extraer la tarjeta SD de forma segura."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"La tarjeta SD se ha extraído. Inserta una nueva."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"No se ha encontrado ninguna actividad coincidente."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar estadísticas de uso de componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Da dos toques para acceder al control de zoom."</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Error al aumentar el widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Buscar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Siguiente"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hecho"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crear un contacto"\n"a partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"seleccionado"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"no seleccionado"</string>
+ <string name="select_character">"Insertar carácter"</string>
+ <string name="sms_control_default_app_name">"Aplicación desconocida"</string>
+ <string name="sms_control_title">"Enviando mensajes SMS..."</string>
+ <string name="sms_control_message">"Se ha enviado un número elevado de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para interrumpir el envío."</string>
+ <string name="sms_control_yes">"Aceptar"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Establecer"</string>
+ <string name="default_permission_group">"Predeterminado"</string>
+ <string name="no_permissions">"No es necesario ningún permiso"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todos"</b></string>
+ <string name="googlewebcontenthelper_loading">"Cargando..."</string>
+ <string name="usb_storage_title">"Conectado por USB"</string>
+ <string name="usb_storage_message">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Activar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
+ <string name="usb_storage_button_mount">"Activar"</string>
+ <string name="usb_storage_button_unmount">"No activar"</string>
+ <string name="usb_storage_error_message">"Se ha producido un problema al intentar utilizar la tarjeta SD para el almacenamiento USB."</string>
+ <string name="usb_storage_notification_title">"Conectado por USB"</string>
+ <string name="usb_storage_notification_message">"Para copiar archivos al/desde el equipo"</string>
+ <string name="usb_storage_stop_notification_title">"Desactivar almacenamiento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleccionar para desactivar USB."</string>
+ <string name="usb_storage_stop_title">"Desactivar almacenamiento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar el almacenamiento USB, asegúrate de haber desactivado el host USB. Selecciona \"Desactivar\" para desactivar el almacenamiento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desactivar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Se ha producido un problema al desactivar el almacenamiento USB. Asegúrate de que has desactivado el host USB e inténtalo de nuevo."</string>
+ <string name="extmedia_format_title">"Formatear tarjeta SD"</string>
+ <string name="extmedia_format_message">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de la tarjeta."</string>
+ <string name="extmedia_format_button_format">"Formato"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Seleccionar método de introducción de texto"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparando tarjeta SD"</string>
+ <string name="ext_media_checking_notification_message">"Comprobando errores..."</string>
+ <string name="ext_media_nofs_notification_title">"Tarjeta SD vacía"</string>
+ <string name="ext_media_nofs_notification_message">"La tarjeta SD está vacía o su sistema de archivos es incompatible."</string>
+ <string name="ext_media_unmountable_notification_title">"Tarjeta SD dañada"</string>
+ <string name="ext_media_unmountable_notification_message">"La tarjeta SD está dañada. Es posible que sea necesario volver a formatearla."</string>
+ <string name="ext_media_badremoval_notification_title">"La tarjeta SD se ha extraído inesperadamente."</string>
+ <string name="ext_media_badremoval_notification_message">"Desactiva la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Es seguro extraer la tarjeta SD."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Puedes extraer la tarjeta SD de forma segura."</string>
+ <string name="ext_media_nomedia_notification_title">"Tarjeta SD extraída"</string>
+ <string name="ext_media_nomedia_notification_message">"La tarjeta SD se ha extraído. Inserta una nueva."</string>
+ <string name="activity_list_empty">"No se ha encontrado ninguna actividad coincidente."</string>
+ <string name="permlab_pkgUsageStats">"actualizar estadísticas de uso de componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Da dos toques para acceder al control de zoom."</string>
+ <string name="gadget_host_error_inflating">"Error al aumentar el widget"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Buscar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Siguiente"</string>
+ <string name="ime_action_done">"Hecho"</string>
+ <string name="ime_action_default">"Ejecutar"</string>
+ <string name="dial_number_using">"Marcar número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crear un contacto"\n"a partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"seleccionado"</string>
+ <string name="accessibility_compound_button_unselected">"no seleccionado"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 865b2d1..ae3c807 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"O"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Ko"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"Mo"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"Go"</string>
- <string name="terabyteShort" msgid="231613018159186962">"To"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"Po"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<sans titre>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Aucun numéro de téléphone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Inconnu)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Messagerie vocale"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problème de connexion ou code IHM non valide."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Le service a été activé."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Ce service a été activé pour :"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Ce service a été désactivé."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Enregistrement réussi."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Effacement réussi."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Le mot de passe est incorrect."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"IHM terminée."</string>
- <string name="badPin" msgid="5085454289896032547">"L\'ancien code PIN saisi est incorrect."</string>
- <string name="badPuk" msgid="5702522162746042460">"La clé PUK saisie est incorrecte."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Les codes PIN saisis ne correspondent pas."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Le code PIN doit compter de 4 à 8 chiffres."</string>
- <string name="needPuk" msgid="919668385956251611">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Numéro de l\'appelant (entrant)"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Numéro de l\'appelant (sortant)"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Transfert d\'appel"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Appel en attente"</string>
- <string name="BaMmi" msgid="455193067926770581">"Interdiction d\'appel"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Modification du mot de passe"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Modification du code PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Présentation du numéro d\'appelant"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numéro de l\'appelant masqué"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Conférence téléphonique à trois"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rejeter les appels indésirables"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Livraison du numéro d\'appel"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Ne pas déranger"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Le paramètre Numéro de l\'appelant ne peut pas être modifié."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Le service vocal/SMS est bloqué."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tous les services vocaux/SMS sont bloqués."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voix"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Données"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"Télécopie"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchrones"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchrones"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquet"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicateur d\'itinérance activé"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicateur d\'itinérance désactivé"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicateur d\'itinérance clignotant"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Hors zone"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Hors du bâtiment"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Itinérance - Système préféré"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Itinérance - Système disponible"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Itinérance - Partenaire Alliance"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Itinérance - Partenaire Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Itinérance - Tous services disponibles"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Itinérance - Services partiellement disponibles"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Bannière d\'itinérance activée"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Bannière d\'itinérance désactivée"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Recherche des services disponibles"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Code de service terminé"</string>
- <string name="fcError" msgid="3327560126588500777">"Problème de connexion ou code de service non valide"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"La page Web contient une erreur."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL introuvable."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Le modèle d\'authentification du site n\'est pas pris en charge."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Échec de l\'authentification."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Échec de l\'authentification par un serveur proxy."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Échec de la connexion au serveur."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Échec de la communication avec le serveur. Veuillez réessayer ultérieurement."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Délai de connexion au serveur dépassé."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Cette page contient trop de redirections de serveurs."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Ce protocole n\'est pas pris en charge."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Aucune connexion sécurisée n\'a pu être établie."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impossible d\'ouvrir cette page. L\'URL n\'est pas correcte."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Impossible d\'accéder au fichier."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Le fichier demandé est introuvable."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchroniser"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
- <string name="low_memory" msgid="6632412458436461203">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
- <string name="me" msgid="6545696007631404292">"Moi"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Options du téléphone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Mode silencieux"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activer le mode sans fil"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Désactiver le mode sans fil"</string>
- <string name="screen_lock" msgid="799094655496098153">"Verrouillage de l\'écran"</string>
- <string name="power_off" msgid="4266614107412865048">"Éteindre"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Aucune application récente"</string>
- <string name="global_actions" msgid="2406416831541615258">"Options du téléphone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silencieux"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Le son est désactivé."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Le son est activé."</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
- <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permet aux applications d\'effectuer des opérations payantes."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vos informations personnelles"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Votre position"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Suivre votre position géographique"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Communications réseau"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permet à des applications d\'accéder à différentes fonctionnalités du réseau."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Vos comptes Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Accédez aux comptes Google disponibles."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Commandes du matériel"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Permet d\'accéder directement au matériel de l\'appareil."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Appels"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Suivre, enregistrer et traiter les appels téléphoniques"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Outils système"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Accès et contrôle de faible niveau du système."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Outils de développement"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Accès à la carte SD"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"Agrandir/réduire la barre d\'état"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permet à l\'application de réduire ou d\'agrandir la barre d\'état."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Interception d\'appels sortants"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permet à l\'application de traiter des appels en cours et de modifier le numéro à composer. Des applications malveillantes peuvent suivre, rediriger ou empêcher des appels sortants."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"Réception de SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller ou effacer vos messages sans que vous les ayez lus."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"Réception des MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller ou effacer vos messages sans que vous les ayez lus."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"Envoi de messages SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"Lecture des SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"Modification de SMS ou de MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permet à une application de modifier des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"Réception de WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permet à l\'application de recevoir et de traiter des messages WAP. Des applications malveillantes peuvent ainsi surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"Récupération des applications en cours d\'exécution"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"Réorganisation des applications en cours d\'exécution"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"Activation du débogage de l\'application"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permet à une application de modifier la configuration actuelle (par ex. : la taille de la police générale ou des paramètres régionaux)."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"Démarrage d\'autres applications"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permet à une application de forcer le lancement d\'autres applications."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"Fermeture forcée de l\'application"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permet à une application de forcer une autre application exécutée au premier plan à se fermer et à passer en arrière-plan. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"Vérification de l\'état interne du système"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permet à l\'application de récupérer l\'état interne du système. Des applications malveillantes peuvent obtenir de nombreuses informations personnelles et sécurisées auxquelles elles ne devraient pas avoir accès."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Empêche l\'utilisateur de changer d\'application."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"Contrôle du lancement des applications"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permet à une application de suivre et de contrôler la façon dont le système lance des activités. Des applications malveillantes peuvent entièrement déstabiliser le système. Cette autorisation est uniquement nécessaire au développement et non pour l\'utilisation normale du téléphone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Envoyer une diffusion sans paquet"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permet à une application de diffuser une notification lorsqu\'un paquet d\'application a été supprimé. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications en cours d\'exécution."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"Envoyer une diffusion reçue par SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permet à une application de diffuser une notification lors de la réception d\'un message SMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour falsifier des messages SMS entrants."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Envoi de diffusion de réception de WAP PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Nombre maximal de processus en cours d\'exécution"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permet à une application de contrôler le nombre de processus maximal exécutés en même temps. Les applications normales n\'ont jamais recours à cette fonctionnalité."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"Fermeture de toutes les applications en tâche de fond"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permet à une application de vérifier si des activités sont systématiquement interrompues lorsqu\'elles sont placées en tâche de fond. Cette fonctionnalité n\'est jamais utilisée par les applications normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"Modification des statistiques de la batterie"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_backup" msgid="470013022865453920">"contrôler la sauvegarde et la restauration du système"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Affichage d\'alertes système"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permet à une application d\'afficher des fenêtres d\'alerte système. Des applications malveillantes peuvent masquer la totalité de l\'écran du téléphone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Réglage de la vitesse des animations"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permet à une application de modifier à tout moment la vitesse générale des animations (pour les rendre plus lentes ou plus rapides)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"Gestion des repères des applications"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permet à des applications de créer et gérer leurs propres jetons en ignorant leur ordre de plan normal. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"Utilisation des touches ou contrôle des commandes"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permet à une application de fournir ses propres commandes (touches enfoncées, etc.) à d\'autres applications. Des applications malveillantes peuvent utiliser cette fonctionnalité pour prendre le contrôle de votre téléphone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"Enregistrer le texte saisi et les actions effectuées"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permet à des applications d\'identifier les touches sur lesquelles vous appuyez même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"Association à un mode de saisie"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permet au support de se connecter à l\'interface de plus haut niveau d\'un mode de saisie. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"Exécution de l\'application en continu"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permet à une application de perdurer en partie afin que le système ne puisse pas l\'utiliser pour d\'autres applications."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"Supprimer des applications"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permet à une application de supprimer des paquets de données Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour supprimer des applications importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"Suppression des données d\'autres applications"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permet à une application d\'effacer les données de l\'utilisateur."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Suppression du cache d\'autres applications"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permet à une application de supprimer des fichiers du cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"Évaluation de l\'espace de stockage de l\'application"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permet à une application de récupérer la taille de son code, de ses données et de son cache."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"Installation directe d\'applications"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permet à une application d\'installer des nouveaux paquets de données ou des mises à jour Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour ajouter de nouvelles applications disposant d\'autorisations anormalement élevées."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"Suppression des données du cache de toutes les applications"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"Lecture des fichiers journaux du système"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"Activer ou désactiver des éléments de l\'application"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"Définition des applications préférées"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permet à une application de modifier vos applications préférées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour modifier discrètement les applications en cours d\'exécution, en imitant vos applications existantes afin de récupérer des données personnelles vous concernant."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"Modification des paramètres généraux du système"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permet à une application de modifier les données des paramètres système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager la configuration de votre système."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"Modifier les paramètres de sécurité du système"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permet à une application de modifier les données des paramètres de sécurité du système. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Modification de la carte des services Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permet à une application de modifier la carte des services Google. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"Lancement automatique au démarrage"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permet à une application de se lancer dès la fin du démarrage du système. Cela peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"Envoi d\'une diffusion persistante"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permet à une application d\'envoyer des diffusions \"persistantes\", qui perdurent après la fin de la diffusion. Des applications malveillantes peuvent ainsi ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Accès aux données des contacts"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permet à une application de lire toutes les données des contacts (adresses) enregistrées sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer vos données à d\'autres personnes."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"Édition des données d\'un contact"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"Édition les données du propriétaire"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permet à une application de modifier les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier ces données."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Lecture des données du propriétaire"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permet à une application de lire les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour lire ces données."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Lecture des données de l\'agenda"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"Écriture des données de l\'agenda"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permet à une application de modifier les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre agenda."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Création de sources de positionnement fictives à des fins de test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Permet de créer des sources de positionnement fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Permet d\'accéder à des commandes de fournisseur de position géographique supplémentaires. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interférer avec l\'utilisation du GPS ou d\'autres sources de positionnement géographique."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localisation OK (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permet d\'accéder à des sources de positionnement précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Position géo. approximative (selon le réseau)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Accès à des sources de positionnement approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Accès à SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permet aux applications de lire/utiliser le contenu de la mémoire tampon graphique."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Modification de vos paramètres audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permet à l\'application de modifier les paramètres audio généraux (p. ex. le volume et le routage)."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"Enregistrement de fichier audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"Prise de photos"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permet à l\'application de prendre des clichés avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Désactivation définitive du téléphone"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"Redémarrage forcé du téléphone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Monter et démonter des systèmes de fichiers"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Formatage du périphérique de stockage externe"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"Contrôle du vibreur"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permet à l\'application de contrôler le vibreur."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Contrôle de la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permet à l\'application de contrôler la lampe de poche."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"Tests du matériel"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"Appel direct des numéros de téléphone"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permet à l\'application d\'appeler des numéros sans votre intervention. Des applications malveillantes peuvent ainsi passer des appels à votre insu qui s\'ajoutent à votre facture téléphonique. Cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"Appel direct de tout numéro de téléphone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permet à une application d\'appeler tout numéro de téléphone (y compris les numéros d\'urgence) sans votre intervention. Des applications malveillantes peuvent passer des appels non nécessaires ou illégitimes à des services d\'urgence."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"Contrôle des notifications de mise à jour de position géo."</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant du signal radio. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"Accès aux propriétés d\'enregistrement"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"choisir les widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permet à l\'application de signaler au système quels widgets peuvent être utilisés par quelle application. Grâce à cette autorisation, les applications peuvent accorder l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Modification de l\'état du téléphone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer le signal radio du téléphone, etc., sans vous en avertir."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"Arrêt du mode veille sur le téléphone"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"Exécution en mode Test d\'usine"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"Configuration du fond d\'écran"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permet à une application de définir le fond d\'écran du système."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Sélection de la la taille du fond d\'écran"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permet à une application de définir la taille du fond d\'écran."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"Réinitialisation du système à ses paramètres d\'usine"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permet à une application de réinitialiser entièrement le système afin de rétablir ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"Sélection du fuseau horaire"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"Identification des comptes connus"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permet à une application d\'obtenir la liste des comptes connus du téléphone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Affichage de l\'état du réseau"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permet à une application d\'afficher l\'état de tous les réseaux."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Accès Internet complet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permet à une application de créer des connecteurs réseau."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Écriture des paramètres \"Nom des points d\'accès\""</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permet à une application de modifier les paramètres APN (Nom des points d\'accès), comme le proxy ou le port de tout APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"Modification de la connectivité du réseau"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permet à une application de modifier la connectivité du réseau."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"modifier le paramètre d\'utilisation des données en arrière-plan"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permet à une application de modifier le paramètre d\'utilisation des données en arrière-plan."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Affichage de l\'état du Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permet à une application d\'afficher des informations concernant l\'état du Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Modifier l\'état du Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Gestion Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Création de connexions Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permet à une application de lire les paramètres de synchronisation (par ex. savoir si la synchronisation est activée pour les Contacts)."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Écriture des paramètres de synchronisation"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permet à une application de modifier les paramètres de synchronisation (p. ex. si la synchronisation est activée pour les contacts)."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Lecture des statistiques de synchronisation"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permet à une application de lire les statistiques de synchronisation (par ex. l\'historique des synchronisations effectuées)."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Lecture des flux auxquels vous êtes abonné"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"Écriture des flux auxquels vous êtes abonné"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"Lecture du dictionnaire défini par l\'utilisateur"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modifier/supprimer le contenu de la carte SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Autorise une application à écrire sur la carte SD."</string>
+ <string name="byteShort">"O"</string>
+ <string name="kilobyteShort">"Ko"</string>
+ <string name="megabyteShort">"Mo"</string>
+ <string name="gigabyteShort">"Go"</string>
+ <string name="terabyteShort">"To"</string>
+ <string name="petabyteShort">"Po"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<sans titre>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Aucun numéro de téléphone)"</string>
+ <string name="unknownName">"(Inconnu)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Messagerie vocale"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problème de connexion ou code IHM non valide."</string>
+ <string name="serviceEnabled">"Le service a été activé."</string>
+ <string name="serviceEnabledFor">"Ce service a été activé pour :"</string>
+ <string name="serviceDisabled">"Ce service a été désactivé."</string>
+ <string name="serviceRegistered">"Enregistrement réussi."</string>
+ <string name="serviceErased">"Effacement réussi."</string>
+ <string name="passwordIncorrect">"Le mot de passe est incorrect."</string>
+ <string name="mmiComplete">"IHM terminée."</string>
+ <string name="badPin">"L\'ancien code PIN saisi est incorrect."</string>
+ <string name="badPuk">"La clé PUK saisie est incorrecte."</string>
+ <string name="mismatchPin">"Les codes PIN saisis ne correspondent pas."</string>
+ <string name="invalidPin">"Le code PIN doit compter de 4 à 8 chiffres."</string>
+ <string name="needPuk">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
+ <string name="needPuk2">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
+ <string name="ClipMmi">"Numéro de l\'appelant (entrant)"</string>
+ <string name="ClirMmi">"Numéro de l\'appelant (sortant)"</string>
+ <string name="CfMmi">"Transfert d\'appel"</string>
+ <string name="CwMmi">"Appel en attente"</string>
+ <string name="BaMmi">"Interdiction d\'appel"</string>
+ <string name="PwdMmi">"Modification du mot de passe"</string>
+ <string name="PinMmi">"Modification du code PIN"</string>
+ <string name="CnipMmi">"Présentation du numéro d\'appelant"</string>
+ <string name="CnirMmi">"Numéro de l\'appelant masqué"</string>
+ <string name="ThreeWCMmi">"Conférence téléphonique à trois"</string>
+ <string name="RuacMmi">"Rejeter les appels indésirables"</string>
+ <string name="CndMmi">"Livraison du numéro d\'appel"</string>
+ <string name="DndMmi">"Ne pas déranger"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
+ <string name="serviceNotProvisioned">"Ce service n\'est pas pris en charge."</string>
+ <string name="CLIRPermanent">"Le paramètre Numéro de l\'appelant ne peut pas être modifié."</string>
+ <string name="RestrictedChangedTitle">"L\'accès limité a été modifié."</string>
+ <string name="RestrictedOnData">"Le service de données est bloqué."</string>
+ <string name="RestrictedOnEmergency">"Le service d\'appel d\'urgence est bloqué."</string>
+ <string name="RestrictedOnNormal">"Le service vocal/SMS est bloqué."</string>
+ <string name="RestrictedOnAll">"Tous les services vocaux/SMS sont bloqués."</string>
+ <string name="serviceClassVoice">"Voix"</string>
+ <string name="serviceClassData">"Données"</string>
+ <string name="serviceClassFAX">"Télécopie"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchrones"</string>
+ <string name="serviceClassDataSync">"Synchrones"</string>
+ <string name="serviceClassPacket">"Paquet"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicateur d\'itinérance activé"</string>
+ <string name="roamingText1">"Indicateur d\'itinérance désactivé"</string>
+ <string name="roamingText2">"Indicateur d\'itinérance clignotant"</string>
+ <string name="roamingText3">"Hors zone"</string>
+ <string name="roamingText4">"Hors du bâtiment"</string>
+ <string name="roamingText5">"Itinérance - Système préféré"</string>
+ <string name="roamingText6">"Itinérance - Système disponible"</string>
+ <string name="roamingText7">"Itinérance - Partenaire Alliance"</string>
+ <string name="roamingText8">"Itinérance - Partenaire Premium"</string>
+ <string name="roamingText9">"Itinérance - Tous services disponibles"</string>
+ <string name="roamingText10">"Itinérance - Services partiellement disponibles"</string>
+ <string name="roamingText11">"Bannière d\'itinérance activée"</string>
+ <string name="roamingText12">"Bannière d\'itinérance désactivée"</string>
+ <string name="roamingTextSearching">"Recherche des services disponibles"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="fcComplete">"Code de service terminé"</string>
+ <string name="fcError">"Problème de connexion ou code de service non valide"</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"La page Web contient une erreur."</string>
+ <string name="httpErrorLookup">"URL introuvable."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Le modèle d\'authentification du site n\'est pas pris en charge."</string>
+ <string name="httpErrorAuth">"Échec de l\'authentification."</string>
+ <string name="httpErrorProxyAuth">"Échec de l\'authentification par un serveur proxy."</string>
+ <string name="httpErrorConnect">"Échec de la connexion au serveur."</string>
+ <string name="httpErrorIO">"Échec de la communication avec le serveur. Veuillez réessayer ultérieurement."</string>
+ <string name="httpErrorTimeout">"Délai de connexion au serveur dépassé."</string>
+ <string name="httpErrorRedirectLoop">"Cette page contient trop de redirections de serveurs."</string>
+ <string name="httpErrorUnsupportedScheme">"Ce protocole n\'est pas pris en charge."</string>
+ <string name="httpErrorFailedSslHandshake">"Aucune connexion sécurisée n\'a pu être établie."</string>
+ <string name="httpErrorBadUrl">"Impossible d\'ouvrir cette page. L\'URL n\'est pas correcte."</string>
+ <string name="httpErrorFile">"Impossible d\'accéder au fichier."</string>
+ <string name="httpErrorFileNotFound">"Le fichier demandé est introuvable."</string>
+ <string name="httpErrorTooManyRequests">"Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement."</string>
+ <string name="contentServiceSync">"Synchroniser"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronisation"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
+ <string name="low_memory">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
+ <string name="me">"Moi"</string>
+ <string name="power_dialog">"Options du téléphone"</string>
+ <string name="silent_mode">"Mode silencieux"</string>
+ <string name="turn_on_radio">"Activer le mode sans fil"</string>
+ <string name="turn_off_radio">"Désactiver le mode sans fil"</string>
+ <string name="screen_lock">"Verrouillage de l\'écran"</string>
+ <string name="power_off">"Éteindre"</string>
+ <string name="shutdown_progress">"Arrêt en cours..."</string>
+ <string name="shutdown_confirm">"Votre téléphone va s\'éteindre."</string>
+ <string name="no_recent_tasks">"Aucune application récente"</string>
+ <string name="global_actions">"Options du téléphone"</string>
+ <string name="global_action_lock">"Verrouillage de l\'écran"</string>
+ <string name="global_action_power_off">"Éteindre"</string>
+ <string name="global_action_toggle_silent_mode">"Mode silencieux"</string>
+ <string name="global_action_silent_mode_on_status">"Le son est désactivé."</string>
+ <string name="global_action_silent_mode_off_status">"Le son est activé."</string>
+ <string name="global_actions_toggle_airplane_mode">"Mode Avion"</string>
+ <string name="global_actions_airplane_mode_on_status">"Le mode Avion est activé."</string>
+ <string name="global_actions_airplane_mode_off_status">"Le mode Avion est désactivé."</string>
+ <string name="safeMode">"Mode sécurisé"</string>
+ <string name="android_system_label">"Système Android"</string>
+ <string name="permgrouplab_costMoney">"Services payants"</string>
+ <string name="permgroupdesc_costMoney">"Permet aux applications d\'effectuer des opérations payantes."</string>
+ <string name="permgrouplab_messages">"Vos messages"</string>
+ <string name="permgroupdesc_messages">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
+ <string name="permgrouplab_personalInfo">"Vos informations personnelles"</string>
+ <string name="permgroupdesc_personalInfo">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
+ <string name="permgrouplab_location">"Votre position"</string>
+ <string name="permgroupdesc_location">"Suivre votre position géographique"</string>
+ <string name="permgrouplab_network">"Communications réseau"</string>
+ <string name="permgroupdesc_network">"Permet à des applications d\'accéder à différentes fonctionnalités du réseau."</string>
+ <string name="permgrouplab_accounts">"Vos comptes Google"</string>
+ <string name="permgroupdesc_accounts">"Accédez aux comptes Google disponibles."</string>
+ <string name="permgrouplab_hardwareControls">"Commandes du matériel"</string>
+ <string name="permgroupdesc_hardwareControls">"Permet d\'accéder directement au matériel de l\'appareil."</string>
+ <string name="permgrouplab_phoneCalls">"Appels"</string>
+ <string name="permgroupdesc_phoneCalls">"Suivre, enregistrer et traiter les appels téléphoniques"</string>
+ <string name="permgrouplab_systemTools">"Outils système"</string>
+ <string name="permgroupdesc_systemTools">"Accès et contrôle de faible niveau du système."</string>
+ <string name="permgrouplab_developmentTools">"Outils de développement"</string>
+ <string name="permgroupdesc_developmentTools">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
+ <string name="permgrouplab_storage">"Stockage"</string>
+ <string name="permgroupdesc_storage">"Accès à la carte SD"</string>
+ <string name="permlab_statusBar">"Désactivation ou modification de la barre d\'état"</string>
+ <string name="permdesc_statusBar">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
+ <string name="permlab_expandStatusBar">"Agrandir/réduire la barre d\'état"</string>
+ <string name="permdesc_expandStatusBar">"Permet à l\'application de réduire ou d\'agrandir la barre d\'état."</string>
+ <string name="permlab_processOutgoingCalls">"Interception d\'appels sortants"</string>
+ <string name="permdesc_processOutgoingCalls">"Permet à l\'application de traiter des appels en cours et de modifier le numéro à composer. Des applications malveillantes peuvent suivre, rediriger ou empêcher des appels sortants."</string>
+ <string name="permlab_receiveSms">"Réception de SMS"</string>
+ <string name="permdesc_receiveSms">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_receiveMms">"Réception des MMS"</string>
+ <string name="permdesc_receiveMms">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_sendSms">"Envoi de messages SMS"</string>
+ <string name="permdesc_sendSms">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
+ <string name="permlab_readSms">"Lecture des SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
+ <string name="permlab_writeSms">"Modification de SMS ou de MMS"</string>
+ <string name="permdesc_writeSms">"Permet à une application de modifier des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
+ <string name="permlab_receiveWapPush">"Réception de WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permet à l\'application de recevoir et de traiter des messages WAP. Des applications malveillantes peuvent ainsi surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
+ <string name="permlab_getTasks">"Récupération des applications en cours d\'exécution"</string>
+ <string name="permdesc_getTasks">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
+ <string name="permlab_reorderTasks">"Réorganisation des applications en cours d\'exécution"</string>
+ <string name="permdesc_reorderTasks">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
+ <string name="permlab_setDebugApp">"Activation du débogage de l\'application"</string>
+ <string name="permdesc_setDebugApp">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
+ <string name="permlab_changeConfiguration">"Modification des paramètres de l\'IU"</string>
+ <string name="permdesc_changeConfiguration">"Permet à une application de modifier la configuration actuelle (par ex. : la taille de la police générale ou des paramètres régionaux)."</string>
+ <string name="permlab_restartPackages">"Démarrage d\'autres applications"</string>
+ <string name="permdesc_restartPackages">"Permet à une application de forcer le lancement d\'autres applications."</string>
+ <string name="permlab_forceBack">"Fermeture forcée de l\'application"</string>
+ <string name="permdesc_forceBack">"Permet à une application de forcer une autre application exécutée au premier plan à se fermer et à passer en arrière-plan. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_dump">"Vérification de l\'état interne du système"</string>
+ <string name="permdesc_dump">"Permet à l\'application de récupérer l\'état interne du système. Des applications malveillantes peuvent obtenir de nombreuses informations personnelles et sécurisées auxquelles elles ne devraient pas avoir accès."</string>
+ <string name="permlab_shutdown">"arrêt partiel"</string>
+ <string name="permdesc_shutdown">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
+ <string name="permlab_stopAppSwitches">"empêcher les changements d\'applications"</string>
+ <string name="permdesc_stopAppSwitches">"Empêche l\'utilisateur de changer d\'application."</string>
+ <string name="permlab_runSetActivityWatcher">"Contrôle du lancement des applications"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permet à une application de suivre et de contrôler la façon dont le système lance des activités. Des applications malveillantes peuvent entièrement déstabiliser le système. Cette autorisation est uniquement nécessaire au développement et non pour l\'utilisation normale du téléphone."</string>
+ <string name="permlab_broadcastPackageRemoved">"Envoyer une diffusion sans paquet"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permet à une application de diffuser une notification lorsqu\'un paquet d\'application a été supprimé. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications en cours d\'exécution."</string>
+ <string name="permlab_broadcastSmsReceived">"Envoyer une diffusion reçue par SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permet à une application de diffuser une notification lors de la réception d\'un message SMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour falsifier des messages SMS entrants."</string>
+ <string name="permlab_broadcastWapPush">"Envoi de diffusion de réception de WAP PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setProcessLimit">"Nombre maximal de processus en cours d\'exécution"</string>
+ <string name="permdesc_setProcessLimit">"Permet à une application de contrôler le nombre de processus maximal exécutés en même temps. Les applications normales n\'ont jamais recours à cette fonctionnalité."</string>
+ <string name="permlab_setAlwaysFinish">"Fermeture de toutes les applications en tâche de fond"</string>
+ <string name="permdesc_setAlwaysFinish">"Permet à une application de vérifier si des activités sont systématiquement interrompues lorsqu\'elles sont placées en tâche de fond. Cette fonctionnalité n\'est jamais utilisée par les applications normales."</string>
+ <string name="permlab_batteryStats">"Modification des statistiques de la batterie"</string>
+ <string name="permdesc_batteryStats">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_backup">"contrôler la sauvegarde et la restauration du système"</string>
+ <string name="permdesc_backup">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
+ <string name="permlab_internalSystemWindow">"Affichage de fenêtres non autorisées"</string>
+ <string name="permdesc_internalSystemWindow">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_systemAlertWindow">"Affichage d\'alertes système"</string>
+ <string name="permdesc_systemAlertWindow">"Permet à une application d\'afficher des fenêtres d\'alerte système. Des applications malveillantes peuvent masquer la totalité de l\'écran du téléphone."</string>
+ <string name="permlab_setAnimationScale">"Réglage de la vitesse des animations"</string>
+ <string name="permdesc_setAnimationScale">"Permet à une application de modifier à tout moment la vitesse générale des animations (pour les rendre plus lentes ou plus rapides)."</string>
+ <string name="permlab_manageAppTokens">"Gestion des repères des applications"</string>
+ <string name="permdesc_manageAppTokens">"Permet à des applications de créer et gérer leurs propres jetons en ignorant leur ordre de plan normal. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_injectEvents">"Utilisation des touches ou contrôle des commandes"</string>
+ <string name="permdesc_injectEvents">"Permet à une application de fournir ses propres commandes (touches enfoncées, etc.) à d\'autres applications. Des applications malveillantes peuvent utiliser cette fonctionnalité pour prendre le contrôle de votre téléphone."</string>
+ <string name="permlab_readInputState">"Enregistrer le texte saisi et les actions effectuées"</string>
+ <string name="permdesc_readInputState">"Permet à des applications d\'identifier les touches sur lesquelles vous appuyez même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindInputMethod">"Association à un mode de saisie"</string>
+ <string name="permdesc_bindInputMethod">"Permet au support de se connecter à l\'interface de plus haut niveau d\'un mode de saisie. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_setOrientation">"Changement d\'orientation de l\'écran"</string>
+ <string name="permdesc_setOrientation">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_signalPersistentProcesses">"Envoi de signaux Linux aux applications"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
+ <string name="permlab_persistentActivity">"Exécution de l\'application en continu"</string>
+ <string name="permdesc_persistentActivity">"Permet à une application de perdurer en partie afin que le système ne puisse pas l\'utiliser pour d\'autres applications."</string>
+ <string name="permlab_deletePackages">"Supprimer des applications"</string>
+ <string name="permdesc_deletePackages">"Permet à une application de supprimer des paquets de données Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour supprimer des applications importantes."</string>
+ <string name="permlab_clearAppUserData">"Suppression des données d\'autres applications"</string>
+ <string name="permdesc_clearAppUserData">"Permet à une application d\'effacer les données de l\'utilisateur."</string>
+ <string name="permlab_deleteCacheFiles">"Suppression du cache d\'autres applications"</string>
+ <string name="permdesc_deleteCacheFiles">"Permet à une application de supprimer des fichiers du cache."</string>
+ <string name="permlab_getPackageSize">"Évaluation de l\'espace de stockage de l\'application"</string>
+ <string name="permdesc_getPackageSize">"Permet à une application de récupérer la taille de son code, de ses données et de son cache."</string>
+ <string name="permlab_installPackages">"Installation directe d\'applications"</string>
+ <string name="permdesc_installPackages">"Permet à une application d\'installer des nouveaux paquets de données ou des mises à jour Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour ajouter de nouvelles applications disposant d\'autorisations anormalement élevées."</string>
+ <string name="permlab_clearAppCache">"Suppression des données du cache de toutes les applications"</string>
+ <string name="permdesc_clearAppCache">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
+ <string name="permlab_readLogs">"Lecture des fichiers journaux du système"</string>
+ <string name="permdesc_readLogs">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
+ <string name="permlab_diagnostic">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
+ <string name="permdesc_diagnostic">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
+ <string name="permlab_changeComponentState">"Activer ou désactiver des éléments de l\'application"</string>
+ <string name="permdesc_changeComponentState">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setPreferredApplications">"Définition des applications préférées"</string>
+ <string name="permdesc_setPreferredApplications">"Permet à une application de modifier vos applications préférées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour modifier discrètement les applications en cours d\'exécution, en imitant vos applications existantes afin de récupérer des données personnelles vous concernant."</string>
+ <string name="permlab_writeSettings">"Modification des paramètres généraux du système"</string>
+ <string name="permdesc_writeSettings">"Permet à une application de modifier les données des paramètres système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager la configuration de votre système."</string>
+ <string name="permlab_writeSecureSettings">"Modifier les paramètres de sécurité du système"</string>
+ <string name="permdesc_writeSecureSettings">"Permet à une application de modifier les données des paramètres de sécurité du système. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_writeGservices">"Modification de la carte des services Google"</string>
+ <string name="permdesc_writeGservices">"Permet à une application de modifier la carte des services Google. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_receiveBootCompleted">"Lancement automatique au démarrage"</string>
+ <string name="permdesc_receiveBootCompleted">"Permet à une application de se lancer dès la fin du démarrage du système. Cela peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
+ <string name="permlab_broadcastSticky">"Envoi d\'une diffusion persistante"</string>
+ <string name="permdesc_broadcastSticky">"Permet à une application d\'envoyer des diffusions \"persistantes\", qui perdurent après la fin de la diffusion. Des applications malveillantes peuvent ainsi ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
+ <string name="permlab_readContacts">"Accès aux données des contacts"</string>
+ <string name="permdesc_readContacts">"Permet à une application de lire toutes les données des contacts (adresses) enregistrées sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer vos données à d\'autres personnes."</string>
+ <string name="permlab_writeContacts">"Édition des données d\'un contact"</string>
+ <string name="permdesc_writeContacts">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
+ <string name="permlab_writeOwnerData">"Édition les données du propriétaire"</string>
+ <string name="permdesc_writeOwnerData">"Permet à une application de modifier les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier ces données."</string>
+ <string name="permlab_readOwnerData">"Lecture des données du propriétaire"</string>
+ <string name="permdesc_readOwnerData">"Permet à une application de lire les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour lire ces données."</string>
+ <string name="permlab_readCalendar">"Lecture des données de l\'agenda"</string>
+ <string name="permdesc_readCalendar">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+ <string name="permlab_writeCalendar">"Écriture des données de l\'agenda"</string>
+ <string name="permdesc_writeCalendar">"Permet à une application de modifier les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre agenda."</string>
+ <string name="permlab_accessMockLocation">"Création de sources de positionnement fictives à des fins de test"</string>
+ <string name="permdesc_accessMockLocation">"Permet de créer des sources de positionnement fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
+ <string name="permlab_accessLocationExtraCommands">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Permet d\'accéder à des commandes de fournisseur de position géographique supplémentaires. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interférer avec l\'utilisation du GPS ou d\'autres sources de positionnement géographique."</string>
+ <string name="permlab_installLocationProvider">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
+ <string name="permdesc_installLocationProvider">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
+ <string name="permlab_accessFineLocation">"Localisation OK (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Permet d\'accéder à des sources de positionnement précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
+ <string name="permlab_accessCoarseLocation">"Position géo. approximative (selon le réseau)"</string>
+ <string name="permdesc_accessCoarseLocation">"Accès à des sources de positionnement approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
+ <string name="permlab_accessSurfaceFlinger">"Accès à SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
+ <string name="permlab_readFrameBuffer">"Lecture de la mémoire tampon graphique"</string>
+ <string name="permdesc_readFrameBuffer">"Permet aux applications de lire/utiliser le contenu de la mémoire tampon graphique."</string>
+ <string name="permlab_modifyAudioSettings">"Modification de vos paramètres audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permet à l\'application de modifier les paramètres audio généraux (p. ex. le volume et le routage)."</string>
+ <string name="permlab_recordAudio">"Enregistrement de fichier audio"</string>
+ <string name="permdesc_recordAudio">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
+ <string name="permlab_camera">"Prise de photos"</string>
+ <string name="permdesc_camera">"Permet à l\'application de prendre des clichés avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
+ <string name="permlab_brick">"Désactivation définitive du téléphone"</string>
+ <string name="permdesc_brick">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
+ <string name="permlab_reboot">"Redémarrage forcé du téléphone"</string>
+ <string name="permdesc_reboot">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
+ <string name="permlab_mount_unmount_filesystems">"Monter et démonter des systèmes de fichiers"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
+ <string name="permlab_mount_format_filesystems">"Formatage du périphérique de stockage externe"</string>
+ <string name="permdesc_mount_format_filesystems">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
+ <string name="permlab_vibrate">"Contrôle du vibreur"</string>
+ <string name="permdesc_vibrate">"Permet à l\'application de contrôler le vibreur."</string>
+ <string name="permlab_flashlight">"Contrôle de la lampe de poche"</string>
+ <string name="permdesc_flashlight">"Permet à l\'application de contrôler la lampe de poche."</string>
+ <string name="permlab_hardware_test">"Tests du matériel"</string>
+ <string name="permdesc_hardware_test">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
+ <string name="permlab_callPhone">"Appel direct des numéros de téléphone"</string>
+ <string name="permdesc_callPhone">"Permet à l\'application d\'appeler des numéros sans votre intervention. Des applications malveillantes peuvent ainsi passer des appels à votre insu qui s\'ajoutent à votre facture téléphonique. Cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
+ <string name="permlab_callPrivileged">"Appel direct de tout numéro de téléphone"</string>
+ <string name="permdesc_callPrivileged">"Permet à une application d\'appeler tout numéro de téléphone (y compris les numéros d\'urgence) sans votre intervention. Des applications malveillantes peuvent passer des appels non nécessaires ou illégitimes à des services d\'urgence."</string>
+ <string name="permlab_locationUpdates">"Contrôle des notifications de mise à jour de position géo."</string>
+ <string name="permdesc_locationUpdates">"Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant du signal radio. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_checkinProperties">"Accès aux propriétés d\'enregistrement"</string>
+ <string name="permdesc_checkinProperties">"Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_bindGadget">"choisir les widgets"</string>
+ <string name="permdesc_bindGadget">"Permet à l\'application de signaler au système quels widgets peuvent être utilisés par quelle application. Grâce à cette autorisation, les applications peuvent accorder l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard."</string>
+ <string name="permlab_modifyPhoneState">"Modification de l\'état du téléphone"</string>
+ <string name="permdesc_modifyPhoneState">"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer le signal radio du téléphone, etc., sans vous en avertir."</string>
+ <string name="permlab_readPhoneState">"Lecture de l\'état du téléphone"</string>
+ <string name="permdesc_readPhoneState">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
+ <string name="permlab_wakeLock">"Arrêt du mode veille sur le téléphone"</string>
+ <string name="permdesc_wakeLock">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
+ <string name="permlab_devicePower">"Éteindre ou allumer le téléphone"</string>
+ <string name="permdesc_devicePower">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
+ <string name="permlab_factoryTest">"Exécution en mode Test d\'usine"</string>
+ <string name="permdesc_factoryTest">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
+ <string name="permlab_setWallpaper">"Configuration du fond d\'écran"</string>
+ <string name="permdesc_setWallpaper">"Permet à une application de définir le fond d\'écran du système."</string>
+ <string name="permlab_setWallpaperHints">"Sélection de la la taille du fond d\'écran"</string>
+ <string name="permdesc_setWallpaperHints">"Permet à une application de définir la taille du fond d\'écran."</string>
+ <string name="permlab_masterClear">"Réinitialisation du système à ses paramètres d\'usine"</string>
+ <string name="permdesc_masterClear">"Permet à une application de réinitialiser entièrement le système afin de rétablir ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
+ <string name="permlab_setTimeZone">"Sélection du fuseau horaire"</string>
+ <string name="permdesc_setTimeZone">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
+ <string name="permlab_getAccounts">"Identification des comptes connus"</string>
+ <string name="permdesc_getAccounts">"Permet à une application d\'obtenir la liste des comptes connus du téléphone."</string>
+ <string name="permlab_accessNetworkState">"Affichage de l\'état du réseau"</string>
+ <string name="permdesc_accessNetworkState">"Permet à une application d\'afficher l\'état de tous les réseaux."</string>
+ <string name="permlab_createNetworkSockets">"Accès Internet complet"</string>
+ <string name="permdesc_createNetworkSockets">"Permet à une application de créer des connecteurs réseau."</string>
+ <string name="permlab_writeApnSettings">"Écriture des paramètres \"Nom des points d\'accès\""</string>
+ <string name="permdesc_writeApnSettings">"Permet à une application de modifier les paramètres APN (Nom des points d\'accès), comme le proxy ou le port de tout APN."</string>
+ <string name="permlab_changeNetworkState">"Modification de la connectivité du réseau"</string>
+ <string name="permdesc_changeNetworkState">"Permet à une application de modifier la connectivité du réseau."</string>
+ <string name="permlab_changeBackgroundDataSetting">"modifier le paramètre d\'utilisation des données en arrière-plan"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permet à une application de modifier le paramètre d\'utilisation des données en arrière-plan."</string>
+ <string name="permlab_accessWifiState">"Affichage de l\'état du Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permet à une application d\'afficher des informations concernant l\'état du Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"Modifier l\'état du Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
+ <string name="permlab_changeWifiMulticastState">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
+ <string name="permdesc_changeWifiMulticastState">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
+ <string name="permlab_bluetoothAdmin">"Gestion Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
+ <string name="permlab_bluetooth">"Création de connexions Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
+ <string name="permlab_disableKeyguard">"Désactivation du verrouillage des touches"</string>
+ <string name="permdesc_disableKeyguard">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
+ <string name="permlab_readSyncSettings">"Lecture des paramètres de synchronisation"</string>
+ <string name="permdesc_readSyncSettings">"Permet à une application de lire les paramètres de synchronisation (par ex. savoir si la synchronisation est activée pour les Contacts)."</string>
+ <string name="permlab_writeSyncSettings">"Écriture des paramètres de synchronisation"</string>
+ <string name="permdesc_writeSyncSettings">"Permet à une application de modifier les paramètres de synchronisation (p. ex. si la synchronisation est activée pour les contacts)."</string>
+ <string name="permlab_readSyncStats">"Lecture des statistiques de synchronisation"</string>
+ <string name="permdesc_readSyncStats">"Permet à une application de lire les statistiques de synchronisation (par ex. l\'historique des synchronisations effectuées)."</string>
+ <string name="permlab_subscribedFeedsRead">"Lecture des flux auxquels vous êtes abonné"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
+ <string name="permlab_subscribedFeedsWrite">"Écriture des flux auxquels vous êtes abonné"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
+ <string name="permlab_readDictionary">"Lecture du dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_readDictionary">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
+ <string name="permlab_writeDictionary">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_writeDictionary">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
+ <string name="permlab_sdcardWrite">"modifier/supprimer le contenu de la carte SD"</string>
+ <string name="permdesc_sdcardWrite">"Autorise une application à écrire sur la carte SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Domicile"</item>
- <item msgid="869923650527136615">"Portable"</item>
- <item msgid="7897544654242874543">"Bureau"</item>
- <item msgid="1103601433382158155">"Télécopie bureau"</item>
- <item msgid="1735177144948329370">"Télécopie domicile"</item>
- <item msgid="603878674477207394">"Récepteur d\'appel"</item>
- <item msgid="1650824275177931637">"Autre"</item>
- <item msgid="9192514806975898961">"Personnalisé"</item>
+ <item>"Domicile"</item>
+ <item>"Portable"</item>
+ <item>"Bureau"</item>
+ <item>"Télécopie bureau"</item>
+ <item>"Télécopie domicile"</item>
+ <item>"Récepteur d\'appel"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisé"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Domicile"</item>
- <item msgid="7084237356602625604">"Bureau"</item>
- <item msgid="1112044410659011023">"Autre"</item>
- <item msgid="2374913952870110618">"Personnalisée"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobile"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Domicile"</item>
- <item msgid="5629153956045109251">"Bureau"</item>
- <item msgid="4966604264500343469">"Autre"</item>
- <item msgid="4932682847595299369">"Personnalisée"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Domicile"</item>
- <item msgid="1359644565647383708">"Bureau"</item>
- <item msgid="7868549401053615677">"Autre"</item>
- <item msgid="3145118944639869809">"Personnalisé"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisé"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Bureau"</item>
- <item msgid="4378074129049520373">"Autre"</item>
- <item msgid="3455047468583965104">"Personnalisée"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Saisissez le code PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Le code PIN est incorrect !"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Aucun service)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Appel d\'urgence"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Combinaison correcte !"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Désolé. Merci de réessayer."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Chargement (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Chargé"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Branchez votre chargeur."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Aucune carte SIM n\'a été trouvée."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Insérez une carte SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Réseau verrouillé"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La carte SIM est verrouillée par clé PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Veuillez consulter le guide d\'utilisation ou contacter l\'assistance clientèle."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carte SIM est verrouillée."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Déblocage de la carte SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Schéma oublié ?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Trop de tentatives !"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Pour déverrouiller le téléphone, connectez-vous à l\'aide de votre compte Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nom d\'utilisateur (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Mot de passe"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Se connecter"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'utilisateur ou mot de passe incorrect."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Chargement..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Branchez le chargeur"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Le niveau de la batterie est bas :"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Batterie restante inférieure à <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Pourquoi ?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Échec du test usine"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Redémarrer"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" affirme :"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Vous souhaitez quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sélectionnez OK pour continuer ou Annuler pour rester sur la page actuelle."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"écrire dans l\'historique et les favoris du navigateur"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
- <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Se souvenir du mot de passe"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Jamais"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Vous n\'êtes pas autorisé à ouvrir cette page."</string>
- <string name="text_copied" msgid="4985729524670131385">"Le texte a été copié dans le presse-papier."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Plus"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espace"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"entrée"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"supprimer"</string>
- <string name="search_go" msgid="8298016669822141719">"Rechercher"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
+ <string name="keyguard_password_enter_pin_code">"Saisissez le code PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Le code PIN est incorrect !"</string>
+ <string name="keyguard_label_text">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numéro d\'urgence"</string>
+ <string name="lockscreen_carrier_default">"(Aucun service)"</string>
+ <string name="lockscreen_screen_locked">"Écran verrouillé"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
+ <string name="lockscreen_pattern_instructions">"Dessinez un schéma pour déverrouiller le téléphone"</string>
+ <string name="lockscreen_emergency_call">"Appel d\'urgence"</string>
+ <string name="lockscreen_pattern_correct">"Combinaison correcte !"</string>
+ <string name="lockscreen_pattern_wrong">"Désolé. Merci de réessayer."</string>
+ <string name="lockscreen_plugged_in">"Chargement (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Branchez votre chargeur."</string>
+ <string name="lockscreen_missing_sim_message_short">"Aucune carte SIM n\'a été trouvée."</string>
+ <string name="lockscreen_missing_sim_message">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Insérez une carte SIM."</string>
+ <string name="lockscreen_network_locked_message">"Réseau verrouillé"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La carte SIM est verrouillée par clé PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Veuillez consulter le guide d\'utilisation ou contacter l\'assistance clientèle."</string>
+ <string name="lockscreen_sim_locked_message">"La carte SIM est verrouillée."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Déblocage de la carte SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Schéma oublié ?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Trop de tentatives !"</string>
+ <string name="lockscreen_glogin_instructions">"Pour déverrouiller le téléphone, connectez-vous à l\'aide de votre compte Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nom d\'utilisateur (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Mot de passe"</string>
+ <string name="lockscreen_glogin_submit_button">"Se connecter"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nom d\'utilisateur ou mot de passe incorrect."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Aucune notification"</string>
+ <string name="status_bar_ongoing_events_title">"En cours"</string>
+ <string name="status_bar_latest_events_title">"Notifications"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Chargement..."</string>
+ <string name="battery_low_title">"Branchez le chargeur"</string>
+ <string name="battery_low_subtitle">"Le niveau de la batterie est bas :"</string>
+ <string name="battery_low_percent_format">"Batterie restante inférieure à <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Pourquoi ?"</string>
+ <string name="factorytest_failed">"Échec du test usine"</string>
+ <string name="factorytest_not_system">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
+ <string name="factorytest_no_action">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Redémarrer"</string>
+ <string name="js_dialog_title">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" affirme :"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Vous souhaitez quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sélectionnez OK pour continuer ou Annuler pour rester sur la page actuelle."</string>
+ <string name="save_password_label">"Confirmer"</string>
+ <string name="permlab_readHistoryBookmarks">"lire l\'historique et les favoris du navigateur"</string>
+ <string name="permdesc_readHistoryBookmarks">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
+ <string name="permlab_writeHistoryBookmarks">"écrire dans l\'historique et les favoris du navigateur"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
+ <string name="save_password_message">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
+ <string name="save_password_notnow">"Pas maintenant"</string>
+ <string name="save_password_remember">"Se souvenir du mot de passe"</string>
+ <string name="save_password_never">"Jamais"</string>
+ <string name="open_permission_deny">"Vous n\'êtes pas autorisé à ouvrir cette page."</string>
+ <string name="text_copied">"Le texte a été copié dans le presse-papier."</string>
+ <string name="more_item_label">"Plus"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espace"</string>
+ <string name="menu_enter_shortcut_label">"entrée"</string>
+ <string name="menu_delete_shortcut_label">"supprimer"</string>
+ <string name="search_go">"Rechercher"</string>
+ <string name="oneMonthDurationPast">"Il y a 1 mois"</string>
+ <string name="beforeOneMonthDurationPast">"Il y a plus d\'un mois"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Il y a 1 seconde"</item>
- <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"Il y a 1 seconde"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"Il y a 1 minute"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"il y a 1 heure"</item>
- <item quantity="other" msgid="2467273239587587569">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"il y a 1 heure"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"hier"</item>
- <item quantity="other" msgid="2479586466153314633">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"hier"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"dans 1 seconde"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"dans 1 minute"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
- <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"dans 1 heure"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"demain"</item>
- <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"demain"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
- <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"il y a 1 seconde"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"il y a 1 minute"</item>
- <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"il y a 1 minute"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"il y a 1 heure"</item>
- <item quantity="other" msgid="6889970745748538901">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"il y a 1 heure"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"hier"</item>
- <item quantity="other" msgid="3453342639616481191">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"hier"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"dans 1 seconde"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
- <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"dans 1 minute"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
- <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"dans 1 heure"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"demain"</item>
- <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"demain"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"à %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"jour"</string>
- <string name="days" msgid="4774547661021344602">"jours"</string>
- <string name="hour" msgid="2126771916426189481">"heure"</string>
- <string name="hours" msgid="894424005266852993">"heures"</string>
- <string name="minute" msgid="9148878657703769868">"mn"</string>
- <string name="minutes" msgid="5646001005827034509">"mn"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"semaine"</string>
- <string name="weeks" msgid="6509623834583944518">"semaines"</string>
- <string name="year" msgid="4001118221013892076">"année"</string>
- <string name="years" msgid="6881577717993213522">"années"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Tous les jours ouvrés (lun.- ven.)"</string>
- <string name="daily" msgid="5738949095624133403">"Tous les jours"</string>
- <string name="weekly" msgid="983428358394268344">"Toutes les semaines le <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Tous les mois"</string>
- <string name="yearly" msgid="1519577999407493836">"Tous les ans"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Échec de la lecture de la vidéo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Désolé, cette vidéo ne peut être lue sur cet appareil."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Désolé, impossible de lire cette vidéo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"midi"</string>
- <string name="Noon" msgid="3342127745230013127">"Midi"</string>
- <string name="midnight" msgid="7166259508850457595">"minuit"</string>
- <string name="Midnight" msgid="5630806906897892201">"Minuit"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string>
- <string name="selectText" msgid="3889149123626888637">"Sélectionner le texte"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Arrêter sélection de texte"</string>
- <string name="cut" msgid="3092569408438626261">"Couper"</string>
- <string name="cutAll" msgid="2436383270024931639">"Tout couper"</string>
- <string name="copy" msgid="2681946229533511987">"Copier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Tout copier"</string>
- <string name="paste" msgid="5629880836805036433">"Coller"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Mode de saisie"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Ajouter \"%s\" au dictionnaire"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Modifier le texte"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Espace disponible faible"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"La mémoire du téléphone commence à être pleine."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuler"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Continuer avec"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil > Applications > Gérer les applications."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Sélectionner une action"</string>
- <string name="noApplications" msgid="1691104391758345586">"Aucune application ne peut effectuer cette action."</string>
- <string name="aerr_title" msgid="653922989522758100">"Désolé !"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu de façon inopinée. Merci de réessayer."</string>
- <string name="anr_title" msgid="3100070910664756057">"Désolé !"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (de l\'application <xliff:g id="APPLICATION">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_process" msgid="1246866008169975783">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas."</string>
- <string name="force_close" msgid="3653416315450806396">"Forcer la fermeture"</string>
- <string name="report" msgid="4060218260984795706">"Rapport"</string>
- <string name="wait" msgid="7147118217226317732">"Attendre"</string>
- <string name="debug" msgid="9103374629678531849">"Débogage"</string>
- <string name="sendText" msgid="5132506121645618310">"Sélectionner une action pour le texte"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Lecture via Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume des appels entrants"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume d\'appels entrants sur Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume des notifications"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencieux"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"à %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"jour"</string>
+ <string name="days">"jours"</string>
+ <string name="hour">"heure"</string>
+ <string name="hours">"heures"</string>
+ <string name="minute">"mn"</string>
+ <string name="minutes">"mn"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"semaine"</string>
+ <string name="weeks">"semaines"</string>
+ <string name="year">"année"</string>
+ <string name="years">"années"</string>
+ <string name="every_weekday">"Tous les jours ouvrés (lun.- ven.)"</string>
+ <string name="daily">"Tous les jours"</string>
+ <string name="weekly">"Toutes les semaines le <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Tous les mois"</string>
+ <string name="yearly">"Tous les ans"</string>
+ <string name="VideoView_error_title">"Échec de la lecture de la vidéo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Désolé, cette vidéo ne peut être lue sur cet appareil."</string>
+ <string name="VideoView_error_text_unknown">"Désolé, impossible de lire cette vidéo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"midi"</string>
+ <string name="Noon">"Midi"</string>
+ <string name="midnight">"minuit"</string>
+ <string name="Midnight">"Minuit"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Tout sélectionner"</string>
+ <string name="selectText">"Sélectionner le texte"</string>
+ <string name="stopSelectingText">"Arrêter sélection de texte"</string>
+ <string name="cut">"Couper"</string>
+ <string name="cutAll">"Tout couper"</string>
+ <string name="copy">"Copier"</string>
+ <string name="copyAll">"Tout copier"</string>
+ <string name="paste">"Coller"</string>
+ <string name="copyUrl">"Copier l\'URL"</string>
+ <string name="inputMethod">"Mode de saisie"</string>
+ <string name="addToDictionary">"Ajouter \"%s\" au dictionnaire"</string>
+ <string name="editTextMenuTitle">"Modifier le texte"</string>
+ <string name="low_internal_storage_view_title">"Espace disponible faible"</string>
+ <string name="low_internal_storage_view_text">"La mémoire du téléphone commence à être pleine."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuler"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuler"</string>
+ <string name="dialog_alert_title">"Attention"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"Continuer avec"</string>
+ <string name="alwaysUse">"Utiliser cette application par défaut pour cette action"</string>
+ <string name="clearDefaultHintMsg">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil > Applications > Gérer les applications."</string>
+ <string name="chooseActivity">"Sélectionner une action"</string>
+ <string name="noApplications">"Aucune application ne peut effectuer cette action."</string>
+ <string name="aerr_title">"Désolé !"</string>
+ <string name="aerr_application">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
+ <string name="aerr_process">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu de façon inopinée. Merci de réessayer."</string>
+ <string name="anr_title">"Désolé !"</string>
+ <string name="anr_activity_application">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (de l\'application <xliff:g id="APPLICATION">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_activity_process">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_application_process">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_process">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas."</string>
+ <string name="force_close">"Forcer la fermeture"</string>
+ <string name="report">"Rapport"</string>
+ <string name="wait">"Attendre"</string>
+ <string name="debug">"Débogage"</string>
+ <string name="sendText">"Sélectionner une action pour le texte"</string>
+ <string name="volume_ringtone">"Volume de la sonnerie"</string>
+ <string name="volume_music">"Volume"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Lecture via Bluetooth"</string>
+ <string name="volume_call">"Volume des appels entrants"</string>
+ <string name="volume_bluetooth_call">"Volume d\'appels entrants sur Bluetooth"</string>
+ <string name="volume_alarm">"Volume"</string>
+ <string name="volume_notification">"Volume des notifications"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Sonnerie par défaut"</string>
+ <string name="ringtone_default_with_actual">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencieux"</string>
+ <string name="ringtone_picker_title">"Sonneries"</string>
+ <string name="ringtone_unknown">"Sonnerie inconnue"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Réseau Wi-Fi disponible"</item>
- <item quantity="other" msgid="4192424489168397386">"Réseaux Wi-Fi disponibles"</item>
+ <item quantity="one">"Réseau Wi-Fi disponible"</item>
+ <item quantity="other">"Réseaux Wi-Fi disponibles"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Réseau Wi-Fi ouvert disponible"</item>
- <item quantity="other" msgid="7915895323644292768">"Réseaux Wi-Fi ouverts disponibles"</item>
+ <item quantity="one">"Réseau Wi-Fi ouvert disponible"</item>
+ <item quantity="other">"Réseaux Wi-Fi ouverts disponibles"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Application inconnue"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Vous êtes sur le point d\'envoyer un grand nombre de messages SMS. Sélectionnez OK pour continuer ou Annuler pour interrompre l\'envoi."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuler"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Définir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Par défaut"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Masquer"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Tout afficher"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Chargement..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Connecté à l\'aide d\'un câble USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez Monter pour copier des fichiers de votre ordinateur vers votre carte SD, ou inversement."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Monter"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Ne pas monter"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Un problème est survenu lors de l\'utilisation de votre carte SD en tant que périphérique de stockage USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Connecté avec un câble USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Activez pour copier des fichiers vers/de votre ordinateur."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Sélectionner pour éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Avant d\'éteindre le périphérique de stockage USB, assurez-vous d\'avoir désactivé l\'hôte USB. Sélectionnez \"Éteindre\" pour éteindre le périphérique de stockage USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Éteindre"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuler"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Un problème est survenu lors de la mise hors tension du périphérique de stockage USB. Assurez-vous que l\'hôte USB a bien été désactivé, puis essayez à nouveau."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formater la carte SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Voulez-vous vraiment formater la carte SD ? Toutes les données de cette carte seront perdues."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Un ordinateur est connecté à votre téléphone."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Sélectionner un mode de saisie"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Préparation de la carte SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Recherche d\'erreurs"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Carte SD vide"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Carte SD endommagée"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Carte SD retirée inopinément"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"La carte SD peut être retirée en toute sécurité"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Vous pouvez retirer la carte SD en toute sécurité."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Carte SD manquante"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"La carte SD a été retirée. Insérez-en une autre."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Aucune activité correspondante trouvée"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"mettre à jour les données statistiques du composant"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permet de modifier les données statistiques collectées du composant. Cette option n\'est pas utilisée par les applications standard."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erreur lors de l\'agrandissement du widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Rechercher"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Envoyer"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Suivant"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"OK"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Exécuter"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Composer le numéro"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Ajouter un contact"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"sélectionné"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"non sélectionné"</string>
+ <string name="select_character">"Insérer un caractère"</string>
+ <string name="sms_control_default_app_name">"Application inconnue"</string>
+ <string name="sms_control_title">"Envoi de messages SMS"</string>
+ <string name="sms_control_message">"Vous êtes sur le point d\'envoyer un grand nombre de messages SMS. Sélectionnez OK pour continuer ou Annuler pour interrompre l\'envoi."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuler"</string>
+ <string name="date_time_set">"Définir"</string>
+ <string name="default_permission_group">"Par défaut"</string>
+ <string name="no_permissions">"Aucune autorisation requise"</string>
+ <string name="perms_hide"><b>"Masquer"</b></string>
+ <string name="perms_show_all"><b>"Tout afficher"</b></string>
+ <string name="googlewebcontenthelper_loading">"Chargement..."</string>
+ <string name="usb_storage_title">"Connecté à l\'aide d\'un câble USB"</string>
+ <string name="usb_storage_message">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez Monter pour copier des fichiers de votre ordinateur vers votre carte SD, ou inversement."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Ne pas monter"</string>
+ <string name="usb_storage_error_message">"Un problème est survenu lors de l\'utilisation de votre carte SD en tant que périphérique de stockage USB."</string>
+ <string name="usb_storage_notification_title">"Connecté avec un câble USB"</string>
+ <string name="usb_storage_notification_message">"Activez pour copier des fichiers vers/de votre ordinateur."</string>
+ <string name="usb_storage_stop_notification_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_notification_message">"Sélectionner pour éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_message">"Avant d\'éteindre le périphérique de stockage USB, assurez-vous d\'avoir désactivé l\'hôte USB. Sélectionnez \"Éteindre\" pour éteindre le périphérique de stockage USB."</string>
+ <string name="usb_storage_stop_button_mount">"Éteindre"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuler"</string>
+ <string name="usb_storage_stop_error_message">"Un problème est survenu lors de la mise hors tension du périphérique de stockage USB. Assurez-vous que l\'hôte USB a bien été désactivé, puis essayez à nouveau."</string>
+ <string name="extmedia_format_title">"Formater la carte SD"</string>
+ <string name="extmedia_format_message">"Voulez-vous vraiment formater la carte SD ? Toutes les données de cette carte seront perdues."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Sélectionner un mode de saisie"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidats"</u></string>
+ <string name="ext_media_checking_notification_title">"Préparation de la carte SD"</string>
+ <string name="ext_media_checking_notification_message">"Recherche d\'erreurs"</string>
+ <string name="ext_media_nofs_notification_title">"Carte SD vide"</string>
+ <string name="ext_media_nofs_notification_message">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
+ <string name="ext_media_unmountable_notification_title">"Carte SD endommagée"</string>
+ <string name="ext_media_unmountable_notification_message">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
+ <string name="ext_media_badremoval_notification_title">"Carte SD retirée inopinément"</string>
+ <string name="ext_media_badremoval_notification_message">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
+ <string name="ext_media_safe_unmount_notification_title">"La carte SD peut être retirée en toute sécurité"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Vous pouvez retirer la carte SD en toute sécurité."</string>
+ <string name="ext_media_nomedia_notification_title">"Carte SD manquante"</string>
+ <string name="ext_media_nomedia_notification_message">"La carte SD a été retirée. Insérez-en une autre."</string>
+ <string name="activity_list_empty">"Aucune activité correspondante trouvée"</string>
+ <string name="permlab_pkgUsageStats">"mettre à jour les données statistiques du composant"</string>
+ <string name="permdesc_pkgUsageStats">"Permet de modifier les données statistiques collectées du composant. Cette option n\'est pas utilisée par les applications standard."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Appuyer deux fois pour régler le zoom"</string>
+ <string name="gadget_host_error_inflating">"Erreur lors de l\'agrandissement du widget"</string>
+ <string name="ime_action_go">"OK"</string>
+ <string name="ime_action_search">"Rechercher"</string>
+ <string name="ime_action_send">"Envoyer"</string>
+ <string name="ime_action_next">"Suivant"</string>
+ <string name="ime_action_done">"OK"</string>
+ <string name="ime_action_default">"Exécuter"</string>
+ <string name="dial_number_using">"Composer le numéro"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Ajouter un contact"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"sélectionné"</string>
+ <string name="accessibility_compound_button_unselected">"non sélectionné"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9ccc6f3..778faac 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<senza nome>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nessun numero di telefono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Sconosciuto)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Segreteria"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema di connessione o codice MMI non valido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Il servizio è stato attivato."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Il servizio è stato attivato per:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Il servizio è stato disattivato."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrazione effettuata."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Eliminazione effettuata."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Password errata."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completo."</string>
- <string name="badPin" msgid="5085454289896032547">"Il PIN attuale digitato è errato."</string>
- <string name="badPuk" msgid="5702522162746042460">"Il PUK digitato è errato."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"I PIN inseriti non corrispondono."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Il PIN deve essere di 4-8 numeri."</string>
- <string name="needPuk" msgid="919668385956251611">"La SIM è bloccata tramite PUK. Digita il codice PUK per sbloccarla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digita il PUK2 per sbloccare la SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID chiamante in entrata"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID chiamante in uscita"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Deviazione chiamate"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Avviso di chiamata"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blocco chiamate"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Modifica password"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Modifica PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Numero chiamante presente"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numero chiamante con restrizioni"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Chiamata a tre"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rifiuto di chiamate fastidiose non desiderate"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Recapito numero chiamante"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Non disturbare"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID chiamante generalmente limitato. Prossima chiamata: limitato"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID chiamante generalmente limitato. Prossima chiamata: non limitato"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID chiamante generalmente non limitato. Prossima chiamata: limitato"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizio non fornito."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Impossibile modificare l\'impostazione dell\'ID del chiamante."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accesso limitato modificato"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Il servizio dati è bloccato."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servizio di emergenza è bloccato."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Il servizio vocale/SMS è bloccato."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tutti i servizi vocali/SMS sono bloccati."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voce"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dati"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asinc"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sinc"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacchetto"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicatore roaming attivato"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicatore roaming disattivato"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicatore roaming lampeggiante"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Fuori dal vicinato"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Fuori dall\'edificio"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Sistema preferito"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Sistema disponibile"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Partner Alliance"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Partner Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Funzionalità servizio completo"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Funzionalità servizio parziale"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner roaming attivato"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner roaming disattivato"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Ricerca servizio"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Codice funzione completo."</string>
- <string name="fcError" msgid="3327560126588500777">"Problema di connessione o codice funzione non valido."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"La pagina web contiene un errore."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Impossibile trovare l\'URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schema di autenticazione del sito non supportato."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Autenticazione non riuscita."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autenticazione tramite il server proxy non riuscita."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Connessione al server non riuscita."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Impossibile comunicare con il server. Riprova più tardi."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Tempo esaurito per la connessione al server."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La pagina contiene troppi reindirizzamenti sul server."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protocollo non supportato."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Impossibile stabilire una connessione protetta."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impossibile aprire la pagina. URL non valido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Impossibile accedere al file."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Impossibile trovare il file richiesto."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Troppe richieste in fase di elaborazione. Riprova più tardi."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sinc"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizzazione"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
- <string name="me" msgid="6545696007631404292">"Io"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opzioni telefono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modalità silenziosa"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Attiva wireless"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Disattiva wireless"</string>
- <string name="screen_lock" msgid="799094655496098153">"Blocco schermo"</string>
- <string name="power_off" msgid="4266614107412865048">"Spegni"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Il telefono verrà spento."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nessuna applicazione recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opzioni telefono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modalità silenziosa"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Audio non attivo"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Audio attivo"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo attiva"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servizi che prevedono un costo"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Consentono alle applicazioni di svolgere operazioni che possono comportare un costo."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"I tuoi messaggi"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leggere e scrivere SMS, email e altri messaggi."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Informazioni personali"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accedere direttamente ai contatti e al calendario memorizzati sul telefono."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"La tua posizione"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorare la posizione fisica dell\'utente"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicazione di rete"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Consentono l\'accesso delle applicazioni a varie funzionalità di rete."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"I tuoi account Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Accedere agli account Google disponibili."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlli hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Accedere direttamente all\'hardware del ricevitore."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonate"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorare, registrare ed elaborare le telefonate."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Strumenti di sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Accesso al sistema e controllo di livello inferiore."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Strumenti di sviluppo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funzionalità necessarie soltanto agli sviluppatori di applicazioni."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Archiviazione"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Accesso alla scheda SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"espansione/compressione barra di stato"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Consente all\'applicazione di espandere o comprimere la barra di stato."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"intercettazione chiamate in uscita"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Le applicazioni dannose potrebbero monitorare, deviare o impedire le chiamate in uscita."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"ricezione SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Consente il ricevimento e l\'elaborazione di SMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"ricezione MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Consente il ricevimento e l\'elaborazione di MMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"invio SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Consente all\'applicazione di inviare messaggi SMS. Le applicazioni dannose potrebbero inviare messaggi a tua insaputa facendoti sostenere dei costi."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"lettura SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Consente all\'applicazione di leggere SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero leggere messaggi riservati."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"modifica SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Consente all\'applicazione di rispondere a SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero eliminare i messaggi."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"ricezione WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Consente il ricevimento e l\'elaborazione di messaggi WAP da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recupero applicazioni in esecuzione"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"riordinamento applicazioni in esecuz."</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"attivazione debug delle applicazioni"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Consente a un\'applicazione di modificare la configurazione corrente, come le dimensioni dei caratteri locali o complessive."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"riavvio altre applicazioni"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Consente a un\'applicazione di riavviare forzatamente altre applicazioni."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"chiusura forzata dell\'applicazione"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Consente a un\'applicazione di forzare la chiusura di attività in primo piano. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recupero stato interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Consente all\'applicazione di recuperare lo stato interno del sistema. Le applicazioni dannose potrebbero recuperare molte informazioni riservate e protette di cui non dovrebbero avere mai bisogno."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"chiusura parziale"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitoraggio e controllo avvio applicazioni"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Consente a un\'applicazione di monitorare e controllare la modalità di avvio delle attività nel sistema. Le applicazioni dannose potrebbero compromettere totalmente il sistema. Questa autorizzazione è necessaria soltanto per lo sviluppo, mai per il normale utilizzo del telefono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"invio broadcast rimossi dal pacchetto"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Consente a un\'applicazione di trasmettere una notifica di rimozione del pacchetto di un\'applicazione. Le applicazioni dannose potrebbero sfruttare questa possibilità per interrompere ogni altra applicazione in esecuzione."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"invio broadcast ricevuti tramite SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un SMS. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che siano stati ricevuti SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"invio broadcast ricevuti tramite WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente contenuti di pagine web con varianti dannose."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"numero limite di processi in esecuzione"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Consente a un\'applicazione di stabilire il numero massimo di processi in esecuzione. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"chiusura applicazioni in background"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Consente a un\'applicazione di controllare se le attività sono sempre completate quando vengono messe in secondo piano. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modifica statistiche batteria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
- <string name="permlab_backup" msgid="470013022865453920">"controllo del backup di sistema e ripristino"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Consente all\'applicazione di controllare i backup dei sistemi e il meccanismo di ripristino. Da non usare per normali applicazioni."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualizzazione finestre non autorizzate"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visualizzazione avvisi di sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Consente a un\'applicazione di visualizzare finestre di avviso del sistema. Le applicazioni dannose possono sfruttare questa opzione per riempire lo schermo del telefono di messaggi."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modifica velocità di animazione globale"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Consente a un\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gestione token applicazioni"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Consente alle applicazioni di creare e gestire i propri token, ignorando il normale ordinamento Z. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"uso tasti e pulsanti di controllo"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Consente a un\'applicazione di offrire i suoi eventi di input (pressioni di tasti etc.) ad altre applicazioni. Le applicazioni dannose possono sfruttare questa possibilità per assumere il controllo del telefono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrazione testo digitato e azioni eseguite"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Consente il rilevamento da parte delle applicazioni dei tasti premuti anche durante l\'interazione con un\'altra applicazione (come nel caso di inserimento di una password). Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"associaz. a un metodo di inserimento"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Consente l\'associazione all\'interfaccia principale di un metodo di inserimento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"invio segnali Linuz alle applicazioni"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"esecuzione permanente delle applicazioni"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Consente a un\'applicazione di rendere delle sue parti costanti in modo che il sistema non possa usarla per altre applicazioni."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminazione applicazioni"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Consente a un\'applicazione di eliminare pacchetti Android. Le applicazioni dannose possono sfruttare questa possibilità per eliminare importanti applicazioni."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminazione dati di altre applicazioni"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Consente a un\'applicazione di cancellare dati dell\'utente."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminazione cache altre applicazioni"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Consente a un\'applicazione di eliminare file della cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"calcolo spazio di archiviazione applicazioni"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Consente a un\'applicazione di recuperare i suoi codici, dati e dimensioni della cache"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installazione diretta di applicazioni"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Consente a un\'applicazione di installare nuovi pacchetti Android o aggiornamenti. Le applicazioni dannose possono sfruttare questa possibilità per aggiungere nuove applicazioni con potenti autorizzazioni arbitrarie."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminazione dati della cache applicazioni"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"lettura file di registro sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"attivazione/disattivazione componenti applicazioni"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Consente a un\'applicazione di attivare o disattivare un componente di un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per disattivare importanti funzionalità del telefono. Prestare attenzione con questa autorizzazione perché è possibile rendere inutilizzabili, incoerenti o instabili i componenti delle applicazioni."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"impostazione applicazioni preferite"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Consente la modifica da parte di un\'applicazione delle applicazioni preferite. Le applicazioni dannose potrebbero essere in grado di modificare automaticamente le applicazioni in esecuzione, effettuando lo spoofing delle applicazioni esistenti per raccogliere dati riservati."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modifica impostazioni di sistema globali"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Consente la modifica in un\'applicazione dei dati delle impostazioni del sistema. Le applicazioni dannose possono danneggiare la configurazione del sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificare le impostazioni di protezione del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Consente a un\'applicazione di modificare i dati delle impostazioni di protezione del sistema. Da non usare per normali applicazioni."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modifica mappa servizi Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Consente a un\'applicazione di modificare la mappa dei servizi Google. Da non usare per normali applicazioni."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"apertura automatica all\'avvio"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Consente a un\'applicazione di aprirsi automaticamente al termine dell\'avvio del sistema. Potrebbe essere necessario più tempo per l\'avvio del telefono e l\'applicazione potrebbe rallentare tutte le funzioni del telefono rimanendo sempre in esecuzione."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"invio broadcast permanenti"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Consente a un\'applicazione di inviare broadcast permanenti, che permangono anche al termine del broadcast. Le applicazioni dannose possono rendere il telefono lento o instabile tramite un uso eccessivo della memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"lettura dati di contatto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Consente la lettura da parte di un\'applicazione di tutti i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i dati ad altre persone."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"scrittura dati di contatto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Consente a un\'applicazione di modificare i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati di contatto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"scrittura dati proprietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Consente a un\'applicazione di modificare i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare tali dati."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"lettura dati proprietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Consente a un\'applicazione di leggere i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per leggere tali dati."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"lettura dati di calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Consente la lettura da parte di un\'applicazione di tutti gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i tuoi eventi di calendario ad altre persone."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"scrittura dati di calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Consente a un\'applicazione di modificare gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di localizzazione fittizie per test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Accedere a comandi aggiuntivi del provider di localizzazione. Le applicazioni dannose possono sfruttare questa possibilità per interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autorizzazione a installare un provider di localizzazione"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete oppure per monitorare e segnalare la tua posizione a una fonte esterna."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"localizzazione precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Consente l\'accesso a fonti di localizzazione precisa, come il sistema GPS del telefono, se disponibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare la tua posizione e, nel farlo, far esaurire più in fretta la batteria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"localizzazione approssimativa (basata sulla rete)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Consente l\'accesso a fonti di localizzazione geografica non puntuale (come il database della rete cellulare) per determinare una posizione approssimativa del telefono, quando possibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare approssimativamente dove ti trovi."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"accesso a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Consente l\'utilizzo dell\'applicazione di funzioni di basso livello SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Consente la lettura da parte dell\'applicazione dei contenuti del buffer di frame."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Consente all\'applicazione di modificare impostazioni audio globali come volume e routing."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Consente l\'accesso dell\'applicazione al percorso di registrazione dell\'audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"acquisizione foto"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Consente di scattare foto nell\'applicazione con la fotocamera. L\'applicazione può acquisire in qualsiasi momento le immagini rilevate dalla fotocamera."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"disattivazione telefono"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Consente all\'applicazione di disattivare l\'intero telefono in modo definitivo. Questa autorizzazione è molto pericolosa."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"riavvio forzato del telefono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Consente all\'applicazione di imporre il riavvio del telefono."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"installazione/disinstallazione filesystem"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Consente montaggio e smontaggio da parte dell\'applicazione dei filesystem degli archivi rimovibili."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formattazione archivio esterno"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Consente all\'applicazione di formattare l\'archivio rimovibile."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controllo vibrazione"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Consente all\'applicazione di controllare la vibrazione."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Consente all\'applicazione di controllare il flash."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"esecuzione test hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Consente all\'applicazione di chiamare numeri automaticamente. Le applicazioni dannose potrebbero far risultare chiamate impreviste sulla bolletta telefonica. Questa autorizzazione non consente all\'applicazione di chiamare numeri di emergenza."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"chiamata diretta di tutti i n. telefono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Consente all\'applicazione di chiamare qualsiasi numero, compresi quelli di emergenza, automaticamente. Le applicazioni dannose potrebbero effettuare chiamate non necessarie e illegali a servizi di emergenza."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controllo notifiche aggiornamento posizione"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"accesso a proprietà di archiviazione"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"scegliere widget"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Consente all\'applicazione di indicare al sistema quali widget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modifica stato del telefono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Consente a un\'applicazione di impedire lo stand-by del telefono."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"accensione o spegnimento del telefono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Consente all\'applicazione di accendere o spegnere il telefono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"esecuzione in modalità test di fabbrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"In esecuzione come test del produttore di basso livello, consentendo l\'accesso completo all\'hardware del telefono. Disponibile soltanto quando il telefono è in esecuzione in modalità test del produttore."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"impostazione sfondo"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Consente all\'applicazione di impostare lo sfondo del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"impostaz. suggerimenti dimensioni sfondo"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Consente all\'applicazione di impostare i suggerimenti per le dimensioni dello sfondo del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"ripristino impostazioni predef. di fabbrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Consente a un\'applicazione di ripristinare le impostazioni di fabbrica del sistema, eliminando tutti i dati, le configurazioni e le applicazioni installate."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"impostazione fuso orario"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Consente a un\'applicazione di modificare il fuso orario del telefono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"rilevamento account noti"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Consente a un\'applicazione di recuperare l\'elenco di account memorizzati sul telefono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"visualizzazione stato della rete"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Consente a un\'applicazione di visualizzare lo stato di tutte le reti."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"accesso completo a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Consente a un\'applicazione di creare socket di rete."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"scrittura impostazioni APN"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Consente a un\'applicazione di modificare le impostazioni APN, come proxy e porta di qualsiasi APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifica connettività di rete"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Consente a un\'applicazione di modificare lo stato di connettività di rete."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiare l\'impostazione di utilizzo dei dati in background"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Consente a un\'applicazione di cambiare l\'impostazione di utilizzo dei dati in background."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visualizzazione stato Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della connessione Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"modifica stato Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"consenti ricezione multicast Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Consente a un\'applicazione di ricevere pacchetti non direttamente indirizzati al tuo dispositivo. Può essere utile durante la ricerca di servizi offerti nelle vicinanze. Consuma di più rispetto alla modalità non multicast."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"gestione Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"creazione connessioni Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"disattivazione blocco tastiera"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Consente a un\'applicazione di leggere le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"scrittura impostazioni di sincronizz."</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"lettura statistiche di sincronizz."</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione, per esempio la cronologia delle sincronizzazioni effettuate."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"scrittura feed sottoscritti"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"lettura dizionario definito dall\'utente"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Consente a un\'applicazione di leggere parole, nomi e frasi private che l\'utente potrebbe aver memorizzato nel dizionario utente."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"scrittura nel dizionario definito dall\'utente"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Consente a un\'applicazione di scrivere nuove parole nel dizionario utente."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modificare/eliminare i contenuti della scheda SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Consente a un\'applicazione di scrivere sulla scheda SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<senza nome>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nessun numero di telefono)"</string>
+ <string name="unknownName">"(Sconosciuto)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Segreteria"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema di connessione o codice MMI non valido."</string>
+ <string name="serviceEnabled">"Il servizio è stato attivato."</string>
+ <string name="serviceEnabledFor">"Il servizio è stato attivato per:"</string>
+ <string name="serviceDisabled">"Il servizio è stato disattivato."</string>
+ <string name="serviceRegistered">"Registrazione effettuata."</string>
+ <string name="serviceErased">"Eliminazione effettuata."</string>
+ <string name="passwordIncorrect">"Password errata."</string>
+ <string name="mmiComplete">"MMI completo."</string>
+ <string name="badPin">"Il PIN attuale digitato è errato."</string>
+ <string name="badPuk">"Il PUK digitato è errato."</string>
+ <string name="mismatchPin">"I PIN inseriti non corrispondono."</string>
+ <string name="invalidPin">"Il PIN deve essere di 4-8 numeri."</string>
+ <string name="needPuk">"La SIM è bloccata tramite PUK. Digita il codice PUK per sbloccarla."</string>
+ <string name="needPuk2">"Digita il PUK2 per sbloccare la SIM."</string>
+ <string name="ClipMmi">"ID chiamante in entrata"</string>
+ <string name="ClirMmi">"ID chiamante in uscita"</string>
+ <string name="CfMmi">"Deviazione chiamate"</string>
+ <string name="CwMmi">"Avviso di chiamata"</string>
+ <string name="BaMmi">"Blocco chiamate"</string>
+ <string name="PwdMmi">"Modifica password"</string>
+ <string name="PinMmi">"Modifica PIN"</string>
+ <string name="CnipMmi">"Numero chiamante presente"</string>
+ <string name="CnirMmi">"Numero chiamante con restrizioni"</string>
+ <string name="ThreeWCMmi">"Chiamata a tre"</string>
+ <string name="RuacMmi">"Rifiuto di chiamate fastidiose non desiderate"</string>
+ <string name="CndMmi">"Recapito numero chiamante"</string>
+ <string name="DndMmi">"Non disturbare"</string>
+ <string name="CLIRDefaultOnNextCallOn">"ID chiamante generalmente limitato. Prossima chiamata: limitato"</string>
+ <string name="CLIRDefaultOnNextCallOff">"ID chiamante generalmente limitato. Prossima chiamata: non limitato"</string>
+ <string name="CLIRDefaultOffNextCallOn">"ID chiamante generalmente non limitato. Prossima chiamata: limitato"</string>
+ <string name="CLIRDefaultOffNextCallOff">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
+ <string name="serviceNotProvisioned">"Servizio non fornito."</string>
+ <string name="CLIRPermanent">"Impossibile modificare l\'impostazione dell\'ID del chiamante."</string>
+ <string name="RestrictedChangedTitle">"Accesso limitato modificato"</string>
+ <string name="RestrictedOnData">"Il servizio dati è bloccato."</string>
+ <string name="RestrictedOnEmergency">"Il servizio di emergenza è bloccato."</string>
+ <string name="RestrictedOnNormal">"Il servizio vocale/SMS è bloccato."</string>
+ <string name="RestrictedOnAll">"Tutti i servizi vocali/SMS sono bloccati."</string>
+ <string name="serviceClassVoice">"Voce"</string>
+ <string name="serviceClassData">"Dati"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asinc"</string>
+ <string name="serviceClassDataSync">"Sinc"</string>
+ <string name="serviceClassPacket">"Pacchetto"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicatore roaming attivato"</string>
+ <string name="roamingText1">"Indicatore roaming disattivato"</string>
+ <string name="roamingText2">"Indicatore roaming lampeggiante"</string>
+ <string name="roamingText3">"Fuori dal vicinato"</string>
+ <string name="roamingText4">"Fuori dall\'edificio"</string>
+ <string name="roamingText5">"Roaming - Sistema preferito"</string>
+ <string name="roamingText6">"Roaming - Sistema disponibile"</string>
+ <string name="roamingText7">"Roaming - Partner Alliance"</string>
+ <string name="roamingText8">"Roaming - Partner Premium"</string>
+ <string name="roamingText9">"Roaming - Funzionalità servizio completo"</string>
+ <string name="roamingText10">"Roaming - Funzionalità servizio parziale"</string>
+ <string name="roamingText11">"Banner roaming attivato"</string>
+ <string name="roamingText12">"Banner roaming disattivato"</string>
+ <string name="roamingTextSearching">"Ricerca servizio"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="fcComplete">"Codice funzione completo."</string>
+ <string name="fcError">"Problema di connessione o codice funzione non valido."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"La pagina web contiene un errore."</string>
+ <string name="httpErrorLookup">"Impossibile trovare l\'URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schema di autenticazione del sito non supportato."</string>
+ <string name="httpErrorAuth">"Autenticazione non riuscita."</string>
+ <string name="httpErrorProxyAuth">"Autenticazione tramite il server proxy non riuscita."</string>
+ <string name="httpErrorConnect">"Connessione al server non riuscita."</string>
+ <string name="httpErrorIO">"Impossibile comunicare con il server. Riprova più tardi."</string>
+ <string name="httpErrorTimeout">"Tempo esaurito per la connessione al server."</string>
+ <string name="httpErrorRedirectLoop">"La pagina contiene troppi reindirizzamenti sul server."</string>
+ <string name="httpErrorUnsupportedScheme">"Protocollo non supportato."</string>
+ <string name="httpErrorFailedSslHandshake">"Impossibile stabilire una connessione protetta."</string>
+ <string name="httpErrorBadUrl">"Impossibile aprire la pagina. URL non valido."</string>
+ <string name="httpErrorFile">"Impossibile accedere al file."</string>
+ <string name="httpErrorFileNotFound">"Impossibile trovare il file richiesto."</string>
+ <string name="httpErrorTooManyRequests">"Troppe richieste in fase di elaborazione. Riprova più tardi."</string>
+ <string name="contentServiceSync">"Sinc"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronizzazione"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
+ <string name="me">"Io"</string>
+ <string name="power_dialog">"Opzioni telefono"</string>
+ <string name="silent_mode">"Modalità silenziosa"</string>
+ <string name="turn_on_radio">"Attiva wireless"</string>
+ <string name="turn_off_radio">"Disattiva wireless"</string>
+ <string name="screen_lock">"Blocco schermo"</string>
+ <string name="power_off">"Spegni"</string>
+ <string name="shutdown_progress">"Spegnimento..."</string>
+ <string name="shutdown_confirm">"Il telefono verrà spento."</string>
+ <string name="no_recent_tasks">"Nessuna applicazione recente."</string>
+ <string name="global_actions">"Opzioni telefono"</string>
+ <string name="global_action_lock">"Blocco schermo"</string>
+ <string name="global_action_power_off">"Spegni"</string>
+ <string name="global_action_toggle_silent_mode">"Modalità silenziosa"</string>
+ <string name="global_action_silent_mode_on_status">"Audio non attivo"</string>
+ <string name="global_action_silent_mode_off_status">"Audio attivo"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modalità aereo attiva"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modalità aereo attiva"</string>
+ <string name="global_actions_airplane_mode_off_status">"Modalità aereo non attiva"</string>
+ <string name="safeMode">"Modalità provvisoria"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Servizi che prevedono un costo"</string>
+ <string name="permgroupdesc_costMoney">"Consentono alle applicazioni di svolgere operazioni che possono comportare un costo."</string>
+ <string name="permgrouplab_messages">"I tuoi messaggi"</string>
+ <string name="permgroupdesc_messages">"Leggere e scrivere SMS, email e altri messaggi."</string>
+ <string name="permgrouplab_personalInfo">"Informazioni personali"</string>
+ <string name="permgroupdesc_personalInfo">"Accedere direttamente ai contatti e al calendario memorizzati sul telefono."</string>
+ <string name="permgrouplab_location">"La tua posizione"</string>
+ <string name="permgroupdesc_location">"Monitorare la posizione fisica dell\'utente"</string>
+ <string name="permgrouplab_network">"Comunicazione di rete"</string>
+ <string name="permgroupdesc_network">"Consentono l\'accesso delle applicazioni a varie funzionalità di rete."</string>
+ <string name="permgrouplab_accounts">"I tuoi account Google"</string>
+ <string name="permgroupdesc_accounts">"Accedere agli account Google disponibili."</string>
+ <string name="permgrouplab_hardwareControls">"Controlli hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Accedere direttamente all\'hardware del ricevitore."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonate"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorare, registrare ed elaborare le telefonate."</string>
+ <string name="permgrouplab_systemTools">"Strumenti di sistema"</string>
+ <string name="permgroupdesc_systemTools">"Accesso al sistema e controllo di livello inferiore."</string>
+ <string name="permgrouplab_developmentTools">"Strumenti di sviluppo"</string>
+ <string name="permgroupdesc_developmentTools">"Funzionalità necessarie soltanto agli sviluppatori di applicazioni."</string>
+ <string name="permgrouplab_storage">"Archiviazione"</string>
+ <string name="permgroupdesc_storage">"Accesso alla scheda SD."</string>
+ <string name="permlab_statusBar">"disattivare o modificare la barra di stato"</string>
+ <string name="permdesc_statusBar">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
+ <string name="permlab_expandStatusBar">"espansione/compressione barra di stato"</string>
+ <string name="permdesc_expandStatusBar">"Consente all\'applicazione di espandere o comprimere la barra di stato."</string>
+ <string name="permlab_processOutgoingCalls">"intercettazione chiamate in uscita"</string>
+ <string name="permdesc_processOutgoingCalls">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Le applicazioni dannose potrebbero monitorare, deviare o impedire le chiamate in uscita."</string>
+ <string name="permlab_receiveSms">"ricezione SMS"</string>
+ <string name="permdesc_receiveSms">"Consente il ricevimento e l\'elaborazione di SMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_receiveMms">"ricezione MMS"</string>
+ <string name="permdesc_receiveMms">"Consente il ricevimento e l\'elaborazione di MMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_sendSms">"invio SMS"</string>
+ <string name="permdesc_sendSms">"Consente all\'applicazione di inviare messaggi SMS. Le applicazioni dannose potrebbero inviare messaggi a tua insaputa facendoti sostenere dei costi."</string>
+ <string name="permlab_readSms">"lettura SMS o MMS"</string>
+ <string name="permdesc_readSms">"Consente all\'applicazione di leggere SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero leggere messaggi riservati."</string>
+ <string name="permlab_writeSms">"modifica SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Consente all\'applicazione di rispondere a SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero eliminare i messaggi."</string>
+ <string name="permlab_receiveWapPush">"ricezione WAP"</string>
+ <string name="permdesc_receiveWapPush">"Consente il ricevimento e l\'elaborazione di messaggi WAP da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_getTasks">"recupero applicazioni in esecuzione"</string>
+ <string name="permdesc_getTasks">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
+ <string name="permlab_reorderTasks">"riordinamento applicazioni in esecuz."</string>
+ <string name="permdesc_reorderTasks">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
+ <string name="permlab_setDebugApp">"attivazione debug delle applicazioni"</string>
+ <string name="permdesc_setDebugApp">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
+ <string name="permlab_changeConfiguration">"modifica impostazioni UI"</string>
+ <string name="permdesc_changeConfiguration">"Consente a un\'applicazione di modificare la configurazione corrente, come le dimensioni dei caratteri locali o complessive."</string>
+ <string name="permlab_restartPackages">"riavvio altre applicazioni"</string>
+ <string name="permdesc_restartPackages">"Consente a un\'applicazione di riavviare forzatamente altre applicazioni."</string>
+ <string name="permlab_forceBack">"chiusura forzata dell\'applicazione"</string>
+ <string name="permdesc_forceBack">"Consente a un\'applicazione di forzare la chiusura di attività in primo piano. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_dump">"recupero stato interno del sistema"</string>
+ <string name="permdesc_dump">"Consente all\'applicazione di recuperare lo stato interno del sistema. Le applicazioni dannose potrebbero recuperare molte informazioni riservate e protette di cui non dovrebbero avere mai bisogno."</string>
+ <string name="permlab_shutdown">"chiusura parziale"</string>
+ <string name="permdesc_shutdown">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
+ <string name="permlab_stopAppSwitches">"impedire commutazione applicazione"</string>
+ <string name="permdesc_stopAppSwitches">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
+ <string name="permlab_runSetActivityWatcher">"monitoraggio e controllo avvio applicazioni"</string>
+ <string name="permdesc_runSetActivityWatcher">"Consente a un\'applicazione di monitorare e controllare la modalità di avvio delle attività nel sistema. Le applicazioni dannose potrebbero compromettere totalmente il sistema. Questa autorizzazione è necessaria soltanto per lo sviluppo, mai per il normale utilizzo del telefono."</string>
+ <string name="permlab_broadcastPackageRemoved">"invio broadcast rimossi dal pacchetto"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Consente a un\'applicazione di trasmettere una notifica di rimozione del pacchetto di un\'applicazione. Le applicazioni dannose potrebbero sfruttare questa possibilità per interrompere ogni altra applicazione in esecuzione."</string>
+ <string name="permlab_broadcastSmsReceived">"invio broadcast ricevuti tramite SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un SMS. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che siano stati ricevuti SMS."</string>
+ <string name="permlab_broadcastWapPush">"invio broadcast ricevuti tramite WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente contenuti di pagine web con varianti dannose."</string>
+ <string name="permlab_setProcessLimit">"numero limite di processi in esecuzione"</string>
+ <string name="permdesc_setProcessLimit">"Consente a un\'applicazione di stabilire il numero massimo di processi in esecuzione. Mai necessario per le normali applicazioni."</string>
+ <string name="permlab_setAlwaysFinish">"chiusura applicazioni in background"</string>
+ <string name="permdesc_setAlwaysFinish">"Consente a un\'applicazione di controllare se le attività sono sempre completate quando vengono messe in secondo piano. Mai necessario per le normali applicazioni."</string>
+ <string name="permlab_batteryStats">"modifica statistiche batteria"</string>
+ <string name="permdesc_batteryStats">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
+ <string name="permlab_backup">"controllo del backup di sistema e ripristino"</string>
+ <string name="permdesc_backup">"Consente all\'applicazione di controllare i backup dei sistemi e il meccanismo di ripristino. Da non usare per normali applicazioni."</string>
+ <string name="permlab_internalSystemWindow">"visualizzazione finestre non autorizzate"</string>
+ <string name="permdesc_internalSystemWindow">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
+ <string name="permlab_systemAlertWindow">"visualizzazione avvisi di sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Consente a un\'applicazione di visualizzare finestre di avviso del sistema. Le applicazioni dannose possono sfruttare questa opzione per riempire lo schermo del telefono di messaggi."</string>
+ <string name="permlab_setAnimationScale">"modifica velocità di animazione globale"</string>
+ <string name="permdesc_setAnimationScale">"Consente a un\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
+ <string name="permlab_manageAppTokens">"gestione token applicazioni"</string>
+ <string name="permdesc_manageAppTokens">"Consente alle applicazioni di creare e gestire i propri token, ignorando il normale ordinamento Z. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_injectEvents">"uso tasti e pulsanti di controllo"</string>
+ <string name="permdesc_injectEvents">"Consente a un\'applicazione di offrire i suoi eventi di input (pressioni di tasti etc.) ad altre applicazioni. Le applicazioni dannose possono sfruttare questa possibilità per assumere il controllo del telefono."</string>
+ <string name="permlab_readInputState">"registrazione testo digitato e azioni eseguite"</string>
+ <string name="permdesc_readInputState">"Consente il rilevamento da parte delle applicazioni dei tasti premuti anche durante l\'interazione con un\'altra applicazione (come nel caso di inserimento di una password). Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_bindInputMethod">"associaz. a un metodo di inserimento"</string>
+ <string name="permdesc_bindInputMethod">"Consente l\'associazione all\'interfaccia principale di un metodo di inserimento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_setOrientation">"modifica orientamento dello schermo"</string>
+ <string name="permdesc_setOrientation">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_signalPersistentProcesses">"invio segnali Linuz alle applicazioni"</string>
+ <string name="permdesc_signalPersistentProcesses">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
+ <string name="permlab_persistentActivity">"esecuzione permanente delle applicazioni"</string>
+ <string name="permdesc_persistentActivity">"Consente a un\'applicazione di rendere delle sue parti costanti in modo che il sistema non possa usarla per altre applicazioni."</string>
+ <string name="permlab_deletePackages">"eliminazione applicazioni"</string>
+ <string name="permdesc_deletePackages">"Consente a un\'applicazione di eliminare pacchetti Android. Le applicazioni dannose possono sfruttare questa possibilità per eliminare importanti applicazioni."</string>
+ <string name="permlab_clearAppUserData">"eliminazione dati di altre applicazioni"</string>
+ <string name="permdesc_clearAppUserData">"Consente a un\'applicazione di cancellare dati dell\'utente."</string>
+ <string name="permlab_deleteCacheFiles">"eliminazione cache altre applicazioni"</string>
+ <string name="permdesc_deleteCacheFiles">"Consente a un\'applicazione di eliminare file della cache."</string>
+ <string name="permlab_getPackageSize">"calcolo spazio di archiviazione applicazioni"</string>
+ <string name="permdesc_getPackageSize">"Consente a un\'applicazione di recuperare i suoi codici, dati e dimensioni della cache"</string>
+ <string name="permlab_installPackages">"installazione diretta di applicazioni"</string>
+ <string name="permdesc_installPackages">"Consente a un\'applicazione di installare nuovi pacchetti Android o aggiornamenti. Le applicazioni dannose possono sfruttare questa possibilità per aggiungere nuove applicazioni con potenti autorizzazioni arbitrarie."</string>
+ <string name="permlab_clearAppCache">"eliminazione dati della cache applicazioni"</string>
+ <string name="permdesc_clearAppCache">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
+ <string name="permlab_readLogs">"lettura file di registro sistema"</string>
+ <string name="permdesc_readLogs">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
+ <string name="permlab_diagnostic">"lettura/scrittura risorse di proprietà di diag"</string>
+ <string name="permdesc_diagnostic">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
+ <string name="permlab_changeComponentState">"attivazione/disattivazione componenti applicazioni"</string>
+ <string name="permdesc_changeComponentState">"Consente a un\'applicazione di attivare o disattivare un componente di un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per disattivare importanti funzionalità del telefono. Prestare attenzione con questa autorizzazione perché è possibile rendere inutilizzabili, incoerenti o instabili i componenti delle applicazioni."</string>
+ <string name="permlab_setPreferredApplications">"impostazione applicazioni preferite"</string>
+ <string name="permdesc_setPreferredApplications">"Consente la modifica da parte di un\'applicazione delle applicazioni preferite. Le applicazioni dannose potrebbero essere in grado di modificare automaticamente le applicazioni in esecuzione, effettuando lo spoofing delle applicazioni esistenti per raccogliere dati riservati."</string>
+ <string name="permlab_writeSettings">"modifica impostazioni di sistema globali"</string>
+ <string name="permdesc_writeSettings">"Consente la modifica in un\'applicazione dei dati delle impostazioni del sistema. Le applicazioni dannose possono danneggiare la configurazione del sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificare le impostazioni di protezione del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Consente a un\'applicazione di modificare i dati delle impostazioni di protezione del sistema. Da non usare per normali applicazioni."</string>
+ <string name="permlab_writeGservices">"modifica mappa servizi Google"</string>
+ <string name="permdesc_writeGservices">"Consente a un\'applicazione di modificare la mappa dei servizi Google. Da non usare per normali applicazioni."</string>
+ <string name="permlab_receiveBootCompleted">"apertura automatica all\'avvio"</string>
+ <string name="permdesc_receiveBootCompleted">"Consente a un\'applicazione di aprirsi automaticamente al termine dell\'avvio del sistema. Potrebbe essere necessario più tempo per l\'avvio del telefono e l\'applicazione potrebbe rallentare tutte le funzioni del telefono rimanendo sempre in esecuzione."</string>
+ <string name="permlab_broadcastSticky">"invio broadcast permanenti"</string>
+ <string name="permdesc_broadcastSticky">"Consente a un\'applicazione di inviare broadcast permanenti, che permangono anche al termine del broadcast. Le applicazioni dannose possono rendere il telefono lento o instabile tramite un uso eccessivo della memoria."</string>
+ <string name="permlab_readContacts">"lettura dati di contatto"</string>
+ <string name="permdesc_readContacts">"Consente la lettura da parte di un\'applicazione di tutti i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i dati ad altre persone."</string>
+ <string name="permlab_writeContacts">"scrittura dati di contatto"</string>
+ <string name="permdesc_writeContacts">"Consente a un\'applicazione di modificare i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati di contatto."</string>
+ <string name="permlab_writeOwnerData">"scrittura dati proprietario"</string>
+ <string name="permdesc_writeOwnerData">"Consente a un\'applicazione di modificare i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare tali dati."</string>
+ <string name="permlab_readOwnerData">"lettura dati proprietario"</string>
+ <string name="permdesc_readOwnerData">"Consente a un\'applicazione di leggere i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per leggere tali dati."</string>
+ <string name="permlab_readCalendar">"lettura dati di calendario"</string>
+ <string name="permdesc_readCalendar">"Consente la lettura da parte di un\'applicazione di tutti gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i tuoi eventi di calendario ad altre persone."</string>
+ <string name="permlab_writeCalendar">"scrittura dati di calendario"</string>
+ <string name="permdesc_writeCalendar">"Consente a un\'applicazione di modificare gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del calendario."</string>
+ <string name="permlab_accessMockLocation">"fonti di localizzazione fittizie per test"</string>
+ <string name="permdesc_accessMockLocation">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete."</string>
+ <string name="permlab_accessLocationExtraCommands">"accesso a comandi aggiuntivi del provider di localizz."</string>
+ <string name="permdesc_accessLocationExtraCommands">"Accedere a comandi aggiuntivi del provider di localizzazione. Le applicazioni dannose possono sfruttare questa possibilità per interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+ <string name="permlab_installLocationProvider">"autorizzazione a installare un provider di localizzazione"</string>
+ <string name="permdesc_installLocationProvider">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete oppure per monitorare e segnalare la tua posizione a una fonte esterna."</string>
+ <string name="permlab_accessFineLocation">"localizzazione precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Consente l\'accesso a fonti di localizzazione precisa, come il sistema GPS del telefono, se disponibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare la tua posizione e, nel farlo, far esaurire più in fretta la batteria."</string>
+ <string name="permlab_accessCoarseLocation">"localizzazione approssimativa (basata sulla rete)"</string>
+ <string name="permdesc_accessCoarseLocation">"Consente l\'accesso a fonti di localizzazione geografica non puntuale (come il database della rete cellulare) per determinare una posizione approssimativa del telefono, quando possibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare approssimativamente dove ti trovi."</string>
+ <string name="permlab_accessSurfaceFlinger">"accesso a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Consente l\'utilizzo dell\'applicazione di funzioni di basso livello SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"lettura buffer di frame"</string>
+ <string name="permdesc_readFrameBuffer">"Consente la lettura da parte dell\'applicazione dei contenuti del buffer di frame."</string>
+ <string name="permlab_modifyAudioSettings">"modifica impostazioni audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Consente all\'applicazione di modificare impostazioni audio globali come volume e routing."</string>
+ <string name="permlab_recordAudio">"registrazione audio"</string>
+ <string name="permdesc_recordAudio">"Consente l\'accesso dell\'applicazione al percorso di registrazione dell\'audio."</string>
+ <string name="permlab_camera">"acquisizione foto"</string>
+ <string name="permdesc_camera">"Consente di scattare foto nell\'applicazione con la fotocamera. L\'applicazione può acquisire in qualsiasi momento le immagini rilevate dalla fotocamera."</string>
+ <string name="permlab_brick">"disattivazione telefono"</string>
+ <string name="permdesc_brick">"Consente all\'applicazione di disattivare l\'intero telefono in modo definitivo. Questa autorizzazione è molto pericolosa."</string>
+ <string name="permlab_reboot">"riavvio forzato del telefono"</string>
+ <string name="permdesc_reboot">"Consente all\'applicazione di imporre il riavvio del telefono."</string>
+ <string name="permlab_mount_unmount_filesystems">"installazione/disinstallazione filesystem"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Consente montaggio e smontaggio da parte dell\'applicazione dei filesystem degli archivi rimovibili."</string>
+ <string name="permlab_mount_format_filesystems">"formattazione archivio esterno"</string>
+ <string name="permdesc_mount_format_filesystems">"Consente all\'applicazione di formattare l\'archivio rimovibile."</string>
+ <string name="permlab_vibrate">"controllo vibrazione"</string>
+ <string name="permdesc_vibrate">"Consente all\'applicazione di controllare la vibrazione."</string>
+ <string name="permlab_flashlight">"controllo flash"</string>
+ <string name="permdesc_flashlight">"Consente all\'applicazione di controllare il flash."</string>
+ <string name="permlab_hardware_test">"esecuzione test hardware"</string>
+ <string name="permdesc_hardware_test">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
+ <string name="permlab_callPhone">"chiamata diretta n. telefono"</string>
+ <string name="permdesc_callPhone">"Consente all\'applicazione di chiamare numeri automaticamente. Le applicazioni dannose potrebbero far risultare chiamate impreviste sulla bolletta telefonica. Questa autorizzazione non consente all\'applicazione di chiamare numeri di emergenza."</string>
+ <string name="permlab_callPrivileged">"chiamata diretta di tutti i n. telefono"</string>
+ <string name="permdesc_callPrivileged">"Consente all\'applicazione di chiamare qualsiasi numero, compresi quelli di emergenza, automaticamente. Le applicazioni dannose potrebbero effettuare chiamate non necessarie e illegali a servizi di emergenza."</string>
+ <string name="permlab_locationUpdates">"controllo notifiche aggiornamento posizione"</string>
+ <string name="permdesc_locationUpdates">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."</string>
+ <string name="permlab_checkinProperties">"accesso a proprietà di archiviazione"</string>
+ <string name="permdesc_checkinProperties">"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."</string>
+ <string name="permlab_bindGadget">"scegliere widget"</string>
+ <string name="permdesc_bindGadget">"Consente all\'applicazione di indicare al sistema quali widget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni."</string>
+ <string name="permlab_modifyPhoneState">"modifica stato del telefono"</string>
+ <string name="permdesc_modifyPhoneState">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica."</string>
+ <string name="permlab_readPhoneState">"lettura stato del telefono"</string>
+ <string name="permdesc_readPhoneState">"Consente l\'accesso dell\'applicazione alle funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può determinare il numero del telefono in uso, se una chiamata è attiva o meno, il numero a cui è collegata la chiamata e simili."</string>
+ <string name="permlab_wakeLock">"disattivazione stand-by del telefono"</string>
+ <string name="permdesc_wakeLock">"Consente a un\'applicazione di impedire lo stand-by del telefono."</string>
+ <string name="permlab_devicePower">"accensione o spegnimento del telefono"</string>
+ <string name="permdesc_devicePower">"Consente all\'applicazione di accendere o spegnere il telefono."</string>
+ <string name="permlab_factoryTest">"esecuzione in modalità test di fabbrica"</string>
+ <string name="permdesc_factoryTest">"In esecuzione come test del produttore di basso livello, consentendo l\'accesso completo all\'hardware del telefono. Disponibile soltanto quando il telefono è in esecuzione in modalità test del produttore."</string>
+ <string name="permlab_setWallpaper">"impostazione sfondo"</string>
+ <string name="permdesc_setWallpaper">"Consente all\'applicazione di impostare lo sfondo del sistema."</string>
+ <string name="permlab_setWallpaperHints">"impostaz. suggerimenti dimensioni sfondo"</string>
+ <string name="permdesc_setWallpaperHints">"Consente all\'applicazione di impostare i suggerimenti per le dimensioni dello sfondo del sistema."</string>
+ <string name="permlab_masterClear">"ripristino impostazioni predef. di fabbrica"</string>
+ <string name="permdesc_masterClear">"Consente a un\'applicazione di ripristinare le impostazioni di fabbrica del sistema, eliminando tutti i dati, le configurazioni e le applicazioni installate."</string>
+ <string name="permlab_setTimeZone">"impostazione fuso orario"</string>
+ <string name="permdesc_setTimeZone">"Consente a un\'applicazione di modificare il fuso orario del telefono."</string>
+ <string name="permlab_getAccounts">"rilevamento account noti"</string>
+ <string name="permdesc_getAccounts">"Consente a un\'applicazione di recuperare l\'elenco di account memorizzati sul telefono."</string>
+ <string name="permlab_accessNetworkState">"visualizzazione stato della rete"</string>
+ <string name="permdesc_accessNetworkState">"Consente a un\'applicazione di visualizzare lo stato di tutte le reti."</string>
+ <string name="permlab_createNetworkSockets">"accesso completo a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Consente a un\'applicazione di creare socket di rete."</string>
+ <string name="permlab_writeApnSettings">"scrittura impostazioni APN"</string>
+ <string name="permdesc_writeApnSettings">"Consente a un\'applicazione di modificare le impostazioni APN, come proxy e porta di qualsiasi APN."</string>
+ <string name="permlab_changeNetworkState">"modifica connettività di rete"</string>
+ <string name="permdesc_changeNetworkState">"Consente a un\'applicazione di modificare lo stato di connettività di rete."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiare l\'impostazione di utilizzo dei dati in background"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Consente a un\'applicazione di cambiare l\'impostazione di utilizzo dei dati in background."</string>
+ <string name="permlab_accessWifiState">"visualizzazione stato Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della connessione Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"modifica stato Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
+ <string name="permlab_changeWifiMulticastState">"consenti ricezione multicast Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Consente a un\'applicazione di ricevere pacchetti non direttamente indirizzati al tuo dispositivo. Può essere utile durante la ricerca di servizi offerti nelle vicinanze. Consuma di più rispetto alla modalità non multicast."</string>
+ <string name="permlab_bluetoothAdmin">"gestione Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
+ <string name="permlab_bluetooth">"creazione connessioni Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
+ <string name="permlab_disableKeyguard">"disattivazione blocco tastiera"</string>
+ <string name="permdesc_disableKeyguard">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
+ <string name="permlab_readSyncSettings">"lettura impostazioni di sincronizz."</string>
+ <string name="permdesc_readSyncSettings">"Consente a un\'applicazione di leggere le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
+ <string name="permlab_writeSyncSettings">"scrittura impostazioni di sincronizz."</string>
+ <string name="permdesc_writeSyncSettings">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
+ <string name="permlab_readSyncStats">"lettura statistiche di sincronizz."</string>
+ <string name="permdesc_readSyncStats">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione, per esempio la cronologia delle sincronizzazioni effettuate."</string>
+ <string name="permlab_subscribedFeedsRead">"lettura feed sottoscritti"</string>
+ <string name="permdesc_subscribedFeedsRead">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
+ <string name="permlab_subscribedFeedsWrite">"scrittura feed sottoscritti"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
+ <string name="permlab_readDictionary">"lettura dizionario definito dall\'utente"</string>
+ <string name="permdesc_readDictionary">"Consente a un\'applicazione di leggere parole, nomi e frasi private che l\'utente potrebbe aver memorizzato nel dizionario utente."</string>
+ <string name="permlab_writeDictionary">"scrittura nel dizionario definito dall\'utente"</string>
+ <string name="permdesc_writeDictionary">"Consente a un\'applicazione di scrivere nuove parole nel dizionario utente."</string>
+ <string name="permlab_sdcardWrite">"modificare/eliminare i contenuti della scheda SD"</string>
+ <string name="permdesc_sdcardWrite">"Consente a un\'applicazione di scrivere sulla scheda SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Casa"</item>
- <item msgid="869923650527136615">"Cellulare"</item>
- <item msgid="7897544654242874543">"Ufficio"</item>
- <item msgid="1103601433382158155">"Fax ufficio"</item>
- <item msgid="1735177144948329370">"Fax casa"</item>
- <item msgid="603878674477207394">"Cercapersone"</item>
- <item msgid="1650824275177931637">"Altro"</item>
- <item msgid="9192514806975898961">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Cellulare"</item>
+ <item>"Ufficio"</item>
+ <item>"Fax ufficio"</item>
+ <item>"Fax casa"</item>
+ <item>"Cercapersone"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Casa"</item>
- <item msgid="7084237356602625604">"Ufficio"</item>
- <item msgid="1112044410659011023">"Altro"</item>
- <item msgid="2374913952870110618">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Cellulare"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Casa"</item>
- <item msgid="5629153956045109251">"Ufficio"</item>
- <item msgid="4966604264500343469">"Altro"</item>
- <item msgid="4932682847595299369">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Casa"</item>
- <item msgid="1359644565647383708">"Uffico"</item>
- <item msgid="7868549401053615677">"Altro"</item>
- <item msgid="3145118944639869809">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Uffico"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Ufficio"</item>
- <item msgid="4378074129049520373">"Altro"</item>
- <item msgid="3455047468583965104">"Personalizzato"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Inserisci il PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Codice PIN errato."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Per sbloccare, premi Menu, poi 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numero di emergenza"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Nessun servizio)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Schermo bloccato."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Premi Menu per sbloccare."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Traccia la sequenza di sblocco"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chiamata di emergenza"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Corretta."</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Riprova"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Carico."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Collegare il caricabatterie."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nessuna SIM presente."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Nessuna SIM presente nel telefono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserisci una SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rete bloccata"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La SIM è bloccata tramite PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta il Manuale utente o contatta il servizio clienti."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La SIM è bloccata."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Sblocco SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Hai dimenticato la sequenza?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Troppi tentativi di inserimento della sequenza."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Per sbloccare, accedi tramite il tuo account Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome utente (email)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Accedi"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Password o nome utente non valido."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Cancella"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"In carica..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Collegare il caricabatterie"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteria quasi scarica:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"energia residua inferiore a <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Perché?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Test di fabbrica non riuscito"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Riavvia"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La pagina all\'indirizzo <xliff:g id="TITLE">%s</xliff:g> indica:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleziona OK per continuare o Annulla per rimanere nella pagina corrente."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lettura cronologia e segnalibri del browser"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Consente all\'applicazione di leggere tutti gli URL visitati e tutti i segnalibri del browser."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"creazione cronologia e segnalibri del browser"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Consente a un\'applicazione di modificare la cronologia o i segnalibri del browser memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del browser."</string>
- <string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Mai"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"L\'utente non è autorizzato ad aprire questa pagina."</string>
- <string name="text_copied" msgid="4985729524670131385">"Testo copiato negli appunti."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Altro"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spazio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Invio"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"Canc"</string>
- <string name="search_go" msgid="8298016669822141719">"Cerca"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
+ <string name="keyguard_password_enter_pin_code">"Inserisci il PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Codice PIN errato."</string>
+ <string name="keyguard_label_text">"Per sbloccare, premi Menu, poi 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numero di emergenza"</string>
+ <string name="lockscreen_carrier_default">"(Nessun servizio)"</string>
+ <string name="lockscreen_screen_locked">"Schermo bloccato."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Premi Menu per sbloccare."</string>
+ <string name="lockscreen_pattern_instructions">"Traccia la sequenza di sblocco"</string>
+ <string name="lockscreen_emergency_call">"Chiamata di emergenza"</string>
+ <string name="lockscreen_pattern_correct">"Corretta."</string>
+ <string name="lockscreen_pattern_wrong">"Riprova"</string>
+ <string name="lockscreen_plugged_in">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Collegare il caricabatterie."</string>
+ <string name="lockscreen_missing_sim_message_short">"Nessuna SIM presente."</string>
+ <string name="lockscreen_missing_sim_message">"Nessuna SIM presente nel telefono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserisci una SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rete bloccata"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La SIM è bloccata tramite PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta il Manuale utente o contatta il servizio clienti."</string>
+ <string name="lockscreen_sim_locked_message">"La SIM è bloccata."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Sblocco SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Hai dimenticato la sequenza?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Troppi tentativi di inserimento della sequenza."</string>
+ <string name="lockscreen_glogin_instructions">"Per sbloccare, accedi tramite il tuo account Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nome utente (email)"</string>
+ <string name="lockscreen_glogin_password_hint">"Password"</string>
+ <string name="lockscreen_glogin_submit_button">"Accedi"</string>
+ <string name="lockscreen_glogin_invalid_input">"Password o nome utente non valido."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Nessuna notifica"</string>
+ <string name="status_bar_ongoing_events_title">"In corso"</string>
+ <string name="status_bar_latest_events_title">"Notifiche"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"In carica..."</string>
+ <string name="battery_low_title">"Collegare il caricabatterie"</string>
+ <string name="battery_low_subtitle">"Batteria quasi scarica:"</string>
+ <string name="battery_low_percent_format">"energia residua inferiore a <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Perché?"</string>
+ <string name="factorytest_failed">"Test di fabbrica non riuscito"</string>
+ <string name="factorytest_not_system">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
+ <string name="factorytest_no_action">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Riavvia"</string>
+ <string name="js_dialog_title">"La pagina all\'indirizzo <xliff:g id="TITLE">%s</xliff:g> indica:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleziona OK per continuare o Annulla per rimanere nella pagina corrente."</string>
+ <string name="save_password_label">"Conferma"</string>
+ <string name="permlab_readHistoryBookmarks">"lettura cronologia e segnalibri del browser"</string>
+ <string name="permdesc_readHistoryBookmarks">"Consente all\'applicazione di leggere tutti gli URL visitati e tutti i segnalibri del browser."</string>
+ <string name="permlab_writeHistoryBookmarks">"creazione cronologia e segnalibri del browser"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Consente a un\'applicazione di modificare la cronologia o i segnalibri del browser memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del browser."</string>
+ <string name="save_password_message">"Memorizzare la password nel browser?"</string>
+ <string name="save_password_notnow">"Non ora"</string>
+ <string name="save_password_remember">"Memorizza"</string>
+ <string name="save_password_never">"Mai"</string>
+ <string name="open_permission_deny">"L\'utente non è autorizzato ad aprire questa pagina."</string>
+ <string name="text_copied">"Testo copiato negli appunti."</string>
+ <string name="more_item_label">"Altro"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"spazio"</string>
+ <string name="menu_enter_shortcut_label">"Invio"</string>
+ <string name="menu_delete_shortcut_label">"Canc"</string>
+ <string name="search_go">"Cerca"</string>
+ <string name="oneMonthDurationPast">"1 mese fa"</string>
+ <string name="beforeOneMonthDurationPast">"Oltre 1 mese fa"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 secondo fa"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
+ <item quantity="one">"1 secondo fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto fa"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
+ <item quantity="one">"1 minuto fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ora fa"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
+ <item quantity="one">"1 ora fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ieri"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
+ <item quantity="one">"ieri"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"tra 1 secondo"</item>
- <item quantity="other" msgid="1241926116443974687">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
+ <item quantity="one">"tra 1 secondo"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"tra 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
+ <item quantity="one">"tra 1 minuto"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"tra 1 ora"</item>
- <item quantity="other" msgid="547290677353727389">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ <item quantity="one">"tra 1 ora"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"domani"</item>
- <item quantity="other" msgid="5109449375100953247">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
+ <item quantity="one">"domani"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sec fa"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
+ <item quantity="one">"1 sec fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min fa"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
+ <item quantity="one">"1 min fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ora fa"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
+ <item quantity="one">"1 ora fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ieri"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
+ <item quantity="one">"ieri"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"tra 1 sec"</item>
- <item quantity="other" msgid="5495880108825805108">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
+ <item quantity="one">"tra 1 sec"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"tra 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"tra 1 min"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"tra 1 ora"</item>
- <item quantity="other" msgid="3705373766798013406">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ <item quantity="one">"tra 1 ora"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"domani"</item>
- <item quantity="other" msgid="2973062968038355991">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
+ <item quantity="one">"domani"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"il %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"alle %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"nel %s"</string>
- <string name="day" msgid="8144195776058119424">"giorno"</string>
- <string name="days" msgid="4774547661021344602">"giorni"</string>
- <string name="hour" msgid="2126771916426189481">"ora"</string>
- <string name="hours" msgid="894424005266852993">"ore"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"sec"</string>
- <string name="seconds" msgid="3161515347216589235">"sec"</string>
- <string name="week" msgid="5617961537173061583">"settimana"</string>
- <string name="weeks" msgid="6509623834583944518">"settimane"</string>
- <string name="year" msgid="4001118221013892076">"anno"</string>
- <string name="years" msgid="6881577717993213522">"anni"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Ogni giorno feriale (lun-ven)"</string>
- <string name="daily" msgid="5738949095624133403">"Quotidianamente"</string>
- <string name="weekly" msgid="983428358394268344">"Ogni settimana il <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensilmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Annualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Impossibile riprodurre il video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Spiacenti, questo video non è valido per lo streaming su questo dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Spiacenti. Impossibile riprodurre il video."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mezzogiorno"</string>
- <string name="Noon" msgid="3342127745230013127">"Mezzogiorno"</string>
- <string name="midnight" msgid="7166259508850457595">"mezzanotte"</string>
- <string name="Midnight" msgid="5630806906897892201">"Mezzanotte"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleziona testo"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Termina selezione testo"</string>
- <string name="cut" msgid="3092569408438626261">"Taglia"</string>
- <string name="cutAll" msgid="2436383270024931639">"Taglia tutto"</string>
- <string name="copy" msgid="2681946229533511987">"Copia"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copia tutto"</string>
- <string name="paste" msgid="5629880836805036433">"Incolla"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copia URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Metodo inserimento"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Aggiungi \"%s\" al dizionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Modifica testo"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Spazio in esaurimento"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Spazio di archiviazione del telefono in esaurimento."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annulla"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Attenzione"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completa l\'azione con"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Usa come predefinita per questa azione."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Cancella predefinita in Home > Impostazioni > Applicazioni > Gestisci applicazioni."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleziona un\'azione"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nessuna applicazione è in grado di svolgere questa azione."</string>
- <string name="aerr_title" msgid="653922989522758100">"Spiacenti."</string>
- <string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo<xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Interruzione imprevista del processo <xliff:g id="PROCESS">%1$s</xliff:g>. Riprova."</string>
- <string name="anr_title" msgid="3100070910664756057">"Spiacenti."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nell\'applicazione <xliff:g id="APPLICATION">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_process" msgid="1246866008169975783">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde."</string>
- <string name="force_close" msgid="3653416315450806396">"Termina"</string>
- <string name="report" msgid="4060218260984795706">"Segnala"</string>
- <string name="wait" msgid="7147118217226317732">"Attendi"</string>
- <string name="debug" msgid="9103374629678531849">"Debug"</string>
- <string name="sendText" msgid="5132506121645618310">"Selezione un\'opzione di invio"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume suoneria"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume app. multimediali"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Riproduzione tramite Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume chiamate"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume chiamate Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume allarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume notifiche"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silenzioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Suoneria sconosciuta"</string>
+ <string name="preposition_for_date">"il %s"</string>
+ <string name="preposition_for_time">"alle %s"</string>
+ <string name="preposition_for_year">"nel %s"</string>
+ <string name="day">"giorno"</string>
+ <string name="days">"giorni"</string>
+ <string name="hour">"ora"</string>
+ <string name="hours">"ore"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"sec"</string>
+ <string name="seconds">"sec"</string>
+ <string name="week">"settimana"</string>
+ <string name="weeks">"settimane"</string>
+ <string name="year">"anno"</string>
+ <string name="years">"anni"</string>
+ <string name="every_weekday">"Ogni giorno feriale (lun-ven)"</string>
+ <string name="daily">"Quotidianamente"</string>
+ <string name="weekly">"Ogni settimana il <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensilmente"</string>
+ <string name="yearly">"Annualmente"</string>
+ <string name="VideoView_error_title">"Impossibile riprodurre il video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Spiacenti, questo video non è valido per lo streaming su questo dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Spiacenti. Impossibile riprodurre il video."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mezzogiorno"</string>
+ <string name="Noon">"Mezzogiorno"</string>
+ <string name="midnight">"mezzanotte"</string>
+ <string name="Midnight">"Mezzanotte"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleziona tutto"</string>
+ <string name="selectText">"Seleziona testo"</string>
+ <string name="stopSelectingText">"Termina selezione testo"</string>
+ <string name="cut">"Taglia"</string>
+ <string name="cutAll">"Taglia tutto"</string>
+ <string name="copy">"Copia"</string>
+ <string name="copyAll">"Copia tutto"</string>
+ <string name="paste">"Incolla"</string>
+ <string name="copyUrl">"Copia URL"</string>
+ <string name="inputMethod">"Metodo inserimento"</string>
+ <string name="addToDictionary">"Aggiungi \"%s\" al dizionario"</string>
+ <string name="editTextMenuTitle">"Modifica testo"</string>
+ <string name="low_internal_storage_view_title">"Spazio in esaurimento"</string>
+ <string name="low_internal_storage_view_text">"Spazio di archiviazione del telefono in esaurimento."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annulla"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annulla"</string>
+ <string name="dialog_alert_title">"Attenzione"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"Completa l\'azione con"</string>
+ <string name="alwaysUse">"Usa come predefinita per questa azione."</string>
+ <string name="clearDefaultHintMsg">"Cancella predefinita in Home > Impostazioni > Applicazioni > Gestisci applicazioni."</string>
+ <string name="chooseActivity">"Seleziona un\'azione"</string>
+ <string name="noApplications">"Nessuna applicazione è in grado di svolgere questa azione."</string>
+ <string name="aerr_title">"Spiacenti."</string>
+ <string name="aerr_application">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo<xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
+ <string name="aerr_process">"Interruzione imprevista del processo <xliff:g id="PROCESS">%1$s</xliff:g>. Riprova."</string>
+ <string name="anr_title">"Spiacenti."</string>
+ <string name="anr_activity_application">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nell\'applicazione <xliff:g id="APPLICATION">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_activity_process">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_application_process">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_process">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde."</string>
+ <string name="force_close">"Termina"</string>
+ <string name="report">"Segnala"</string>
+ <string name="wait">"Attendi"</string>
+ <string name="debug">"Debug"</string>
+ <string name="sendText">"Selezione un\'opzione di invio"</string>
+ <string name="volume_ringtone">"Volume suoneria"</string>
+ <string name="volume_music">"Volume app. multimediali"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Riproduzione tramite Bluetooth"</string>
+ <string name="volume_call">"Volume chiamate"</string>
+ <string name="volume_bluetooth_call">"Volume chiamate Bluetooth"</string>
+ <string name="volume_alarm">"Volume allarme"</string>
+ <string name="volume_notification">"Volume notifiche"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Suoneria predefinita"</string>
+ <string name="ringtone_default_with_actual">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silenzioso"</string>
+ <string name="ringtone_picker_title">"Suonerie"</string>
+ <string name="ringtone_unknown">"Suoneria sconosciuta"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rete Wi-Fi disponibile"</item>
- <item quantity="other" msgid="4192424489168397386">"Reti Wi-Fi disponibili"</item>
+ <item quantity="one">"Rete Wi-Fi disponibile"</item>
+ <item quantity="other">"Reti Wi-Fi disponibili"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rete Wi-Fi aperta disponibile"</item>
- <item quantity="other" msgid="7915895323644292768">"Reti Wi-Fi aperte disponibili"</item>
+ <item quantity="one">"Rete Wi-Fi aperta disponibile"</item>
+ <item quantity="other">"Reti Wi-Fi aperte disponibili"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Applicazione sconosciuta"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"È in corso l\'invio di numerosi SMS. Seleziona \"OK\" per continuare, oppure \"Annulla\" per interrompere l\'invio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annulla"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Imposta"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predefinito"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Nascondi"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostra tutto"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Caricamento..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB collegata"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Il telefono è stato collegato al computer tramite USB. Seleziona \"Collega\" se desideri copiare file tra il computer e la scheda SD del telefono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Collega"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Non collegare"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Problema di utilizzo della scheda SD per l\'archiviazione USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB collegata"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleziona per copiare file sul/dal tuo computer."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Disattiva archivio USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleziona per disattivare archivio USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Disattiva archivio USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Prima di disattivare l\'archivio USB, verifica di aver smontato l\'host USB. A tale scopo, seleziona \"Disattiva\"."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Disattiva"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annulla"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Abbiamo riscontrato un problema disattivando l\'archivio USB. Verifica di aver smontato l\'host USB e riprova."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatta scheda SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Formattare la scheda SD? Tutti i dati sulla scheda verranno persi."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatta"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Un computer è collegato al tuo cellulare."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Seleziona metodo di inserimento"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparazione scheda SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Ricerca errori."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Scheda SD vuota"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Scheda SD vuota o con filesystem non supportato."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Scheda SD danneggiata"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Scheda SD danneggiata. Potrebbe essere necessario riformattarla."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Rimozione imprevista della scheda SD"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Smonta scheda SD prima della rimozione per evitare la perdita di dati."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"È possibile rimuovere la scheda SD"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Puoi rimuovere la scheda SD in tutta sicurezza."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Scheda SD rimossa"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Scheda SD rimossa. Inseriscine un\'altra."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nessuna attività corrispondente trovata"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aggiornare le statistiche di utilizzo dei componenti"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Consente la modifica delle statistiche di utilizzo dei componenti raccolte. Da non usare per normali applicazioni."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Errore durante l\'ampliamento del widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Vai"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Cerca"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Invia"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Avanti"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Fine"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Esegui"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Componi numero"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crea contatto"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"selezionato"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"non selezionato"</string>
+ <string name="select_character">"Inserisci carattere"</string>
+ <string name="sms_control_default_app_name">"Applicazione sconosciuta"</string>
+ <string name="sms_control_title">"Invio SMS"</string>
+ <string name="sms_control_message">"È in corso l\'invio di numerosi SMS. Seleziona \"OK\" per continuare, oppure \"Annulla\" per interrompere l\'invio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annulla"</string>
+ <string name="date_time_set">"Imposta"</string>
+ <string name="default_permission_group">"Predefinito"</string>
+ <string name="no_permissions">"Nessuna autorizzazione richiesta"</string>
+ <string name="perms_hide"><b>"Nascondi"</b></string>
+ <string name="perms_show_all"><b>"Mostra tutto"</b></string>
+ <string name="googlewebcontenthelper_loading">"Caricamento..."</string>
+ <string name="usb_storage_title">"USB collegata"</string>
+ <string name="usb_storage_message">"Il telefono è stato collegato al computer tramite USB. Seleziona \"Collega\" se desideri copiare file tra il computer e la scheda SD del telefono."</string>
+ <string name="usb_storage_button_mount">"Collega"</string>
+ <string name="usb_storage_button_unmount">"Non collegare"</string>
+ <string name="usb_storage_error_message">"Problema di utilizzo della scheda SD per l\'archiviazione USB."</string>
+ <string name="usb_storage_notification_title">"USB collegata"</string>
+ <string name="usb_storage_notification_message">"Seleziona per copiare file sul/dal tuo computer."</string>
+ <string name="usb_storage_stop_notification_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleziona per disattivare archivio USB."</string>
+ <string name="usb_storage_stop_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_message">"Prima di disattivare l\'archivio USB, verifica di aver smontato l\'host USB. A tale scopo, seleziona \"Disattiva\"."</string>
+ <string name="usb_storage_stop_button_mount">"Disattiva"</string>
+ <string name="usb_storage_stop_button_unmount">"Annulla"</string>
+ <string name="usb_storage_stop_error_message">"Abbiamo riscontrato un problema disattivando l\'archivio USB. Verifica di aver smontato l\'host USB e riprova."</string>
+ <string name="extmedia_format_title">"Formatta scheda SD"</string>
+ <string name="extmedia_format_message">"Formattare la scheda SD? Tutti i dati sulla scheda verranno persi."</string>
+ <string name="extmedia_format_button_format">"Formatta"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Seleziona metodo di inserimento"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidati"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparazione scheda SD"</string>
+ <string name="ext_media_checking_notification_message">"Ricerca errori."</string>
+ <string name="ext_media_nofs_notification_title">"Scheda SD vuota"</string>
+ <string name="ext_media_nofs_notification_message">"Scheda SD vuota o con filesystem non supportato."</string>
+ <string name="ext_media_unmountable_notification_title">"Scheda SD danneggiata"</string>
+ <string name="ext_media_unmountable_notification_message">"Scheda SD danneggiata. Potrebbe essere necessario riformattarla."</string>
+ <string name="ext_media_badremoval_notification_title">"Rimozione imprevista della scheda SD"</string>
+ <string name="ext_media_badremoval_notification_message">"Smonta scheda SD prima della rimozione per evitare la perdita di dati."</string>
+ <string name="ext_media_safe_unmount_notification_title">"È possibile rimuovere la scheda SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Puoi rimuovere la scheda SD in tutta sicurezza."</string>
+ <string name="ext_media_nomedia_notification_title">"Scheda SD rimossa"</string>
+ <string name="ext_media_nomedia_notification_message">"Scheda SD rimossa. Inseriscine un\'altra."</string>
+ <string name="activity_list_empty">"Nessuna attività corrispondente trovata"</string>
+ <string name="permlab_pkgUsageStats">"aggiornare le statistiche di utilizzo dei componenti"</string>
+ <string name="permdesc_pkgUsageStats">"Consente la modifica delle statistiche di utilizzo dei componenti raccolte. Da non usare per normali applicazioni."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tocca due volte per il comando dello zoom"</string>
+ <string name="gadget_host_error_inflating">"Errore durante l\'ampliamento del widget"</string>
+ <string name="ime_action_go">"Vai"</string>
+ <string name="ime_action_search">"Cerca"</string>
+ <string name="ime_action_send">"Invia"</string>
+ <string name="ime_action_next">"Avanti"</string>
+ <string name="ime_action_done">"Fine"</string>
+ <string name="ime_action_default">"Esegui"</string>
+ <string name="dial_number_using">"Componi numero"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crea contatto"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"selezionato"</string>
+ <string name="accessibility_compound_button_unselected">"non selezionato"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b8bfdf6..4ad87d7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -15,697 +15,748 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<新規>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(電話番号なし)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(名前)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ボイスメール"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"接続に問題があるか、MMIコードが正しくありません。"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"サービスが有効になりました。"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"次のサービスが有効になりました:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"サービスが無効になりました。"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"登録されました。"</string>
- <string name="serviceErased" msgid="1288584695297200972">"消去されました。"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"パスワードが正しくありません。"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMIが完了しました。"</string>
- <string name="badPin" msgid="5085454289896032547">"入力した古いPINは正しくありません。"</string>
- <string name="badPuk" msgid="5702522162746042460">"入力したPUKは正しくありません。"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"入力したPINが一致しません。"</string>
- <string name="invalidPin" msgid="3850018445187475377">"4~8桁の数字のPINを入力してください。"</string>
- <string name="needPuk" msgid="919668385956251611">"SIMカードはPUKでロックされています。ロックを解除するにはPUKコードを入力してください。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"SIMカードのロック解除のためPUK2を入力します。"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"着信時の発信者番号"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"発信者番号"</string>
- <string name="CfMmi" msgid="5123218989141573515">"着信転送"</string>
- <string name="CwMmi" msgid="9129678056795016867">"通話中着信"</string>
- <string name="BaMmi" msgid="455193067926770581">"発信制限"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"パスワードの変更"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PINの変更"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"発呼者番号を提示"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"発呼者番号を制限"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"三者間通話"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"迷惑な着信を拒否"</string>
- <string name="CndMmi" msgid="3116446237081575808">"発呼者番号を配信"</string>
- <string name="DndMmi" msgid="1265478932418334331">"着信拒否"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"既定: 発信者番号非通知、次の発信: 非通知"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"既定: 発信者番号非通知、次の発信: 通知"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"既定: 発信者番号通知、次の発信: 非通知"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"既定: 発信者番号通知、次の発信: 通知"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"提供可能なサービスがありません。"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"発信者番号の設定は変更できません。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"アクセス制限が変更されました"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"データサービスがブロックされています。"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"緊急サービスがブロックされています。"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"音声/SMSサービスがブロックされています。"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"すべての音声/SMSサービスがブロックされています。"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"音声"</string>
- <string name="serviceClassData" msgid="872456782077937893">"データ"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"非同期"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"同期"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"パケット"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"ローミングインジケーターON"</string>
- <string name="roamingText1" msgid="5314861519752538922">"ローミングインジケーターOFF"</string>
- <string name="roamingText2" msgid="8969929049081268115">"ローミングインジケーター点滅中"</string>
- <string name="roamingText3" msgid="5148255027043943317">"周辺外"</string>
- <string name="roamingText4" msgid="8808456682550796530">"屋外"</string>
- <string name="roamingText5" msgid="7604063252850354350">"ローミング: 優先するシステム"</string>
- <string name="roamingText6" msgid="2059440825782871513">"ローミング: 利用できるシステム"</string>
- <string name="roamingText7" msgid="7112078724097233605">"ローミング: 提携パートナー"</string>
- <string name="roamingText8" msgid="5989569778604089291">"ローミング: プレミアムパートナー"</string>
- <string name="roamingText9" msgid="7969296811355152491">"ローミング: サービスの全機能を利用可"</string>
- <string name="roamingText10" msgid="3992906999815316417">"ローミング: サービスの一部機能のみ利用可"</string>
- <string name="roamingText11" msgid="4154476854426920970">"ローミングバナーON"</string>
- <string name="roamingText12" msgid="1189071119992726320">"ローミングバナーOFF"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"サービスを検索中"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
- <string name="fcComplete" msgid="3118848230966886575">"機能コードが完了しました。"</string>
- <string name="fcError" msgid="3327560126588500777">"接続エラーまたは無効な機能コードです。"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"ウェブページにエラーがあります。"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URLが見つかりません。"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"このサイトの認証方式には対応していません。"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"認証できませんでした。"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"プロキシサーバーを使用した認証に失敗しました。"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"サーバーに接続できませんでした。"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"サーバーと通信できませんでした。しばらくしてからもう一度試してください。"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"サーバーへの接続がタイムアウトになりました。"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"このページはサーバーのリダイレクトが多すぎます。"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"このプロトコルには対応していません。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"安全な接続を確立できませんでした。"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URLが無効なのでページを表示できませんでした。"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"ファイルにアクセスできませんでした。"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"要求されたファイルが見つかりませんでした。"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"処理中のリクエストが多すぎます。しばらくしてからもう一度試してください。"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"同期"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同期"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
- <string name="low_memory" msgid="6632412458436461203">"電話のメモリがいっぱいです。ファイルを削除してメモリを解放してください。"</string>
- <string name="me" msgid="6545696007631404292">"自分"</string>
- <string name="power_dialog" msgid="1319919075463988638">"携帯電話オプション"</string>
- <string name="silent_mode" msgid="7167703389802618663">"マナーモード"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"ワイヤレス接続をONにする"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"ワイヤレス接続をOFFにする"</string>
- <string name="screen_lock" msgid="799094655496098153">"画面をロック"</string>
- <string name="power_off" msgid="4266614107412865048">"電源を切る"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"携帯電話の電源を切ります。"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"最近使ったアプリケーションはありません。"</string>
- <string name="global_actions" msgid="2406416831541615258">"携帯電話オプション"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"マナーモード"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"サウンドOFF"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"サウンドON"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
- <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"料金の発生するサービス"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"料金の発生する操作をアプリケーションに許可します。"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"送受信したメッセージ"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS、メールなどのメッセージの読み書き"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"個人情報"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"端末の連絡先とカレンダーに直接アクセス"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"現在地"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"現在地を追跡"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"ネットワーク通信"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"ネットワークのさまざまな機能へのアクセスをアプリケーションに許可します。"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Googleアカウント"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"利用可能なGoogleアカウントへのアクセス"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"ハードウェアの制御"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"携帯電話のハードウェアに直接アクセスします。"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"電話/通話"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"通話の監視、記録、処理"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"システムツール"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"システムの低レベルのアクセスと制御"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"開発ツール"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"アプリケーションのデベロッパーにのみ必要な機能です。"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"ストレージ"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"SDカードにアクセスします。"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"ステータスバーの無効化や変更"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"ステータスバーの無効化やシステムアイコンの追加や削除をアプリケーションに許可します。"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ステータスバーの拡大/縮小"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"ステータスバーの拡大や縮小をアプリケーションに許可します。"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"発信の傍受"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"通話発信とダイヤルする番号の変更をアプリケーションに許可します。悪意のあるアプリケーションが発信を監視、転送、阻止する恐れがあります。"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMSの受信"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"SMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMSの受信"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"MMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMSメッセージの送信"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"SMSメッセージの送信をアプリケーションに許可します。悪意のあるアプリケーションが確認なしでメッセージを送信し、料金が発生する恐れがあります。"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMSの読み取り"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"携帯電話やSIMカードに保存したSMSメッセージの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが機密メッセージを読み取る恐れがあります。"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMSの編集"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"携帯電話やSIMカードに保存したSMSメッセージへの書き込みをアプリケーションに許可します。悪意のあるアプリケーションがメッセージを削除する恐れがあります。"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAPの受信"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"WAPメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"実行中のアプリケーションの取得"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"現在実行中または最近実行したタスクに関する情報の取得をアプリケーションに許可します。悪意のあるアプリケーションが他のアプリケーションの非公開情報を取得する恐れがあります。"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"実行中のアプリケーションの順序の変更"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリケーションに許可します。悪意のあるアプリケーションが優先されて、コントロールできなくなる恐れがあります。"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"アプリケーションのデバッグを有効にする"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。悪意のあるアプリケーションが別のアプリケーションを終了させる恐れがあります。"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"地域/言語やフォントのサイズなど、現在の設定の変更をアプリケーションに許可します。"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"他のアプリケーションの再起動"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"他のアプリケーションの強制的な再起動をアプリケーションに許可します。"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"アプリケーションの強制終了"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"フォアグラウンドで実行されている操作を強制終了して戻ることをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"システムの内部状態の取得"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"システムの内部状態の取得をアプリケーションに許可します。悪意のあるアプリケーションが、通常は必要としない広範囲にわたる非公開の機密情報を取得する恐れがあります。"</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"部分的にシャットダウンする"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"アクティビティマネージャをシャットダウン状態にします。完全なシャットダウンは実行しません。"</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションの切り替えを禁止する"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"ユーザーが別のアプリケーションに切り替えられないようにします。"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"起動中のすべてのアプリケーションの監視と制御"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"システムが起動する操作の監視と制御をアプリケーションに許可します。悪意のあるアプリケーションがシステムを完全に破壊する恐れがあります。この許可は開発にのみ必要で、携帯電話の通常の使用にはまったく必要ありません。"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"パッケージ削除ブロードキャストの送信"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"アプリケーションパッケージの削除の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションが他の実行中のアプリケーションを強制終了する恐れがあります。"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS受信ブロードキャストの送信"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"SMSメッセージの受信通知の配信をアプリケーションに許可します。悪意のあるアプリケーションが受信SMSメッセージを偽造する恐れがあります。"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH受信ブロードキャストの送信"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"WAP PUSHメッセージの受信の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションがMMS受信メッセージを偽造したり、ウェブページのコンテンツを密かに改ざんする恐れがあります。"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"実行中のプロセスの数を制限"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"実行するプロセス数の上限の制御をアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"バックグラウンドアプリケーションをすべて終了する"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"バックグラウンドになり次第必ず操作を終了させるかどうかの制御をアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"電池統計情報の変国"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"収集した電池統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_backup" msgid="470013022865453920">"システムのバックアップと復元を制御する"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"システムのバックアップおよび復元メカニズムの制御をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"未許可のウィンドウの表示"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"内部システムのユーザーインターフェースで使用するためのウィンドウ作成を許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"システムレベルの警告の表示"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"システムの警告ウィンドウの表示をアプリケーションに許可します。悪意のあるアプリケーションが携帯電話の画面全体を偽装する恐れがあります。"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"アニメーションのプリセット速度の変更"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"いつでもアニメーション全般の速度を変更する (アニメーションを速くまたは遅くする) ことをアプリケーションに許可します。"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"アプリケーショントークンの管理"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"通常のZ-orderingを回避して、独自のトークンを作成、管理することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"キーを押してボタンをコントロール"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"入力イベント (キーを押すなど) を別のアプリケーションに伝えることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話を乗っ取る恐れがあります。"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"入力や操作の記録"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"別のアプリケーションへの入力(パスワードなど)でもキー入力を監視することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"入力方法に関連付ける"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"入力方法のトップレベルインターフェースに関連付けることを所有者に許可します。通常のアプリケーションにはまったく必要ありません。"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linuxのシグナルをアプリケーションに送信"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"受信した電波を継続プロセスに送信することをアプリケーションに許可します。"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"アプリケーションを常に実行する"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"自身を部分的に永続させて、他のアプリケーション用にはその領域をシステムに使わせないようにすることをアプリケーションに許可します。"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"アプリケーションの削除"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Androidパッケージの削除をアプリケーションに許可します。悪意のあるアプリケーションが、重要なアプリケーションを削除する恐れがあります。"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"他のアプリケーションのデータを削除"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"ユーザーデータの消去をアプリケーションに許可します。"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"他のアプリケーションのキャッシュを削除"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"キャッシュファイルの削除をアプリケーションに許可します。"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"アプリケーションのメモリ容量の計測"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"アプリケーションのコード、データ、キャッシュのサイズを取得することを許可します。"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"アプリケーションを直接インストール"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Androidパッケージのインストール/更新をアプリケーションに許可します。悪意のあるアプリケーションが、勝手に強力な権限を持つ新しいアプリケーションを追加する恐れがあります。"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"アプリケーションキャッシュデータの削除"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"システムログファイルの読み取り"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"アプリケーションのコンポーネントを有効/無効にする"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"別アプリケーションのコンポーネントの有効/無効を変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話の重要な機能を無効にする恐れがあります。アプリケーションコンポーネントが利用できない、整合性が取れない、または不安定な状態になる恐れがあるので、許可には注意が必要です。"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"優先アプリケーションの設定"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"優先アプリケーションを変更することをアプリケーションに許可します。悪意のあるアプリケーションが実行中のアプリケーションを密かに変更し、既存のアプリケーションになりすまして非公開データを収集する恐れがあります。"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"システムの全般設定の変更"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"システム設定データの変更をアプリケーションに許可します。悪意のあるアプリケーションがシステム設定を破壊する恐れがあります。"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"システムのセキュリティ設定の変更"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"システムのセキュリティ設定の変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Googleサービスの地図の変更"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Googleサービスマップの変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"起動時に自動的に開始"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"システムの起動後に自動的に起動することをアプリケーションに許可します。携帯電話の起動に時間がかかるようになり、アプリケーションが常に実行されるために携帯電話の全体的な動作が遅くなります。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"stickyブロードキャストの配信"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"配信が終了してもメモリに残るようなstickyブロードキャストをアプリケーションに許可します。悪意のあるアプリケーションがメモリを使いすぎて、携帯電話の動作が遅くなったり、不安定になる恐れがあります。"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"連絡先データの読み取り"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"端末に保存した連絡先(アドレス)データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションがデータを他人に送信する恐れがあります。"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"連絡先データの書き込み"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"端末に保存した連絡先(アドレス)データの変更をアプリケーションに許可します。悪意のあるアプリケーションが連絡先データを消去/変更する恐れがあります。"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"所有者データの書き込み"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"端末に保存した所有者のデータの変更をアプリケーションに許可します。悪意のあるアプリケーションが所有者のデータを消去/変更する恐れがあります。"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"所有者データの読み取り"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"携帯電話に保存した所有者データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが所有者データを読み取る恐れがあります。"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"カレンダーデータの読み取り"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"端末に保存したカレンダーの予定の読み取りをアプリケーションに許可します。悪意のあるアプリケーションがカレンダーの予定を他人に送信する恐れがあります。"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"カレンダーデータの書き込み"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"端末に保存したカレンダーの予定の変更をアプリケーションに許可します。悪意のあるアプリケーションが、カレンダーデータを消去/変更する恐れがあります。"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"仮の位置情報でテスト"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"テスト用に仮の位置情報源を作成します。これにより悪意のあるアプリケーションが、GPS、ネットワークプロバイダなどから返される本当の位置情報や状況を改ざんする恐れがあります。"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"位置情報提供者の追加コマンドアクセス"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"位置情報提供元の追加コマンドにアクセスします。悪意のあるアプリケーションがGPSなどの位置提供の動作を妨害する恐れがあります。"</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"位置情報提供元のインストールを許可する"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"テスト用に仮の位置情報を作成します。これにより悪意のあるアプリケーションが、GPSやネットワークプロバイダなどから返される本当の位置情報や状況を改ざんしたり、端末の現在地を監視して外部に報告したりする恐れがあります。"</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"精細な位置情報(GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"GPSなど携帯電話の位置情報にアクセスします(可能な場合)。今いる場所が悪意のあるアプリケーションに検出されたり、バッテリーの消費が増える恐れがあります。"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"おおよその位置情報(ネットワーク基地局)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"セルラーネットワークデータベースなど、携帯電話のおおよその位置を特定する情報源が利用可能な場合にアクセスします。これにより悪意のあるアプリケーションが、ユーザーのおおよその位置を特定できる恐れがあります。"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlingerへのアクセス"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"SurfaceFlingerの低レベルの機能の使用をアプリケーションに許可します。"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"フレームバッファの読み取り"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"フレームバッファの内容の読み取りと使用をアプリケーションに許可します。"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"音声設定の変更"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"音量や転送などの音声全般の設定の変更をアプリケーションに許可します。"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"録音"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"オーディオ録音パスへのアクセスをアプリケーションに許可します。"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"写真の撮影"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"カメラでの写真撮影をアプリケーションに許可します。アプリケーションはカメラから画像をいつでも収集できます。"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"端末を永続的に無効にする"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"携帯電話全体を永続的に無効にすることをアプリケーションに許可します。この許可は非常に危険です。"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"端末の再起動"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"端末の強制的な再起動をアプリケーションに許可します。"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"ファイルシステムのマウントとマウント解除"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"リムーバブルメモリのファイルシステムのマウントとマウント解除をアプリケーションに許可します。"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"外部ストレージのフォーマット"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"アプリケーションがリムーバブルストレージをフォーマットすることを許可します。"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"バイブレーション制御"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"バイブレーションの制御をアプリケーションに許可します。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"ライトの制御をアプリケーションに許可します。"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"ハードウェアのテスト"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"電話番号の自動発信をアプリケーションに許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急通報への発信は許可しません。"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"電話番号発信"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"緊急通報を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"位置情報の更新通知"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"チェックインプロパティへのアクセス"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"ウィジェットの選択"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"どのアプリケーションがどのウィジェットを使用できるかシステムに指定することをこのアプリケーションに許可します。これにより、アプリケーション間で個人データにアクセスできるようになります。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"端末ステータスの変更"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
+ <string name="untitled">"<新規>"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(電話番号なし)"</string>
+ <string name="unknownName">"(名前)"</string>
+ <string name="defaultVoiceMailAlphaTag">"ボイスメール"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"接続に問題があるか、MMIコードが正しくありません。"</string>
+ <string name="serviceEnabled">"サービスが有効になりました。"</string>
+ <string name="serviceEnabledFor">"次のサービスが有効になりました:"</string>
+ <string name="serviceDisabled">"サービスが無効になりました。"</string>
+ <string name="serviceRegistered">"登録されました。"</string>
+ <string name="serviceErased">"消去されました。"</string>
+ <string name="passwordIncorrect">"パスワードが正しくありません。"</string>
+ <string name="mmiComplete">"MMIが完了しました。"</string>
+ <string name="badPin">"入力した古いPINは正しくありません。"</string>
+ <string name="badPuk">"入力したPUKは正しくありません。"</string>
+ <string name="mismatchPin">"入力したPINが一致しません。"</string>
+ <string name="invalidPin">"4~8桁の数字のPINを入力してください。"</string>
+ <string name="needPuk">"SIMカードはPUKでロックされています。ロックを解除するにはPUKコードを入力してください。"</string>
+ <string name="needPuk2">"SIMカードのロック解除のためPUK2を入力します。"</string>
+ <string name="ClipMmi">"着信時の発信者番号"</string>
+ <string name="ClirMmi">"発信者番号"</string>
+ <string name="CfMmi">"着信転送"</string>
+ <string name="CwMmi">"通話中着信"</string>
+ <string name="BaMmi">"発信制限"</string>
+ <string name="PwdMmi">"パスワードの変更"</string>
+ <string name="PinMmi">"PINの変更"</string>
+ <!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"端末のスリープを無効にする"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"端末のスリープを無効にすることをアプリケーションに許可します。"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"電源のON/OFF"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"携帯電話の電源のオン/オフをアプリケーションに許可します。"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"出荷時試験モードでの実行"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"携帯電話のハードウェアへのアクセスを完全に許可して、低レベルのメーカーテストとして実行します。メーカーのテストモードで携帯電話を使用するときのみ利用できます。"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"壁紙の設定"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"システムの壁紙の設定をアプリケーションに許可します。"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"壁紙サイズのヒントの設定"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"システムの壁紙サイズのヒントの設定をアプリケーションに許可します。"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"システムを出荷時設定にリセット"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"データ、設定、インストールしたアプリケーションをすべて消去して、完全に出荷時の設定にシステムをリセットすることをアプリケーションに許可します。"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"タイムゾーンの設定"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"端末のタイムゾーンの変更をアプリケーションに許可します。"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"既知のアカウントの取得"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"端末内にあるアカウントのリストの取得をアプリケーションに許可します。"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ネットワーク状態の表示"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"すべてのネットワーク状態の表示をアプリケーションに許可します。"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"完全なインターネットアクセス"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"ネットワークソケットの作成をアプリケーションに許可します。"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"アクセスポイント名設定の書き込み"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ネットワーク接続の変更"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"ネットワークの接続状態の変更をアプリケーションに許可します。"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"バックグラウンドデータ使用設定の変更"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"バックグラウンドデータ使用の設定の変更をアプリケーションに許可します。"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi状態の表示"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Wi-Fi状態に関する情報の表示をアプリケーションに許可します。"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi状態の変更"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Wi-Fiアクセスポイントへの接続や接続の切断、設定されたWi-Fiネットワークの変更をアプリケーションに許可します。"</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fiマルチキャストの受信を許可する"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"端末を直接の宛先とはしていないパケットの受信をアプリケーションに許可します。近隣で提供中のサービスを検出したい場合に便利です。マルチキャスト以外のモードよりも電力を消費します。"</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetoothの管理"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"このBluetooth端末の設定、およびリモート端末を検出してペアに設定することをアプリケーションに許可します。"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth接続の作成"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"このBluetooth端末の設定表示、および別の端末をペアとして設定し接続を承認することをアプリケーションに許可します。"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"キーロックを無効にする"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"キーロックや関連するパスワードセキュリティを無効にすることをアプリケーションに許可します。正当な利用の例では、かかってきた電話を受信する際にキーロックを無効にし、通話の終了時にキーロックを有効にし直します。"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"連絡先の同期の有効/無効など、同期設定の読み取りをアプリケーションに許可します。"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"同期設定の書き込み"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"連絡先の同期の有効/無効など、同期設定の変更をアプリケーションに許可します。"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"同期統計の読み取り"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"同期状態(同期履歴など)の読み取りをアプリケーションに許可します。"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"登録したフィードの読み取り"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"現在同期しているフィードの詳細の取得をアプリケーションに許可します。"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"登録したフィードの書き込み"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"現在同期しているフィードの変更をアプリケーションに許可します。悪意のあるアプリケーションが同期フィードを変更する恐れがあります。"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ユーザー定義辞書の読み込み"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"アプリケーションがユーザー辞書に登録されている個人的な語句や名前を読み込むことを許可します。"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"ユーザー定義辞書への書き込み"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"アプリケーションがユーザー辞書に新しい語句を書き込むことを許可します。"</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"SDカードのコンテンツを修正/削除する"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"SDカードへの書き込みをアプリケーションに許可します。"</string>
+ <!-- no translation found for CnirMmi (3062102121430548731) -->
+ <skip />
+ <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
+ <skip />
+ <!-- no translation found for RuacMmi (7827887459138308886) -->
+ <skip />
+ <!-- no translation found for CndMmi (3116446237081575808) -->
+ <skip />
+ <!-- no translation found for DndMmi (1265478932418334331) -->
+ <skip />
+ <string name="CLIRDefaultOnNextCallOn">"既定: 発信者番号非通知、次の発信: 非通知"</string>
+ <string name="CLIRDefaultOnNextCallOff">"既定: 発信者番号非通知、次の発信: 通知"</string>
+ <string name="CLIRDefaultOffNextCallOn">"既定: 発信者番号通知、次の発信: 非通知"</string>
+ <string name="CLIRDefaultOffNextCallOff">"既定: 発信者番号通知、次の発信: 通知"</string>
+ <string name="serviceNotProvisioned">"提供可能なサービスがありません。"</string>
+ <string name="CLIRPermanent">"発信者番号の設定は変更できません。"</string>
+ <string name="RestrictedChangedTitle">"アクセス制限が変更されました"</string>
+ <string name="RestrictedOnData">"データサービスがブロックされています。"</string>
+ <string name="RestrictedOnEmergency">"緊急サービスがブロックされています。"</string>
+ <string name="RestrictedOnNormal">"音声/SMSサービスがブロックされています。"</string>
+ <string name="RestrictedOnAll">"すべての音声/SMSサービスがブロックされています。"</string>
+ <string name="serviceClassVoice">"音声"</string>
+ <string name="serviceClassData">"データ"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"非同期"</string>
+ <string name="serviceClassDataSync">"同期"</string>
+ <string name="serviceClassPacket">"パケット"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <!-- no translation found for roamingText0 (7170335472198694945) -->
+ <skip />
+ <!-- no translation found for roamingText1 (5314861519752538922) -->
+ <skip />
+ <!-- no translation found for roamingText2 (8969929049081268115) -->
+ <skip />
+ <!-- no translation found for roamingText3 (5148255027043943317) -->
+ <skip />
+ <!-- no translation found for roamingText4 (8808456682550796530) -->
+ <skip />
+ <!-- no translation found for roamingText5 (7604063252850354350) -->
+ <skip />
+ <!-- no translation found for roamingText6 (2059440825782871513) -->
+ <skip />
+ <!-- no translation found for roamingText7 (7112078724097233605) -->
+ <skip />
+ <!-- no translation found for roamingText8 (5989569778604089291) -->
+ <skip />
+ <!-- no translation found for roamingText9 (7969296811355152491) -->
+ <skip />
+ <!-- no translation found for roamingText10 (3992906999815316417) -->
+ <skip />
+ <!-- no translation found for roamingText11 (4154476854426920970) -->
+ <skip />
+ <!-- no translation found for roamingText12 (1189071119992726320) -->
+ <skip />
+ <!-- no translation found for roamingTextSearching (8360141885972279963) -->
+ <skip />
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
+ <!-- no translation found for fcComplete (3118848230966886575) -->
+ <skip />
+ <!-- no translation found for fcError (3327560126588500777) -->
+ <skip />
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"ウェブページにエラーがあります。"</string>
+ <string name="httpErrorLookup">"URLが見つかりません。"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"このサイトの認証方式には対応していません。"</string>
+ <string name="httpErrorAuth">"認証できませんでした。"</string>
+ <string name="httpErrorProxyAuth">"プロキシサーバーを使用した認証に失敗しました。"</string>
+ <string name="httpErrorConnect">"サーバーに接続できませんでした。"</string>
+ <string name="httpErrorIO">"サーバーと通信できませんでした。しばらくしてからもう一度試してください。"</string>
+ <string name="httpErrorTimeout">"サーバーへの接続がタイムアウトになりました。"</string>
+ <string name="httpErrorRedirectLoop">"このページはサーバーのリダイレクトが多すぎます。"</string>
+ <string name="httpErrorUnsupportedScheme">"このプロトコルには対応していません。"</string>
+ <string name="httpErrorFailedSslHandshake">"安全な接続を確立できませんでした。"</string>
+ <string name="httpErrorBadUrl">"URLが無効なのでページを表示できませんでした。"</string>
+ <string name="httpErrorFile">"ファイルにアクセスできませんでした。"</string>
+ <string name="httpErrorFileNotFound">"要求されたファイルが見つかりませんでした。"</string>
+ <string name="httpErrorTooManyRequests">"処理中のリクエストが多すぎます。しばらくしてからもう一度試してください。"</string>
+ <string name="contentServiceSync">"同期"</string>
+ <string name="contentServiceSyncNotificationTitle">"同期"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
+ <string name="low_memory">"電話のメモリがいっぱいです。ファイルを削除してメモリを解放してください。"</string>
+ <string name="me">"自分"</string>
+ <string name="power_dialog">"携帯電話オプション"</string>
+ <string name="silent_mode">"マナーモード"</string>
+ <string name="turn_on_radio">"ワイヤレス接続をONにする"</string>
+ <string name="turn_off_radio">"ワイヤレス接続をOFFにする"</string>
+ <string name="screen_lock">"画面をロック"</string>
+ <string name="power_off">"電源を切る"</string>
+ <string name="shutdown_progress">"シャットダウン中..."</string>
+ <string name="shutdown_confirm">"携帯電話の電源を切ります。"</string>
+ <string name="no_recent_tasks">"最近使ったアプリケーションはありません。"</string>
+ <string name="global_actions">"携帯電話オプション"</string>
+ <string name="global_action_lock">"画面ロック"</string>
+ <string name="global_action_power_off">"電源を切る"</string>
+ <string name="global_action_toggle_silent_mode">"マナーモード"</string>
+ <string name="global_action_silent_mode_on_status">"サウンドOFF"</string>
+ <string name="global_action_silent_mode_off_status">"サウンドON"</string>
+ <string name="global_actions_toggle_airplane_mode">"機内モード"</string>
+ <string name="global_actions_airplane_mode_on_status">"機内モードON"</string>
+ <string name="global_actions_airplane_mode_off_status">"機内モードOFF"</string>
+ <string name="safeMode">"セーフモード"</string>
+ <string name="android_system_label">"Androidシステム"</string>
+ <string name="permgrouplab_costMoney">"料金の発生するサービス"</string>
+ <string name="permgroupdesc_costMoney">"料金の発生する操作をアプリケーションに許可します。"</string>
+ <string name="permgrouplab_messages">"送受信したメッセージ"</string>
+ <string name="permgroupdesc_messages">"SMS、メールなどのメッセージの読み書き"</string>
+ <string name="permgrouplab_personalInfo">"個人情報"</string>
+ <string name="permgroupdesc_personalInfo">"端末の連絡先とカレンダーに直接アクセス"</string>
+ <string name="permgrouplab_location">"現在地"</string>
+ <string name="permgroupdesc_location">"現在地を追跡"</string>
+ <string name="permgrouplab_network">"ネットワーク通信"</string>
+ <string name="permgroupdesc_network">"ネットワークのさまざまな機能へのアクセスをアプリケーションに許可します。"</string>
+ <string name="permgrouplab_accounts">"Googleアカウント"</string>
+ <string name="permgroupdesc_accounts">"利用可能なGoogleアカウントへのアクセス"</string>
+ <string name="permgrouplab_hardwareControls">"ハードウェアの制御"</string>
+ <string name="permgroupdesc_hardwareControls">"携帯電話のハードウェアに直接アクセスします。"</string>
+ <string name="permgrouplab_phoneCalls">"電話/通話"</string>
+ <string name="permgroupdesc_phoneCalls">"通話の監視、記録、処理"</string>
+ <string name="permgrouplab_systemTools">"システムツール"</string>
+ <string name="permgroupdesc_systemTools">"システムの低レベルのアクセスと制御"</string>
+ <string name="permgrouplab_developmentTools">"開発ツール"</string>
+ <string name="permgroupdesc_developmentTools">"アプリケーションのデベロッパーにのみ必要な機能です。"</string>
+ <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
+ <skip />
+ <string name="permlab_statusBar">"ステータスバーの無効化や変更"</string>
+ <string name="permdesc_statusBar">"ステータスバーの無効化やシステムアイコンの追加や削除をアプリケーションに許可します。"</string>
+ <string name="permlab_expandStatusBar">"ステータスバーの拡大/縮小"</string>
+ <string name="permdesc_expandStatusBar">"ステータスバーの拡大や縮小をアプリケーションに許可します。"</string>
+ <string name="permlab_processOutgoingCalls">"発信の傍受"</string>
+ <string name="permdesc_processOutgoingCalls">"通話発信とダイヤルする番号の変更をアプリケーションに許可します。悪意のあるアプリケーションが発信を監視、転送、阻止する恐れがあります。"</string>
+ <string name="permlab_receiveSms">"SMSの受信"</string>
+ <string name="permdesc_receiveSms">"SMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+ <string name="permlab_receiveMms">"MMSの受信"</string>
+ <string name="permdesc_receiveMms">"MMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+ <string name="permlab_sendSms">"SMSメッセージの送信"</string>
+ <string name="permdesc_sendSms">"SMSメッセージの送信をアプリケーションに許可します。悪意のあるアプリケーションが確認なしでメッセージを送信し、料金が発生する恐れがあります。"</string>
+ <string name="permlab_readSms">"SMSの読み取り"</string>
+ <string name="permdesc_readSms">"携帯電話やSIMカードに保存したSMSメッセージの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが機密メッセージを読み取る恐れがあります。"</string>
+ <string name="permlab_writeSms">"SMSの編集"</string>
+ <string name="permdesc_writeSms">"携帯電話やSIMカードに保存したSMSメッセージへの書き込みをアプリケーションに許可します。悪意のあるアプリケーションがメッセージを削除する恐れがあります。"</string>
+ <string name="permlab_receiveWapPush">"WAPの受信"</string>
+ <string name="permdesc_receiveWapPush">"WAPメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
+ <string name="permlab_getTasks">"実行中のアプリケーションの取得"</string>
+ <string name="permdesc_getTasks">"現在実行中または最近実行したタスクに関する情報の取得をアプリケーションに許可します。悪意のあるアプリケーションが他のアプリケーションの非公開情報を取得する恐れがあります。"</string>
+ <string name="permlab_reorderTasks">"実行中のアプリケーションの順序の変更"</string>
+ <string name="permdesc_reorderTasks">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリケーションに許可します。悪意のあるアプリケーションが優先されて、コントロールできなくなる恐れがあります。"</string>
+ <string name="permlab_setDebugApp">"アプリケーションのデバッグを有効にする"</string>
+ <string name="permdesc_setDebugApp">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。悪意のあるアプリケーションが別のアプリケーションを終了させる恐れがあります。"</string>
+ <string name="permlab_changeConfiguration">"UI設定の変更"</string>
+ <string name="permdesc_changeConfiguration">"地域/言語やフォントのサイズなど、現在の設定の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_restartPackages">"他のアプリケーションの再起動"</string>
+ <string name="permdesc_restartPackages">"他のアプリケーションの強制的な再起動をアプリケーションに許可します。"</string>
+ <string name="permlab_forceBack">"アプリケーションの強制終了"</string>
+ <string name="permdesc_forceBack">"フォアグラウンドで実行されている操作を強制終了して戻ることをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+ <string name="permlab_dump">"システムの内部状態の取得"</string>
+ <string name="permdesc_dump">"システムの内部状態の取得をアプリケーションに許可します。悪意のあるアプリケーションが、通常は必要としない広範囲にわたる非公開の機密情報を取得する恐れがあります。"</string>
+ <!-- no translation found for permlab_shutdown (7185747824038909016) -->
+ <skip />
+ <!-- no translation found for permdesc_shutdown (7046500838746291775) -->
+ <skip />
+ <!-- no translation found for permlab_stopAppSwitches (4138608610717425573) -->
+ <skip />
+ <!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
+ <skip />
+ <string name="permlab_runSetActivityWatcher">"起動中のすべてのアプリケーションの監視と制御"</string>
+ <string name="permdesc_runSetActivityWatcher">"システムが起動する操作の監視と制御をアプリケーションに許可します。悪意のあるアプリケーションがシステムを完全に破壊する恐れがあります。この許可は開発にのみ必要で、携帯電話の通常の使用にはまったく必要ありません。"</string>
+ <string name="permlab_broadcastPackageRemoved">"パッケージ削除ブロードキャストの送信"</string>
+ <string name="permdesc_broadcastPackageRemoved">"アプリケーションパッケージの削除の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションが他の実行中のアプリケーションを強制終了する恐れがあります。"</string>
+ <string name="permlab_broadcastSmsReceived">"SMS受信ブロードキャストの送信"</string>
+ <string name="permdesc_broadcastSmsReceived">"SMSメッセージの受信通知の配信をアプリケーションに許可します。悪意のあるアプリケーションが受信SMSメッセージを偽造する恐れがあります。"</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH受信ブロードキャストの送信"</string>
+ <string name="permdesc_broadcastWapPush">"WAP PUSHメッセージの受信の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションがMMS受信メッセージを偽造したり、ウェブページのコンテンツを密かに改ざんする恐れがあります。"</string>
+ <string name="permlab_setProcessLimit">"実行中のプロセスの数を制限"</string>
+ <string name="permdesc_setProcessLimit">"実行するプロセス数の上限の制御をアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+ <string name="permlab_setAlwaysFinish">"バックグラウンドアプリケーションをすべて終了する"</string>
+ <string name="permdesc_setAlwaysFinish">"バックグラウンドになり次第必ず操作を終了させるかどうかの制御をアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+ <string name="permlab_batteryStats">"電池統計情報の変国"</string>
+ <string name="permdesc_batteryStats">"収集した電池統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
+ <!-- no translation found for permlab_backup (470013022865453920) -->
+ <skip />
+ <!-- no translation found for permdesc_backup (2305432853944929371) -->
+ <skip />
+ <string name="permlab_internalSystemWindow">"未許可のウィンドウの表示"</string>
+ <string name="permdesc_internalSystemWindow">"内部システムのユーザーインターフェースで使用するためのウィンドウ作成を許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_systemAlertWindow">"システムレベルの警告の表示"</string>
+ <string name="permdesc_systemAlertWindow">"システムの警告ウィンドウの表示をアプリケーションに許可します。悪意のあるアプリケーションが携帯電話の画面全体を偽装する恐れがあります。"</string>
+ <string name="permlab_setAnimationScale">"アニメーションのプリセット速度の変更"</string>
+ <string name="permdesc_setAnimationScale">"いつでもアニメーション全般の速度を変更する (アニメーションを速くまたは遅くする) ことをアプリケーションに許可します。"</string>
+ <string name="permlab_manageAppTokens">"アプリケーショントークンの管理"</string>
+ <string name="permdesc_manageAppTokens">"通常のZ-orderingを回避して、独自のトークンを作成、管理することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+ <string name="permlab_injectEvents">"キーを押してボタンをコントロール"</string>
+ <string name="permdesc_injectEvents">"入力イベント (キーを押すなど) を別のアプリケーションに伝えることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話を乗っ取る恐れがあります。"</string>
+ <string name="permlab_readInputState">"入力や操作の記録"</string>
+ <string name="permdesc_readInputState">"別のアプリケーションへの入力(パスワードなど)でもキー入力を監視することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+ <string name="permlab_bindInputMethod">"入力方法に関連付ける"</string>
+ <string name="permdesc_bindInputMethod">"入力方法のトップレベルインターフェースに関連付けることを所有者に許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+ <string name="permlab_setOrientation">"画面の向きの変更"</string>
+ <string name="permdesc_setOrientation">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
+ <string name="permlab_signalPersistentProcesses">"Linuxのシグナルをアプリケーションに送信"</string>
+ <string name="permdesc_signalPersistentProcesses">"受信した電波を継続プロセスに送信することをアプリケーションに許可します。"</string>
+ <string name="permlab_persistentActivity">"アプリケーションを常に実行する"</string>
+ <string name="permdesc_persistentActivity">"自身を部分的に永続させて、他のアプリケーション用にはその領域をシステムに使わせないようにすることをアプリケーションに許可します。"</string>
+ <string name="permlab_deletePackages">"アプリケーションの削除"</string>
+ <string name="permdesc_deletePackages">"Androidパッケージの削除をアプリケーションに許可します。悪意のあるアプリケーションが、重要なアプリケーションを削除する恐れがあります。"</string>
+ <string name="permlab_clearAppUserData">"他のアプリケーションのデータを削除"</string>
+ <string name="permdesc_clearAppUserData">"ユーザーデータの消去をアプリケーションに許可します。"</string>
+ <string name="permlab_deleteCacheFiles">"他のアプリケーションのキャッシュを削除"</string>
+ <string name="permdesc_deleteCacheFiles">"キャッシュファイルの削除をアプリケーションに許可します。"</string>
+ <string name="permlab_getPackageSize">"アプリケーションのメモリ容量の計測"</string>
+ <string name="permdesc_getPackageSize">"アプリケーションのコード、データ、キャッシュのサイズを取得することを許可します。"</string>
+ <string name="permlab_installPackages">"アプリケーションを直接インストール"</string>
+ <string name="permdesc_installPackages">"Androidパッケージのインストール/更新をアプリケーションに許可します。悪意のあるアプリケーションが、勝手に強力な権限を持つ新しいアプリケーションを追加する恐れがあります。"</string>
+ <string name="permlab_clearAppCache">"アプリケーションキャッシュデータの削除"</string>
+ <string name="permdesc_clearAppCache">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string>
+ <string name="permlab_readLogs">"システムログファイルの読み取り"</string>
+ <string name="permdesc_readLogs">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string>
+ <string name="permlab_diagnostic">"diagが所有するリソースの読み書き"</string>
+ <string name="permdesc_diagnostic">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string>
+ <string name="permlab_changeComponentState">"アプリケーションのコンポーネントを有効/無効にする"</string>
+ <string name="permdesc_changeComponentState">"別アプリケーションのコンポーネントの有効/無効を変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話の重要な機能を無効にする恐れがあります。アプリケーションコンポーネントが利用できない、整合性が取れない、または不安定な状態になる恐れがあるので、許可には注意が必要です。"</string>
+ <string name="permlab_setPreferredApplications">"優先アプリケーションの設定"</string>
+ <string name="permdesc_setPreferredApplications">"優先アプリケーションを変更することをアプリケーションに許可します。悪意のあるアプリケーションが実行中のアプリケーションを密かに変更し、既存のアプリケーションになりすまして非公開データを収集する恐れがあります。"</string>
+ <string name="permlab_writeSettings">"システムの全般設定の変更"</string>
+ <string name="permdesc_writeSettings">"システム設定データの変更をアプリケーションに許可します。悪意のあるアプリケーションがシステム設定を破壊する恐れがあります。"</string>
+ <string name="permlab_writeSecureSettings">"システムのセキュリティ設定の変更"</string>
+ <string name="permdesc_writeSecureSettings">"システムのセキュリティ設定の変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_writeGservices">"Googleサービスの地図の変更"</string>
+ <string name="permdesc_writeGservices">"Googleサービスマップの変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_receiveBootCompleted">"起動時に自動的に開始"</string>
+ <string name="permdesc_receiveBootCompleted">"システムの起動後に自動的に起動することをアプリケーションに許可します。携帯電話の起動に時間がかかるようになり、アプリケーションが常に実行されるために携帯電話の全体的な動作が遅くなります。"</string>
+ <string name="permlab_broadcastSticky">"stickyブロードキャストの配信"</string>
+ <string name="permdesc_broadcastSticky">"配信が終了してもメモリに残るようなstickyブロードキャストをアプリケーションに許可します。悪意のあるアプリケーションがメモリを使いすぎて、携帯電話の動作が遅くなったり、不安定になる恐れがあります。"</string>
+ <string name="permlab_readContacts">"連絡先データの読み取り"</string>
+ <string name="permdesc_readContacts">"端末に保存した連絡先(アドレス)データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションがデータを他人に送信する恐れがあります。"</string>
+ <string name="permlab_writeContacts">"連絡先データの書き込み"</string>
+ <string name="permdesc_writeContacts">"端末に保存した連絡先(アドレス)データの変更をアプリケーションに許可します。悪意のあるアプリケーションが連絡先データを消去/変更する恐れがあります。"</string>
+ <string name="permlab_writeOwnerData">"所有者データの書き込み"</string>
+ <string name="permdesc_writeOwnerData">"端末に保存した所有者のデータの変更をアプリケーションに許可します。悪意のあるアプリケーションが所有者のデータを消去/変更する恐れがあります。"</string>
+ <string name="permlab_readOwnerData">"所有者データの読み取り"</string>
+ <string name="permdesc_readOwnerData">"携帯電話に保存した所有者データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが所有者データを読み取る恐れがあります。"</string>
+ <string name="permlab_readCalendar">"カレンダーデータの読み取り"</string>
+ <string name="permdesc_readCalendar">"端末に保存したカレンダーの予定の読み取りをアプリケーションに許可します。悪意のあるアプリケーションがカレンダーの予定を他人に送信する恐れがあります。"</string>
+ <string name="permlab_writeCalendar">"カレンダーデータの書き込み"</string>
+ <string name="permdesc_writeCalendar">"端末に保存したカレンダーの予定の変更をアプリケーションに許可します。悪意のあるアプリケーションが、カレンダーデータを消去/変更する恐れがあります。"</string>
+ <string name="permlab_accessMockLocation">"仮の位置情報でテスト"</string>
+ <string name="permdesc_accessMockLocation">"テスト用に仮の位置情報源を作成します。これにより悪意のあるアプリケーションが、GPS、ネットワークプロバイダなどから返される本当の位置情報や状況を改ざんする恐れがあります。"</string>
+ <string name="permlab_accessLocationExtraCommands">"位置情報提供者の追加コマンドアクセス"</string>
+ <string name="permdesc_accessLocationExtraCommands">"位置情報提供元の追加コマンドにアクセスします。悪意のあるアプリケーションがGPSなどの位置提供の動作を妨害する恐れがあります。"</string>
+ <!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
+ <skip />
+ <!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
+ <skip />
+ <string name="permlab_accessFineLocation">"精細な位置情報(GPS)"</string>
+ <string name="permdesc_accessFineLocation">"GPSなど携帯電話の位置情報にアクセスします(可能な場合)。今いる場所が悪意のあるアプリケーションに検出されたり、バッテリーの消費が増える恐れがあります。"</string>
+ <string name="permlab_accessCoarseLocation">"おおよその位置情報(ネットワーク基地局)"</string>
+ <string name="permdesc_accessCoarseLocation">"セルラーネットワークデータベースなど、携帯電話のおおよその位置を特定する情報源が利用可能な場合にアクセスします。これにより悪意のあるアプリケーションが、ユーザーのおおよその位置を特定できる恐れがあります。"</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlingerへのアクセス"</string>
+ <string name="permdesc_accessSurfaceFlinger">"SurfaceFlingerの低レベルの機能の使用をアプリケーションに許可します。"</string>
+ <string name="permlab_readFrameBuffer">"フレームバッファの読み取り"</string>
+ <string name="permdesc_readFrameBuffer">"フレームバッファの内容の読み取りと使用をアプリケーションに許可します。"</string>
+ <string name="permlab_modifyAudioSettings">"音声設定の変更"</string>
+ <string name="permdesc_modifyAudioSettings">"音量や転送などの音声全般の設定の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_recordAudio">"録音"</string>
+ <string name="permdesc_recordAudio">"オーディオ録音パスへのアクセスをアプリケーションに許可します。"</string>
+ <string name="permlab_camera">"写真の撮影"</string>
+ <string name="permdesc_camera">"カメラでの写真撮影をアプリケーションに許可します。アプリケーションはカメラから画像をいつでも収集できます。"</string>
+ <string name="permlab_brick">"端末を永続的に無効にする"</string>
+ <string name="permdesc_brick">"携帯電話全体を永続的に無効にすることをアプリケーションに許可します。この許可は非常に危険です。"</string>
+ <string name="permlab_reboot">"端末の再起動"</string>
+ <string name="permdesc_reboot">"端末の強制的な再起動をアプリケーションに許可します。"</string>
+ <string name="permlab_mount_unmount_filesystems">"ファイルシステムのマウントとマウント解除"</string>
+ <string name="permdesc_mount_unmount_filesystems">"リムーバブルメモリのファイルシステムのマウントとマウント解除をアプリケーションに許可します。"</string>
+ <string name="permlab_mount_format_filesystems">"外部ストレージのフォーマット"</string>
+ <string name="permdesc_mount_format_filesystems">"アプリケーションがリムーバブルストレージをフォーマットすることを許可します。"</string>
+ <string name="permlab_vibrate">"バイブレーション制御"</string>
+ <string name="permdesc_vibrate">"バイブレーションの制御をアプリケーションに許可します。"</string>
+ <string name="permlab_flashlight">"ライトのコントロール"</string>
+ <string name="permdesc_flashlight">"ライトの制御をアプリケーションに許可します。"</string>
+ <string name="permlab_hardware_test">"ハードウェアのテスト"</string>
+ <string name="permdesc_hardware_test">"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"</string>
+ <string name="permlab_callPhone">"電話番号発信"</string>
+ <string name="permdesc_callPhone">"電話番号の自動発信をアプリケーションに許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急通報への発信は許可しません。"</string>
+ <string name="permlab_callPrivileged">"電話番号発信"</string>
+ <string name="permdesc_callPrivileged">"緊急通報を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。"</string>
+ <string name="permlab_locationUpdates">"位置情報の更新通知"</string>
+ <string name="permdesc_locationUpdates">"無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_checkinProperties">"チェックインプロパティへのアクセス"</string>
+ <string name="permdesc_checkinProperties">"チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_bindGadget">"ウィジェットの選択"</string>
+ <string name="permdesc_bindGadget">"どのアプリケーションがどのウィジェットを使用できるかシステムに指定することをこのアプリケーションに許可します。これにより、アプリケーション間で個人データにアクセスできるようになります。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_modifyPhoneState">"端末ステータスの変更"</string>
+ <string name="permdesc_modifyPhoneState">"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
+ <string name="permlab_readPhoneState">"端末ステータスの読み取り"</string>
+ <string name="permdesc_readPhoneState">"端末の電話機能へのアクセスをアプリケーションに許可します。アプリケーションは、この携帯電話の電話番号、通話中かどうか、通話相手の電話番号などを特定できます。"</string>
+ <string name="permlab_wakeLock">"端末のスリープを無効にする"</string>
+ <string name="permdesc_wakeLock">"端末のスリープを無効にすることをアプリケーションに許可します。"</string>
+ <string name="permlab_devicePower">"電源のON/OFF"</string>
+ <string name="permdesc_devicePower">"携帯電話の電源のオン/オフをアプリケーションに許可します。"</string>
+ <string name="permlab_factoryTest">"出荷時試験モードでの実行"</string>
+ <string name="permdesc_factoryTest">"携帯電話のハードウェアへのアクセスを完全に許可して、低レベルのメーカーテストとして実行します。メーカーのテストモードで携帯電話を使用するときのみ利用できます。"</string>
+ <string name="permlab_setWallpaper">"壁紙の設定"</string>
+ <string name="permdesc_setWallpaper">"システムの壁紙の設定をアプリケーションに許可します。"</string>
+ <string name="permlab_setWallpaperHints">"壁紙サイズのヒントの設定"</string>
+ <string name="permdesc_setWallpaperHints">"システムの壁紙サイズのヒントの設定をアプリケーションに許可します。"</string>
+ <string name="permlab_masterClear">"システムを出荷時設定にリセット"</string>
+ <string name="permdesc_masterClear">"データ、設定、インストールしたアプリケーションをすべて消去して、完全に出荷時の設定にシステムをリセットすることをアプリケーションに許可します。"</string>
+ <string name="permlab_setTimeZone">"タイムゾーンの設定"</string>
+ <string name="permdesc_setTimeZone">"端末のタイムゾーンの変更をアプリケーションに許可します。"</string>
+ <string name="permlab_getAccounts">"既知のアカウントの取得"</string>
+ <string name="permdesc_getAccounts">"端末内にあるアカウントのリストの取得をアプリケーションに許可します。"</string>
+ <string name="permlab_accessNetworkState">"ネットワーク状態の表示"</string>
+ <string name="permdesc_accessNetworkState">"すべてのネットワーク状態の表示をアプリケーションに許可します。"</string>
+ <string name="permlab_createNetworkSockets">"完全なインターネットアクセス"</string>
+ <string name="permdesc_createNetworkSockets">"ネットワークソケットの作成をアプリケーションに許可します。"</string>
+ <string name="permlab_writeApnSettings">"アクセスポイント名設定の書き込み"</string>
+ <string name="permdesc_writeApnSettings">"APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_changeNetworkState">"ネットワーク接続の変更"</string>
+ <string name="permdesc_changeNetworkState">"ネットワークの接続状態の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"バックグラウンドデータ使用設定の変更"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"バックグラウンドデータ使用の設定の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_accessWifiState">"Wi-Fi状態の表示"</string>
+ <string name="permdesc_accessWifiState">"Wi-Fi状態に関する情報の表示をアプリケーションに許可します。"</string>
+ <string name="permlab_changeWifiState">"Wi-Fi状態の変更"</string>
+ <string name="permdesc_changeWifiState">"Wi-Fiアクセスポイントへの接続や接続の切断、設定されたWi-Fiネットワークの変更をアプリケーションに許可します。"</string>
+ <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
+ <skip />
+ <string name="permlab_bluetoothAdmin">"Bluetoothの管理"</string>
+ <string name="permdesc_bluetoothAdmin">"このBluetooth端末の設定、およびリモート端末を検出してペアに設定することをアプリケーションに許可します。"</string>
+ <string name="permlab_bluetooth">"Bluetooth接続の作成"</string>
+ <string name="permdesc_bluetooth">"このBluetooth端末の設定表示、および別の端末をペアとして設定し接続を承認することをアプリケーションに許可します。"</string>
+ <string name="permlab_disableKeyguard">"キーロックを無効にする"</string>
+ <string name="permdesc_disableKeyguard">"キーロックや関連するパスワードセキュリティを無効にすることをアプリケーションに許可します。正当な利用の例では、かかってきた電話を受信する際にキーロックを無効にし、通話の終了時にキーロックを有効にし直します。"</string>
+ <string name="permlab_readSyncSettings">"同期設定の読み取り"</string>
+ <string name="permdesc_readSyncSettings">"連絡先の同期の有効/無効など、同期設定の読み取りをアプリケーションに許可します。"</string>
+ <string name="permlab_writeSyncSettings">"同期設定の書き込み"</string>
+ <string name="permdesc_writeSyncSettings">"連絡先の同期の有効/無効など、同期設定の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_readSyncStats">"同期統計の読み取り"</string>
+ <string name="permdesc_readSyncStats">"同期状態(同期履歴など)の読み取りをアプリケーションに許可します。"</string>
+ <string name="permlab_subscribedFeedsRead">"登録したフィードの読み取り"</string>
+ <string name="permdesc_subscribedFeedsRead">"現在同期しているフィードの詳細の取得をアプリケーションに許可します。"</string>
+ <string name="permlab_subscribedFeedsWrite">"登録したフィードの書き込み"</string>
+ <string name="permdesc_subscribedFeedsWrite">"現在同期しているフィードの変更をアプリケーションに許可します。悪意のあるアプリケーションが同期フィードを変更する恐れがあります。"</string>
+ <string name="permlab_readDictionary">"ユーザー定義辞書の読み込み"</string>
+ <string name="permdesc_readDictionary">"アプリケーションがユーザー辞書に登録されている個人的な語句や名前を読み込むことを許可します。"</string>
+ <string name="permlab_writeDictionary">"ユーザー定義辞書への書き込み"</string>
+ <string name="permdesc_writeDictionary">"アプリケーションがユーザー辞書に新しい語句を書き込むことを許可します。"</string>
+ <!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
+ <skip />
+ <!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
+ <skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"自宅"</item>
- <item msgid="869923650527136615">"携帯"</item>
- <item msgid="7897544654242874543">"仕事"</item>
- <item msgid="1103601433382158155">"FAX(仕事)"</item>
- <item msgid="1735177144948329370">"FAX(自宅)"</item>
- <item msgid="603878674477207394">"ポケベル"</item>
- <item msgid="1650824275177931637">"その他"</item>
- <item msgid="9192514806975898961">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"携帯"</item>
+ <item>"仕事"</item>
+ <item>"FAX(仕事)"</item>
+ <item>"FAX(自宅)"</item>
+ <item>"ポケベル"</item>
+ <item>"その他"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"自宅"</item>
- <item msgid="7084237356602625604">"仕事"</item>
- <item msgid="1112044410659011023">"その他"</item>
- <item msgid="2374913952870110618">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"その他"</item>
+ <item>"カスタム"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"携帯"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"自宅"</item>
- <item msgid="5629153956045109251">"仕事"</item>
- <item msgid="4966604264500343469">"その他"</item>
- <item msgid="4932682847595299369">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"その他"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"自宅"</item>
- <item msgid="1359644565647383708">"仕事"</item>
- <item msgid="7868549401053615677">"その他"</item>
- <item msgid="3145118944639869809">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"その他"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"仕事"</item>
- <item msgid="4378074129049520373">"その他"</item>
- <item msgid="3455047468583965104">"カスタム"</item>
+ <item>"仕事"</item>
+ <item>"その他"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Googleトーク"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Googleトーク"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PINコードを入力"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PINコードが正しくありません。"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"MENU、0キーでロック解除"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急通報番号"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(通信サービスなし)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"画面ロック中"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"MENUキーでロック解除(または緊急通報)"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"MENUキーでロック解除"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ロックを解除するパターンを入力"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"緊急通報"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"一致しました"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"やり直してください"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"充電中(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"充電完了。"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"充電してください。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIMカードが挿入されていません"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"SIMカードが挿入されていません"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"SIMカードを挿入してください。"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ネットワークがロックされました"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIMカードはPUKでロックされています。"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"ユーザーガイドを参照するか、お客様サポートにお問い合わせください。"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIMカードはロックされています。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIMカードのロック解除中..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"ロック解除のパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しく指定されていません。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度指定してください。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>秒後にやり直してください。"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"パターンを忘れた場合"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"パターンのエラーが多すぎます"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Googleアカウントでログインしてロック解除"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ユーザー名 (メール)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"パスワード"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ログイン"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ユーザー名またはパスワードが正しくありません。"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"クリア"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知なし"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"充電中..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"充電してください"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"電池が残り少なくなっています:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"残量<xliff:g id="NUMBER">%d%%</xliff:g>以下"</string>
- <string name="battery_low_why" msgid="7655196144309694753">"理由"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"出荷時試験が失敗"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST操作は、/system/appにインストールされたパッケージのみが対象です。"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST操作を行うパッケージは見つかりませんでした。"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"再起動"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"ページ「<xliff:g id="TITLE">%s</xliff:g>」の記述:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。"</string>
- <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ブラウザの履歴とブックマークを読み取る"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"ブラウザでアクセスしたすべてのURLおよびブラウザのすべてのブックマークの読み取りをアプリケーションに許可します。"</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"ブラウザの履歴とブックマークを書き込む"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"携帯電話に保存されているブラウザの履歴やブックマークの修正をアプリケーショに許可します。これにより悪意のあるアプリケーションが、ブラウザのデータを消去または変更する恐れがあります。"</string>
- <string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"保存"</string>
- <string name="save_password_never" msgid="8274330296785855105">"保存しない"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"このページへのアクセスは許可されていません。"</string>
- <string name="text_copied" msgid="4985729524670131385">"テキストをクリップボードにコピーしました。"</string>
- <string name="more_item_label" msgid="4650918923083320495">"その他"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"Space"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"Del"</string>
- <string name="search_go" msgid="8298016669822141719">"検索"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1か月前"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1か月前"</string>
+ <string name="keyguard_password_enter_pin_code">"PINコードを入力"</string>
+ <string name="keyguard_password_wrong_pin_code">"PINコードが正しくありません。"</string>
+ <string name="keyguard_label_text">"MENU、0キーでロック解除"</string>
+ <string name="emergency_call_dialog_number_for_display">"緊急通報番号"</string>
+ <string name="lockscreen_carrier_default">"(通信サービスなし)"</string>
+ <string name="lockscreen_screen_locked">"画面ロック中"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"MENUキーでロック解除(または緊急通報)"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"MENUキーでロック解除"</string>
+ <string name="lockscreen_pattern_instructions">"ロックを解除するパターンを入力"</string>
+ <string name="lockscreen_emergency_call">"緊急通報"</string>
+ <string name="lockscreen_pattern_correct">"一致しました"</string>
+ <string name="lockscreen_pattern_wrong">"やり直してください"</string>
+ <string name="lockscreen_plugged_in">"充電中(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"充電してください。"</string>
+ <string name="lockscreen_missing_sim_message_short">"SIMカードが挿入されていません"</string>
+ <string name="lockscreen_missing_sim_message">"SIMカードが挿入されていません"</string>
+ <string name="lockscreen_missing_sim_instructions">"SIMカードを挿入してください。"</string>
+ <string name="lockscreen_network_locked_message">"ネットワークがロックされました"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIMカードはPUKでロックされています。"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"ユーザーガイドを参照するか、お客様サポートにお問い合わせください。"</string>
+ <string name="lockscreen_sim_locked_message">"SIMカードはロックされています。"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIMカードのロック解除中..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"ロック解除のパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しく指定されていません。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度指定してください。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>秒後にやり直してください。"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"パターンを忘れた場合"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"パターンのエラーが多すぎます"</string>
+ <string name="lockscreen_glogin_instructions">"Googleアカウントでログインしてロック解除"</string>
+ <string name="lockscreen_glogin_username_hint">"ユーザー名 (メール)"</string>
+ <string name="lockscreen_glogin_password_hint">"パスワード"</string>
+ <string name="lockscreen_glogin_submit_button">"ログイン"</string>
+ <string name="lockscreen_glogin_invalid_input">"ユーザー名またはパスワードが正しくありません。"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"通知なし"</string>
+ <string name="status_bar_ongoing_events_title">"実行中"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"充電中..."</string>
+ <string name="battery_low_title">"充電してください"</string>
+ <string name="battery_low_subtitle">"電池が残り少なくなっています:"</string>
+ <string name="battery_low_percent_format">"残量<xliff:g id="NUMBER">%d%%</xliff:g>以下"</string>
+ <!-- no translation found for battery_low_why (7655196144309694753) -->
+ <skip />
+ <string name="factorytest_failed">"出荷時試験が失敗"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST操作は、/system/appにインストールされたパッケージのみが対象です。"</string>
+ <string name="factorytest_no_action">"FACTORY_TEST操作を行うパッケージは見つかりませんでした。"</string>
+ <string name="factorytest_reboot">"再起動"</string>
+ <string name="js_dialog_title">"ページ「<xliff:g id="TITLE">%s</xliff:g>」の記述:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。"</string>
+ <string name="save_password_label">"確認"</string>
+ <!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
+ <skip />
+ <!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
+ <skip />
+ <!-- no translation found for permlab_writeHistoryBookmarks (9009434109836280374) -->
+ <skip />
+ <!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
+ <skip />
+ <string name="save_password_message">"このパスワードをブラウザで保存しますか?"</string>
+ <string name="save_password_notnow">"今は保存しない"</string>
+ <string name="save_password_remember">"保存"</string>
+ <string name="save_password_never">"保存しない"</string>
+ <string name="open_permission_deny">"このページへのアクセスは許可されていません。"</string>
+ <string name="text_copied">"テキストをクリップボードにコピーしました。"</string>
+ <string name="more_item_label">"その他"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"Space"</string>
+ <string name="menu_enter_shortcut_label">"Enter"</string>
+ <string name="menu_delete_shortcut_label">"Del"</string>
+ <string name="search_go">"検索"</string>
+ <string name="oneMonthDurationPast">"1か月前"</string>
+ <string name="beforeOneMonthDurationPast">"1か月前"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
+ <item quantity="one">"1秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1分前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
+ <item quantity="one">"1分前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1時間前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
+ <item quantity="one">"1時間前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨日"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
+ <item quantity="one">"昨日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1秒後"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+ <item quantity="one">"1秒後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1分後"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ <item quantity="one">"1分後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1時間後"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+ <item quantity="one">"1時間後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明日"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+ <item quantity="one">"明日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
+ <item quantity="one">"1秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1分前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
+ <item quantity="one">"1分前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1時間前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
+ <item quantity="one">"1時間前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨日"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
+ <item quantity="one">"昨日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1秒後"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+ <item quantity="one">"1秒後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1分後"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ <item quantity="one">"1分後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1時間後"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+ <item quantity="one">"1時間後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明日"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+ <item quantity="one">"明日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s年"</string>
- <string name="day" msgid="8144195776058119424">"日"</string>
- <string name="days" msgid="4774547661021344602">"日"</string>
- <string name="hour" msgid="2126771916426189481">"時間"</string>
- <string name="hours" msgid="894424005266852993">"時間"</string>
- <string name="minute" msgid="9148878657703769868">"分"</string>
- <string name="minutes" msgid="5646001005827034509">"分"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"週間"</string>
- <string name="weeks" msgid="6509623834583944518">"週間"</string>
- <string name="year" msgid="4001118221013892076">"年"</string>
- <string name="years" msgid="6881577717993213522">"年"</string>
- <string name="every_weekday" msgid="8777593878457748503">"平日(月~金)"</string>
- <string name="daily" msgid="5738949095624133403">"毎日"</string>
- <string name="weekly" msgid="983428358394268344">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"毎月"</string>
- <string name="yearly" msgid="1519577999407493836">"毎年"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"動画を再生できません"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"この動画はご使用の端末でストリーミングできません。"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"この動画は再生できません。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"正午"</string>
- <string name="Noon" msgid="3342127745230013127">"正午"</string>
- <string name="midnight" msgid="7166259508850457595">"午前0時"</string>
- <string name="Midnight" msgid="5630806906897892201">"午前0時"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"すべて選択"</string>
- <string name="selectText" msgid="3889149123626888637">"テキストを選択"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"テキストの選択を終了"</string>
- <string name="cut" msgid="3092569408438626261">"切り取り"</string>
- <string name="cutAll" msgid="2436383270024931639">"すべて切り取り"</string>
- <string name="copy" msgid="2681946229533511987">"コピー"</string>
- <string name="copyAll" msgid="2590829068100113057">"すべてコピー"</string>
- <string name="paste" msgid="5629880836805036433">"貼り付け"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URLをコピー"</string>
- <string name="inputMethod" msgid="7673923508389094672">"入力方法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"辞書に「%s」を追加"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"テキストを編集"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"空き容量低下"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"携帯電話の空き容量が少なくなっています。"</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"キャンセル"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"アプリケーションを選択"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"常にこの操作で使用する"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"ホームの[設定]>[アプリケーション]>[アプリケーションの管理]でデフォルト設定をクリアします。"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"操作の選択"</string>
- <string name="noApplications" msgid="1691104391758345586">"この操作を実行できるアプリケーションはありません。"</string>
- <string name="aerr_title" msgid="653922989522758100">"エラー"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)が予期せず停止しました。やり直してください。"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g>が予期せず停止しました。やり直してください。"</string>
- <string name="anr_title" msgid="3100070910664756057">"エラー"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(<xliff:g id="APPLICATION">%2$s</xliff:g>)は応答していません。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(プロセス: <xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g>は応答していません。"</string>
- <string name="force_close" msgid="3653416315450806396">"強制終了"</string>
- <string name="report" msgid="4060218260984795706">"レポート"</string>
- <string name="wait" msgid="7147118217226317732">"待機"</string>
- <string name="debug" msgid="9103374629678531849">"デバッグ"</string>
- <string name="sendText" msgid="5132506121645618310">"アプリケーションを選択"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"着信音量"</string>
- <string name="volume_music" msgid="5421651157138628171">"メディアの音量"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth経由で再生中です"</string>
- <string name="volume_call" msgid="3941680041282788711">"通話音量"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth着信音量"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"アラームの音量"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音量"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音量"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"プリセット着信音"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"端末の基本着信音(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"サイレント"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"着信音"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"不明な着信音"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s年"</string>
+ <string name="day">"日"</string>
+ <string name="days">"日"</string>
+ <string name="hour">"時間"</string>
+ <string name="hours">"時間"</string>
+ <string name="minute">"分"</string>
+ <string name="minutes">"分"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"週間"</string>
+ <string name="weeks">"週間"</string>
+ <string name="year">"年"</string>
+ <string name="years">"年"</string>
+ <string name="every_weekday">"平日(月~金)"</string>
+ <string name="daily">"毎日"</string>
+ <string name="weekly">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"毎月"</string>
+ <string name="yearly">"毎年"</string>
+ <string name="VideoView_error_title">"動画を再生できません"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"この動画はご使用の端末でストリーミングできません。"</string>
+ <string name="VideoView_error_text_unknown">"この動画は再生できません。"</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"正午"</string>
+ <string name="Noon">"正午"</string>
+ <string name="midnight">"午前0時"</string>
+ <string name="Midnight">"午前0時"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"すべて選択"</string>
+ <string name="selectText">"テキストを選択"</string>
+ <string name="stopSelectingText">"テキストの選択を終了"</string>
+ <string name="cut">"切り取り"</string>
+ <string name="cutAll">"すべて切り取り"</string>
+ <string name="copy">"コピー"</string>
+ <string name="copyAll">"すべてコピー"</string>
+ <string name="paste">"貼り付け"</string>
+ <string name="copyUrl">"URLをコピー"</string>
+ <string name="inputMethod">"入力方法"</string>
+ <string name="addToDictionary">"辞書に「%s」を追加"</string>
+ <string name="editTextMenuTitle">"テキストを編集"</string>
+ <string name="low_internal_storage_view_title">"空き容量低下"</string>
+ <string name="low_internal_storage_view_text">"携帯電話の空き容量が少なくなっています。"</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"キャンセル"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"キャンセル"</string>
+ <string name="dialog_alert_title">"注意"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"アプリケーションを選択"</string>
+ <string name="alwaysUse">"常にこの操作で使用する"</string>
+ <string name="clearDefaultHintMsg">"ホームの[設定]>[アプリケーション]>[アプリケーションの管理]でデフォルト設定をクリアします。"</string>
+ <string name="chooseActivity">"操作の選択"</string>
+ <string name="noApplications">"この操作を実行できるアプリケーションはありません。"</string>
+ <string name="aerr_title">"エラー"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)が予期せず停止しました。やり直してください。"</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>が予期せず停止しました。やり直してください。"</string>
+ <string name="anr_title">"エラー"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(<xliff:g id="APPLICATION">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(プロセス: <xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>は応答していません。"</string>
+ <string name="force_close">"強制終了"</string>
+ <!-- no translation found for report (4060218260984795706) -->
+ <skip />
+ <string name="wait">"待機"</string>
+ <string name="debug">"デバッグ"</string>
+ <string name="sendText">"アプリケーションを選択"</string>
+ <string name="volume_ringtone">"着信音量"</string>
+ <string name="volume_music">"メディアの音量"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth経由で再生中です"</string>
+ <string name="volume_call">"通話音量"</string>
+ <string name="volume_bluetooth_call">"Bluetooth着信音量"</string>
+ <string name="volume_alarm">"アラームの音量"</string>
+ <string name="volume_notification">"通知音量"</string>
+ <string name="volume_unknown">"音量"</string>
+ <string name="ringtone_default">"プリセット着信音"</string>
+ <string name="ringtone_default_with_actual">"端末の基本着信音(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"サイレント"</string>
+ <string name="ringtone_picker_title">"着信音"</string>
+ <string name="ringtone_unknown">"不明な着信音"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fiを利用できます"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fiを利用できます"</item>
+ <item quantity="one">"Wi-Fiを利用できます"</item>
+ <item quantity="other">"Wi-Fiを利用できます"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Wi-Fiオープンネットワークが利用できます"</item>
- <item quantity="other" msgid="7915895323644292768">"Wi-Fiオープンネットワークが利用できます"</item>
+ <item quantity="one">"Wi-Fiオープンネットワークが利用できます"</item>
+ <item quantity="other">"Wi-Fiオープンネットワークが利用できます"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"不明なアプリケーション"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"キャンセル"</string>
- <string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"端末既定"</string>
- <string name="no_permissions" msgid="7283357728219338112">"権限付与の必要はありません"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"隠す"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"すべて表示"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"読み込み中..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB接続"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"USB経由で携帯電話をコンピュータに接続しました。コンピュータと携帯電話のSDカード間でファイルをコピーするには、[マウント]を選択します。"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"マウント"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"マウントしない"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"USBメモリにSDカードを使用する際に問題が発生しました。"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB接続"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"パソコンとの間でファイルをコピーします。"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USBストレージをOFFにする"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USBストレージをOFFにする場合に選択します。"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USBストレージをOFFにする"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USBストレージをOFFにする前にUSBホストのマウントを解除したことを確認してください。USBストレージをOFFにするには[OFF]を選択します。"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"OFF"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"キャンセル"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USBストレージをOFFにする際に問題が発生しました。USBホストのマウントが解除されていることを確認してからもう一度お試しください。"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SDカードをフォーマット"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SDカードをフォーマットしてもよろしいですか?カード内のすべてのデータが失われます。"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"フォーマット"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"コンピュータが携帯に接続されました。"</string>
- <string name="select_input_method" msgid="2086499663193509436">"入力方法の選択"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SDカードの準備中"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"エラーを確認しています。"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"空のSDカード"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SDカードが空か、サポート対象外のファイルシステムを使用しています。"</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"破損したSDカード"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SDカードが破損しています。カードのフォーマットが必要な可能性があります。"</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SDカードが予期せず取り外されました"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"データの喪失を防ぐためSDカードを取り外す前にマウントを解除してください。"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SDカードを安全に取り外しました"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"SDカードは安全に取り外せます。"</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SDカードが取り外されています"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SDカードが取り外されました。新しいカードを挿入してください。"</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"一致するアクティビティが見つかりません"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"コンポーネント使用状況に関する統計情報の更新"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"収集されたコンポーネント使用状況に関する統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ダブルタップでズームします"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"ウィジェットの展開エラー"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"移動"</string>
- <string name="ime_action_search" msgid="658110271822807811">"検索"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"送信"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"次へ"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完了"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"実行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"発信"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"連絡先を新規登録"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"オン"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"オフ"</string>
+ <string name="select_character">"文字を挿入"</string>
+ <string name="sms_control_default_app_name">"不明なアプリケーション"</string>
+ <string name="sms_control_title">"SMSメッセージの送信中"</string>
+ <string name="sms_control_message">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"キャンセル"</string>
+ <string name="date_time_set">"設定"</string>
+ <string name="default_permission_group">"端末既定"</string>
+ <string name="no_permissions">"権限付与の必要はありません"</string>
+ <string name="perms_hide"><b>"隠す"</b></string>
+ <string name="perms_show_all"><b>"すべて表示"</b></string>
+ <string name="googlewebcontenthelper_loading">"読み込み中..."</string>
+ <string name="usb_storage_title">"USB接続"</string>
+ <string name="usb_storage_message">"USB経由で携帯電話をコンピュータに接続しました。コンピュータと携帯電話のSDカード間でファイルをコピーするには、[マウント]を選択します。"</string>
+ <string name="usb_storage_button_mount">"マウント"</string>
+ <string name="usb_storage_button_unmount">"マウントしない"</string>
+ <string name="usb_storage_error_message">"USBメモリにSDカードを使用する際に問題が発生しました。"</string>
+ <string name="usb_storage_notification_title">"USB接続"</string>
+ <string name="usb_storage_notification_message">"パソコンとの間でファイルをコピーします。"</string>
+ <string name="usb_storage_stop_notification_title">"USBストレージをOFFにする"</string>
+ <string name="usb_storage_stop_notification_message">"USBストレージをOFFにする場合に選択します。"</string>
+ <string name="usb_storage_stop_title">"USBストレージをOFFにする"</string>
+ <string name="usb_storage_stop_message">"USBストレージをOFFにする前にUSBホストのマウントを解除したことを確認してください。USBストレージをOFFにするには[OFF]を選択します。"</string>
+ <string name="usb_storage_stop_button_mount">"OFF"</string>
+ <string name="usb_storage_stop_button_unmount">"キャンセル"</string>
+ <string name="usb_storage_stop_error_message">"USBストレージをOFFにする際に問題が発生しました。USBホストのマウントが解除されていることを確認してからもう一度お試しください。"</string>
+ <string name="extmedia_format_title">"SDカードをフォーマット"</string>
+ <string name="extmedia_format_message">"SDカードをフォーマットしてもよろしいですか?カード内のすべてのデータが失われます。"</string>
+ <string name="extmedia_format_button_format">"フォーマット"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"入力方法の選択"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候補"</u></string>
+ <string name="ext_media_checking_notification_title">"SDカードの準備中"</string>
+ <!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
+ <skip />
+ <string name="ext_media_nofs_notification_title">"空のSDカード"</string>
+ <!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
+ <skip />
+ <string name="ext_media_unmountable_notification_title">"破損したSDカード"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
+ <skip />
+ <string name="ext_media_badremoval_notification_title">"SDカードが予期せず取り外されました"</string>
+ <string name="ext_media_badremoval_notification_message">"データの喪失を防ぐためSDカードを取り外す前にマウントを解除してください。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SDカードを安全に取り外しました"</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
+ <skip />
+ <string name="ext_media_nomedia_notification_title">"SDカードが取り外されています"</string>
+ <!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
+ <skip />
+ <string name="activity_list_empty">"一致するアクティビティが見つかりません"</string>
+ <string name="permlab_pkgUsageStats">"コンポーネント使用状況に関する統計情報の更新"</string>
+ <string name="permdesc_pkgUsageStats">"収集されたコンポーネント使用状況に関する統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"ダブルタップでズームします"</string>
+ <string name="gadget_host_error_inflating">"ウィジェットの展開エラー"</string>
+ <string name="ime_action_go">"移動"</string>
+ <string name="ime_action_search">"検索"</string>
+ <string name="ime_action_send">"送信"</string>
+ <string name="ime_action_next">"次へ"</string>
+ <string name="ime_action_done">"完了"</string>
+ <string name="ime_action_default">"実行"</string>
+ <string name="dial_number_using">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"発信"</string>
+ <string name="create_contact_using">"<xliff:g id="NUMBER">%s</xliff:g>を使って"\n"連絡先を新規登録"</string>
+ <!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2e85a10..c3a9c70 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<제목없음>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(전화번호 없음)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(알 수 없음)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"음성메일"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"연결에 문제가 있거나 MMI 코드가 잘못되었습니다."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"서비스를 사용하도록 설정했습니다."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"사용 설정된 서비스 목록:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"서비스가 사용 중지되었습니다."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"등록이 완료되었습니다."</string>
- <string name="serviceErased" msgid="1288584695297200972">"삭제했습니다."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"비밀번호가 잘못되었습니다."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 완료"</string>
- <string name="badPin" msgid="5085454289896032547">"이전 PIN이 올바르지 않습니다."</string>
- <string name="badPuk" msgid="5702522162746042460">"입력한 PUK가 올바르지 않습니다."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"입력한 PIN이 일치하지 않습니다."</string>
- <string name="invalidPin" msgid="3850018445187475377">"4~ 8자리 숫자로 된 PIN을 입력하세요."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM 카드의 PUK가 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
- <string name="needPuk2" msgid="4526033371987193070">"SIM 카드 잠금을 해제하려면 PUK2를 입력하세요."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"수신 발신자 번호"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"발신 발신자 번호"</string>
- <string name="CfMmi" msgid="5123218989141573515">"착신전환"</string>
- <string name="CwMmi" msgid="9129678056795016867">"통화중 대기"</string>
- <string name="BaMmi" msgid="455193067926770581">"착발신 제한"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"비밀번호 변경"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN 변경"</string>
+ <string name="untitled">"<제목없음>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(전화번호 없음)"</string>
+ <string name="unknownName">"(알 수 없음)"</string>
+ <string name="defaultVoiceMailAlphaTag">"음성메일"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"연결에 문제가 있거나 MMI 코드가 잘못되었습니다."</string>
+ <string name="serviceEnabled">"서비스를 사용하도록 설정했습니다."</string>
+ <string name="serviceEnabledFor">"사용 설정된 서비스 목록:"</string>
+ <string name="serviceDisabled">"서비스가 사용 중지되었습니다."</string>
+ <string name="serviceRegistered">"등록이 완료되었습니다."</string>
+ <string name="serviceErased">"삭제했습니다."</string>
+ <string name="passwordIncorrect">"비밀번호가 잘못되었습니다."</string>
+ <string name="mmiComplete">"MMI 완료"</string>
+ <string name="badPin">"이전 PIN이 올바르지 않습니다."</string>
+ <string name="badPuk">"입력한 PUK가 올바르지 않습니다."</string>
+ <string name="mismatchPin">"입력한 PIN이 일치하지 않습니다."</string>
+ <string name="invalidPin">"4~ 8자리 숫자로 된 PIN을 입력하세요."</string>
+ <string name="needPuk">"SIM 카드의 PUK가 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
+ <string name="needPuk2">"SIM 카드 잠금을 해제하려면 PUK2를 입력하세요."</string>
+ <string name="ClipMmi">"수신 발신자 번호"</string>
+ <string name="ClirMmi">"발신 발신자 번호"</string>
+ <string name="CfMmi">"착신전환"</string>
+ <string name="CwMmi">"통화중 대기"</string>
+ <string name="BaMmi">"착발신 제한"</string>
+ <string name="PwdMmi">"비밀번호 변경"</string>
+ <string name="PinMmi">"PIN 변경"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한됨"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한됨"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"서비스가 준비되지 않았습니다."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"발신자 번호 설정을 변경할 수 없습니다."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"제한된 액세스가 변경되었습니다."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"데이터 서비스가 차단되었습니다."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"긴급 서비스가 차단되었습니다."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"음성/SMS 서비스가 차단되었습니다."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"모든 음성/SMS 서비스가 차단되었습니다."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"음성"</string>
- <string name="serviceClassData" msgid="872456782077937893">"데이터"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"팩스"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"비동기"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"동기화"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"패킷"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한됨"</string>
+ <string name="CLIRDefaultOnNextCallOff">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
+ <string name="CLIRDefaultOffNextCallOn">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한됨"</string>
+ <string name="CLIRDefaultOffNextCallOff">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
+ <string name="serviceNotProvisioned">"서비스가 준비되지 않았습니다."</string>
+ <string name="CLIRPermanent">"발신자 번호 설정을 변경할 수 없습니다."</string>
+ <string name="RestrictedChangedTitle">"제한된 액세스가 변경되었습니다."</string>
+ <string name="RestrictedOnData">"데이터 서비스가 차단되었습니다."</string>
+ <string name="RestrictedOnEmergency">"긴급 서비스가 차단되었습니다."</string>
+ <string name="RestrictedOnNormal">"음성/SMS 서비스가 차단되었습니다."</string>
+ <string name="RestrictedOnAll">"모든 음성/SMS 서비스가 차단되었습니다."</string>
+ <string name="serviceClassVoice">"음성"</string>
+ <string name="serviceClassData">"데이터"</string>
+ <string name="serviceClassFAX">"팩스"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"비동기"</string>
+ <string name="serviceClassDataSync">"동기화"</string>
+ <string name="serviceClassPacket">"패킷"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"확인"</string>
- <string name="httpError" msgid="2567300624552921790">"웹페이지에 오류가 있습니다."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL을 찾을 수 없습니다."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"사이트 인증 스키마가 지원되지 않습니다."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"인증에 실패했습니다."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"프록시 서버를 통한 인증에 실패했습니다."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"서버에 연결하지 못했습니다."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"서버와 통신할 수 없습니다. 잠시 후에 다시 시도해 주세요."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"서버 연결 제한시간이 초과되었습니다."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"페이지에 서버 리디렉션이 너무 많이 포함되어 있습니다."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"지원되지 않는 프로토콜입니다."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"보안 연결을 설정하지 못했습니다."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URL이 올바르지 않아 페이지를 열 수 없습니다."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"파일에 액세스할 수 없습니다."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"요청한 파일을 찾을 수 없습니다."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"처리 중인 요청이 너무 많습니다. 잠시 후에 다시 시도해 주세요."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"동기화"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"동기화"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
- <string name="low_memory" msgid="6632412458436461203">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
- <string name="me" msgid="6545696007631404292">"나"</string>
- <string name="power_dialog" msgid="1319919075463988638">"휴대전화 옵션"</string>
- <string name="silent_mode" msgid="7167703389802618663">"무음 모드"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"무선 사용"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"무선 끄기"</string>
- <string name="screen_lock" msgid="799094655496098153">"화면 잠금"</string>
- <string name="power_off" msgid="4266614107412865048">"끄기"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"휴대전화가 종료됩니다."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"최신 응용프로그램이 아닙니다."</string>
- <string name="global_actions" msgid="2406416831541615258">"휴대전화 옵션"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"끄기"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"무음 모드"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"소리 꺼짐"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"소리 켜짐"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행 모드"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행 모드 사용"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행 모드 사용 안함"</string>
- <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"응용프로그램이 요금이 부과될 수 있는 작업을 할 수 있도록 합니다."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS, 이메일 및 기타 메시지를 읽고 씁니다."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"개인정보"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"휴대전화에 저장된 주소록 및 캘린더에 직접 액세스합니다."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"위치"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"실제 위치 모니터링"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"네트워크 통신"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"응용프로그램이 다양한 네트워크 기능에 액세스할 수 있도록 합니다."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google 계정"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"사용 가능한 Google 계정에 액세스합니다."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"하드웨어 제어"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"휴대전화의 하드웨어에 직접 액세스합니다."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"전화 통화"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"전화 통화를 모니터링, 기록 및 처리합니다."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"시스템 도구"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"시스템을 하위 수준에서 액세스하고 제어합니다."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"개발 도구"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"응용프로그램 개발자에게만 필요한 기능입니다."</string>
+ <string name="httpErrorOk">"확인"</string>
+ <string name="httpError">"웹페이지에 오류가 있습니다."</string>
+ <string name="httpErrorLookup">"URL을 찾을 수 없습니다."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"사이트 인증 스키마가 지원되지 않습니다."</string>
+ <string name="httpErrorAuth">"인증에 실패했습니다."</string>
+ <string name="httpErrorProxyAuth">"프록시 서버를 통한 인증에 실패했습니다."</string>
+ <string name="httpErrorConnect">"서버에 연결하지 못했습니다."</string>
+ <string name="httpErrorIO">"서버와 통신할 수 없습니다. 잠시 후에 다시 시도해 주세요."</string>
+ <string name="httpErrorTimeout">"서버 연결 제한시간이 초과되었습니다."</string>
+ <string name="httpErrorRedirectLoop">"페이지에 서버 리디렉션이 너무 많이 포함되어 있습니다."</string>
+ <string name="httpErrorUnsupportedScheme">"지원되지 않는 프로토콜입니다."</string>
+ <string name="httpErrorFailedSslHandshake">"보안 연결을 설정하지 못했습니다."</string>
+ <string name="httpErrorBadUrl">"URL이 올바르지 않아 페이지를 열 수 없습니다."</string>
+ <string name="httpErrorFile">"파일에 액세스할 수 없습니다."</string>
+ <string name="httpErrorFileNotFound">"요청한 파일을 찾을 수 없습니다."</string>
+ <string name="httpErrorTooManyRequests">"처리 중인 요청이 너무 많습니다. 잠시 후에 다시 시도해 주세요."</string>
+ <string name="contentServiceSync">"동기화"</string>
+ <string name="contentServiceSyncNotificationTitle">"동기화"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
+ <string name="low_memory">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
+ <string name="me">"나"</string>
+ <string name="power_dialog">"휴대전화 옵션"</string>
+ <string name="silent_mode">"무음 모드"</string>
+ <string name="turn_on_radio">"무선 사용"</string>
+ <string name="turn_off_radio">"무선 끄기"</string>
+ <string name="screen_lock">"화면 잠금"</string>
+ <string name="power_off">"끄기"</string>
+ <string name="shutdown_progress">"종료 중..."</string>
+ <string name="shutdown_confirm">"휴대전화가 종료됩니다."</string>
+ <string name="no_recent_tasks">"최신 응용프로그램이 아닙니다."</string>
+ <string name="global_actions">"휴대전화 옵션"</string>
+ <string name="global_action_lock">"화면 잠금"</string>
+ <string name="global_action_power_off">"끄기"</string>
+ <string name="global_action_toggle_silent_mode">"무음 모드"</string>
+ <string name="global_action_silent_mode_on_status">"소리 꺼짐"</string>
+ <string name="global_action_silent_mode_off_status">"소리 켜짐"</string>
+ <string name="global_actions_toggle_airplane_mode">"비행 모드"</string>
+ <string name="global_actions_airplane_mode_on_status">"비행 모드 사용"</string>
+ <string name="global_actions_airplane_mode_off_status">"비행 모드 사용 안함"</string>
+ <string name="safeMode">"안전 모드"</string>
+ <string name="android_system_label">"Android 시스템"</string>
+ <string name="permgrouplab_costMoney">"요금이 부과되는 서비스"</string>
+ <string name="permgroupdesc_costMoney">"응용프로그램이 요금이 부과될 수 있는 작업을 할 수 있도록 합니다."</string>
+ <string name="permgrouplab_messages">"메시지"</string>
+ <string name="permgroupdesc_messages">"SMS, 이메일 및 기타 메시지를 읽고 씁니다."</string>
+ <string name="permgrouplab_personalInfo">"개인정보"</string>
+ <string name="permgroupdesc_personalInfo">"휴대전화에 저장된 주소록 및 캘린더에 직접 액세스합니다."</string>
+ <string name="permgrouplab_location">"위치"</string>
+ <string name="permgroupdesc_location">"실제 위치 모니터링"</string>
+ <string name="permgrouplab_network">"네트워크 통신"</string>
+ <string name="permgroupdesc_network">"응용프로그램이 다양한 네트워크 기능에 액세스할 수 있도록 합니다."</string>
+ <string name="permgrouplab_accounts">"Google 계정"</string>
+ <string name="permgroupdesc_accounts">"사용 가능한 Google 계정에 액세스합니다."</string>
+ <string name="permgrouplab_hardwareControls">"하드웨어 제어"</string>
+ <string name="permgroupdesc_hardwareControls">"휴대전화의 하드웨어에 직접 액세스합니다."</string>
+ <string name="permgrouplab_phoneCalls">"전화 통화"</string>
+ <string name="permgroupdesc_phoneCalls">"전화 통화를 모니터링, 기록 및 처리합니다."</string>
+ <string name="permgrouplab_systemTools">"시스템 도구"</string>
+ <string name="permgroupdesc_systemTools">"시스템을 하위 수준에서 액세스하고 제어합니다."</string>
+ <string name="permgrouplab_developmentTools">"개발 도구"</string>
+ <string name="permgroupdesc_developmentTools">"응용프로그램 개발자에게만 필요한 기능입니다."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"상태 표시줄 사용 중지 또는 수정"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"응용프로그램이 상태 표시줄을 사용 중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 합니다."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"상태 표시줄 확장/축소"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"응용프로그램이 상태 표시줄을 확장하거나 축소할 수 있도록 합니다."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"발신전화 가로채기"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"응용프로그램이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS 수신"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"응용프로그램이 SMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS 수신"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"응용프로그램이 MMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS 메시지 보내기"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"응용프로그램이 SMS 메시지를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 확인 없이 메시지를 전송하여 요금을 부과할 수 있습니다."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS 또는 MMS 읽기"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 기밀 메시지를 읽을 수 있습니다."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS 또는 MMS 편집"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지에 쓸 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 메시지를 삭제할 수 있습니다."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP 수신"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"응용프로그램이 WAP 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"실행 중인 응용프로그램 검색"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"응용프로그램이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램에 대한 개인 정보를 검색할 수 있습니다."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"실행 중인 응용프로그램 순서 재지정"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"응용프로그램이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"응용프로그램 디버깅 사용"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"응용프로그램이 다른 응용프로그램에 대해 디버깅을 사용할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램을 중지시킬 수 있습니다."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"응용프로그램이 로케일 또는 전체 글꼴 크기와 같은 현재 구성을 변경할 수 있도록 합니다."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"다른 응용프로그램 다시 시작"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"응용프로그램이 다른 응용프로그램을 강제로 다시 시작할 수 있도록 합니다."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"강제로 응용프로그램 닫기"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"응용프로그램이 포그라운드에 있는 활동을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"시스템 내부 상태 검색"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"응용프로그램이 시스템의 내부 상태를 검색할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인정보와 보안정보를 검색할 수 있습니다."</string>
+ <string name="permlab_statusBar">"상태 표시줄 사용 중지 또는 수정"</string>
+ <string name="permdesc_statusBar">"응용프로그램이 상태 표시줄을 사용 중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 합니다."</string>
+ <string name="permlab_expandStatusBar">"상태 표시줄 확장/축소"</string>
+ <string name="permdesc_expandStatusBar">"응용프로그램이 상태 표시줄을 확장하거나 축소할 수 있도록 합니다."</string>
+ <string name="permlab_processOutgoingCalls">"발신전화 가로채기"</string>
+ <string name="permdesc_processOutgoingCalls">"응용프로그램이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
+ <string name="permlab_receiveSms">"SMS 수신"</string>
+ <string name="permdesc_receiveSms">"응용프로그램이 SMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_receiveMms">"MMS 수신"</string>
+ <string name="permdesc_receiveMms">"응용프로그램이 MMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_sendSms">"SMS 메시지 보내기"</string>
+ <string name="permdesc_sendSms">"응용프로그램이 SMS 메시지를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 확인 없이 메시지를 전송하여 요금을 부과할 수 있습니다."</string>
+ <string name="permlab_readSms">"SMS 또는 MMS 읽기"</string>
+ <string name="permdesc_readSms">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 기밀 메시지를 읽을 수 있습니다."</string>
+ <string name="permlab_writeSms">"SMS 또는 MMS 편집"</string>
+ <string name="permdesc_writeSms">"응용프로그램이 휴대전화 또는 SIM 카드에 저장된 SMS 메시지에 쓸 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 메시지를 삭제할 수 있습니다."</string>
+ <string name="permlab_receiveWapPush">"WAP 수신"</string>
+ <string name="permdesc_receiveWapPush">"응용프로그램이 WAP 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 응용프로그램이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_getTasks">"실행 중인 응용프로그램 검색"</string>
+ <string name="permdesc_getTasks">"응용프로그램이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램에 대한 개인 정보를 검색할 수 있습니다."</string>
+ <string name="permlab_reorderTasks">"실행 중인 응용프로그램 순서 재지정"</string>
+ <string name="permdesc_reorderTasks">"응용프로그램이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
+ <string name="permlab_setDebugApp">"응용프로그램 디버깅 사용"</string>
+ <string name="permdesc_setDebugApp">"응용프로그램이 다른 응용프로그램에 대해 디버깅을 사용할 수 있도록 합니다. 이 경우 악성 응용프로그램이 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+ <string name="permlab_changeConfiguration">"UI 설정 변경"</string>
+ <string name="permdesc_changeConfiguration">"응용프로그램이 로케일 또는 전체 글꼴 크기와 같은 현재 구성을 변경할 수 있도록 합니다."</string>
+ <string name="permlab_restartPackages">"다른 응용프로그램 다시 시작"</string>
+ <string name="permdesc_restartPackages">"응용프로그램이 다른 응용프로그램을 강제로 다시 시작할 수 있도록 합니다."</string>
+ <string name="permlab_forceBack">"강제로 응용프로그램 닫기"</string>
+ <string name="permdesc_forceBack">"응용프로그램이 포그라운드에 있는 활동을 강제로 닫고 되돌아갈 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_dump">"시스템 내부 상태 검색"</string>
+ <string name="permdesc_dump">"응용프로그램이 시스템의 내부 상태를 검색할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인정보와 보안정보를 검색할 수 있습니다."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"실행 중인 모든 응용프로그램 모니터링 및 제어"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"응용프로그램이 시스템에서 활동이 시작되는 방식을 모니터링하고 제어할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 휴대전화 사용 시에는 필요하지 않습니다."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"패키지 제거 브로드캐스트 보내기"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"응용프로그램이 응용프로그램 패키지가 삭제되었다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 실행 중인 다른 응용프로그램을 중지시킬 수 있습니다."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS 수신 브로드캐스트 보내기"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"응용프로그램이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 들어오는 SMS 메시지처럼 위장할 수 있습니다."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"응용프로그램이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 중인 프로세스 수 제한"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"응용프로그램이 실행할 최대 프로세스 수를 제어할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"모든 백그라운드 응용프로그램이 닫히도록 하기"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"응용프로그램이 백그라운드로 이동한 활동을 항상 바로 종료할지 여부를 제어할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"배터리 통계 수정"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"수집된 배터리 통계를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용할 수 없습니다."</string>
+ <string name="permlab_runSetActivityWatcher">"실행 중인 모든 응용프로그램 모니터링 및 제어"</string>
+ <string name="permdesc_runSetActivityWatcher">"응용프로그램이 시스템에서 활동이 시작되는 방식을 모니터링하고 제어할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 휴대전화 사용 시에는 필요하지 않습니다."</string>
+ <string name="permlab_broadcastPackageRemoved">"패키지 제거 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastPackageRemoved">"응용프로그램이 응용프로그램 패키지가 삭제되었다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 실행 중인 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+ <string name="permlab_broadcastSmsReceived">"SMS 수신 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastSmsReceived">"응용프로그램이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 들어오는 SMS 메시지처럼 위장할 수 있습니다."</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastWapPush">"응용프로그램이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 합니다. 이 경우 악성 응용프로그램이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
+ <string name="permlab_setProcessLimit">"실행 중인 프로세스 수 제한"</string>
+ <string name="permdesc_setProcessLimit">"응용프로그램이 실행할 최대 프로세스 수를 제어할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_setAlwaysFinish">"모든 백그라운드 응용프로그램이 닫히도록 하기"</string>
+ <string name="permdesc_setAlwaysFinish">"응용프로그램이 백그라운드로 이동한 활동을 항상 바로 종료할지 여부를 제어할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_batteryStats">"배터리 통계 수정"</string>
+ <string name="permdesc_batteryStats">"수집된 배터리 통계를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용할 수 없습니다."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"인증되지 않은 창 표시"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"시스템 수준 경고 표시"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"응용프로그램이 시스템 경고 창을 표시할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 화면 전체를 차지할 수 있습니다."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"전체 애니메이션 속도 수정"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"응용프로그램이 언제든지 전체 애니메이션 속도를 빠르게 또는 느리게 변경할 수 있도록 합니다."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"응용프로그램 토큰 관리"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"응용프로그램이 일반적인 Z-순서를 무시하여 자체 토큰을 만들고 관리할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"키 및 컨트롤 버튼 누르기"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"응용프로그램이 입력 이벤트(예: 키 누름)를 다른 응용프로그램에 전달할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화를 완전히 제어할 수 있습니다."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"사용자가 입력한 내용 및 수행한 작업 기록"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"응용프로그램이 다른 응용프로그램과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"입력 방법 고정"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"보유자가 입력 방법의 최상위 인터페이스만 사용하도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"응용프로그램이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"응용프로그램에 Linux 신호 보내기"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"응용프로그램이 제공된 신호를 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"응용프로그램이 항상 실행되도록 설정"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"응용프로그램이 연결된 일부 구성 요소를 지속하여 다른 응용프로그램에 사용할 수 없도록 합니다."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"응용프로그램 삭제"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"응용프로그램이 Android 패키지를 삭제할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 응용프로그램을 삭제할 수 있습니다."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"다른 응용프로그램의 데이터 삭제"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"응용프로그램이 사용자 데이터를 지울 수 있도록 합니다."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"다른 응용프로그램의 캐시 삭제"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"응용프로그램이 캐시 파일을 삭제할 수 있도록 합니다."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"응용프로그램 저장공간 계산"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"응용프로그램이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있도록 합니다."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"응용프로그램 직접 설치"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"응용프로그램이 새로운 또는 업데이트된 Android 패키지를 설치할 수 있도록 합니다. 이 경우 악성 응용프로그램이 임의의 강력한 권한으로 새 응용프로그램을 추가할 수 있습니다."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"모든 응용프로그램 캐시 데이터 삭제"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"응용프로그램이 응용프로그램 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"시스템 로그 파일 읽기"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"응용프로그램이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 응용프로그램은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있지만 여기에 개인정보는 포함되어서는 안 됩니다."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/작성"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"응용프로그램이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"응용프로그램 구성 요소 사용 또는 사용 안함"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"응용프로그램이 다른 응용프로그램 구성 요소 사용 여부를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 휴대전화 기능을 사용하지 않도록 설정할 수 있습니다. 이 권한을 설정할 경우 응용프로그램 구성 요소가 사용 불가능하게 되거나 일관성이 맞지 않거나 불안정해질 수 있으므로 주의해야 합니다."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"기본 응용프로그램 설정"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"응용프로그램이 기본 응용프로그램을 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 개인 정보를 수집하기 위해 기존 응용프로그램을 스푸핑하여 실행되는 응용프로그램을 몰래 변경할 수 있습니다."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"전체 시스템 설정 수정"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"응용프로그램이 시스템의 설정 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 시스템 구성을 손상시킬 수 있습니다."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"보안 시스템 설정 수정"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"응용프로그램이 시스템 보안 설정값 데이터를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google 서비스 지도 수정"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"응용프로그램이 Google 서비스 지도를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"부팅할 때 자동 시작"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"응용프로그램이 시스템 부팅이 끝난 후 바로 시작할 수 있도록 합니다. 이 경우 휴대전화가 시작하는 데 시간이 오래 걸리고 응용프로그램이 항상 실행되어 전체 휴대전화 속도가 느려질 수 있습니다."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"남은 브로드캐스트 보내기"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"응용프로그램이 브로드캐스트가 끝난 후에 남은 브로드캐스트를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화가 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"연락처 데이터 읽기"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"응용프로그램이 휴대전화에 저장된 모든 연락처(주소) 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 데이터를 다른 사람에게 보낼 수 있습니다."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"연락처 데이터 작성"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"응용프로그램이 휴대전화에 저장된 연락처(주소) 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 연락처 데이터를 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"소유자 데이터 작성"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"응용프로그램이 휴대전화에 저장된 소유자 데이터를 수정할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 소유자 데이터를 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"소유자 데이터 읽기"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"응용프로그램이 휴대전화에 저장된 휴대전화 소유자 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 소유자 데이터를 읽을 수 있습니다."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"캘린더 데이터 읽기"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"응용프로그램이 휴대전화에 저장된 모든 캘린더 일정을 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 캘린더 일정을 다른 사람에게 보낼 수 있습니다."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"캘린더 데이터 작성"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"응용프로그램이 휴대전화에 저장된 캘린더 일정을 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 캘린더 데이터를 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"테스트를 위해 위치 소스로 가장"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"테스트용 가짜 위치 소스를 만듭니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS, 네트워크 제공업체 같은 실제 위치 소스에서 반환한 위치 및/또는 상태를 덮어쓸 수 있습니다."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"추가 위치 제공업체 명령 액세스"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"추가 위치 제공업체 명령에 액세스합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
+ <string name="permlab_internalSystemWindow">"인증되지 않은 창 표시"</string>
+ <string name="permdesc_internalSystemWindow">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_systemAlertWindow">"시스템 수준 경고 표시"</string>
+ <string name="permdesc_systemAlertWindow">"응용프로그램이 시스템 경고 창을 표시할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 화면 전체를 차지할 수 있습니다."</string>
+ <string name="permlab_setAnimationScale">"전체 애니메이션 속도 수정"</string>
+ <string name="permdesc_setAnimationScale">"응용프로그램이 언제든지 전체 애니메이션 속도를 빠르게 또는 느리게 변경할 수 있도록 합니다."</string>
+ <string name="permlab_manageAppTokens">"응용프로그램 토큰 관리"</string>
+ <string name="permdesc_manageAppTokens">"응용프로그램이 일반적인 Z-순서를 무시하여 자체 토큰을 만들고 관리할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_injectEvents">"키 및 컨트롤 버튼 누르기"</string>
+ <string name="permdesc_injectEvents">"응용프로그램이 입력 이벤트(예: 키 누름)를 다른 응용프로그램에 전달할 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화를 완전히 제어할 수 있습니다."</string>
+ <string name="permlab_readInputState">"사용자가 입력한 내용 및 수행한 작업 기록"</string>
+ <string name="permdesc_readInputState">"응용프로그램이 다른 응용프로그램과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_bindInputMethod">"입력 방법 고정"</string>
+ <string name="permdesc_bindInputMethod">"보유자가 입력 방법의 최상위 인터페이스만 사용하도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_setOrientation">"화면 방향 변경"</string>
+ <string name="permdesc_setOrientation">"응용프로그램이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_signalPersistentProcesses">"응용프로그램에 Linux 신호 보내기"</string>
+ <string name="permdesc_signalPersistentProcesses">"응용프로그램이 제공된 신호를 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string>
+ <string name="permlab_persistentActivity">"응용프로그램이 항상 실행되도록 설정"</string>
+ <string name="permdesc_persistentActivity">"응용프로그램이 연결된 일부 구성 요소를 지속하여 다른 응용프로그램에 사용할 수 없도록 합니다."</string>
+ <string name="permlab_deletePackages">"응용프로그램 삭제"</string>
+ <string name="permdesc_deletePackages">"응용프로그램이 Android 패키지를 삭제할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 응용프로그램을 삭제할 수 있습니다."</string>
+ <string name="permlab_clearAppUserData">"다른 응용프로그램의 데이터 삭제"</string>
+ <string name="permdesc_clearAppUserData">"응용프로그램이 사용자 데이터를 지울 수 있도록 합니다."</string>
+ <string name="permlab_deleteCacheFiles">"다른 응용프로그램의 캐시 삭제"</string>
+ <string name="permdesc_deleteCacheFiles">"응용프로그램이 캐시 파일을 삭제할 수 있도록 합니다."</string>
+ <string name="permlab_getPackageSize">"응용프로그램 저장공간 계산"</string>
+ <string name="permdesc_getPackageSize">"응용프로그램이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있도록 합니다."</string>
+ <string name="permlab_installPackages">"응용프로그램 직접 설치"</string>
+ <string name="permdesc_installPackages">"응용프로그램이 새로운 또는 업데이트된 Android 패키지를 설치할 수 있도록 합니다. 이 경우 악성 응용프로그램이 임의의 강력한 권한으로 새 응용프로그램을 추가할 수 있습니다."</string>
+ <string name="permlab_clearAppCache">"모든 응용프로그램 캐시 데이터 삭제"</string>
+ <string name="permdesc_clearAppCache">"응용프로그램이 응용프로그램 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
+ <string name="permlab_readLogs">"시스템 로그 파일 읽기"</string>
+ <string name="permdesc_readLogs">"응용프로그램이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 응용프로그램은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있지만 여기에 개인정보는 포함되어서는 안 됩니다."</string>
+ <string name="permlab_diagnostic">"진단 그룹 소유의 리소스 읽기/작성"</string>
+ <string name="permdesc_diagnostic">"응용프로그램이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
+ <string name="permlab_changeComponentState">"응용프로그램 구성 요소 사용 또는 사용 안함"</string>
+ <string name="permdesc_changeComponentState">"응용프로그램이 다른 응용프로그램 구성 요소 사용 여부를 변경할 수 있도록 합니다. 이 경우 악성 응용프로그램이 중요한 휴대전화 기능을 사용하지 않도록 설정할 수 있습니다. 이 권한을 설정할 경우 응용프로그램 구성 요소가 사용 불가능하게 되거나 일관성이 맞지 않거나 불안정해질 수 있으므로 주의해야 합니다."</string>
+ <string name="permlab_setPreferredApplications">"기본 응용프로그램 설정"</string>
+ <string name="permdesc_setPreferredApplications">"응용프로그램이 기본 응용프로그램을 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 사용자의 개인 정보를 수집하기 위해 기존 응용프로그램을 스푸핑하여 실행되는 응용프로그램을 몰래 변경할 수 있습니다."</string>
+ <string name="permlab_writeSettings">"전체 시스템 설정 수정"</string>
+ <string name="permdesc_writeSettings">"응용프로그램이 시스템의 설정 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 시스템 구성을 손상시킬 수 있습니다."</string>
+ <string name="permlab_writeSecureSettings">"보안 시스템 설정 수정"</string>
+ <string name="permdesc_writeSecureSettings">"응용프로그램이 시스템 보안 설정값 데이터를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_writeGservices">"Google 서비스 지도 수정"</string>
+ <string name="permdesc_writeGservices">"응용프로그램이 Google 서비스 지도를 수정할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_receiveBootCompleted">"부팅할 때 자동 시작"</string>
+ <string name="permdesc_receiveBootCompleted">"응용프로그램이 시스템 부팅이 끝난 후 바로 시작할 수 있도록 합니다. 이 경우 휴대전화가 시작하는 데 시간이 오래 걸리고 응용프로그램이 항상 실행되어 전체 휴대전화 속도가 느려질 수 있습니다."</string>
+ <string name="permlab_broadcastSticky">"남은 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastSticky">"응용프로그램이 브로드캐스트가 끝난 후에 남은 브로드캐스트를 보낼 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화가 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
+ <string name="permlab_readContacts">"연락처 데이터 읽기"</string>
+ <string name="permdesc_readContacts">"응용프로그램이 휴대전화에 저장된 모든 연락처(주소) 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 데이터를 다른 사람에게 보낼 수 있습니다."</string>
+ <string name="permlab_writeContacts">"연락처 데이터 작성"</string>
+ <string name="permdesc_writeContacts">"응용프로그램이 휴대전화에 저장된 연락처(주소) 데이터를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 연락처 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_writeOwnerData">"소유자 데이터 작성"</string>
+ <string name="permdesc_writeOwnerData">"응용프로그램이 휴대전화에 저장된 소유자 데이터를 수정할 수 있도록 합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 소유자 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_readOwnerData">"소유자 데이터 읽기"</string>
+ <string name="permdesc_readOwnerData">"응용프로그램이 휴대전화에 저장된 휴대전화 소유자 데이터를 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 휴대전화 소유자 데이터를 읽을 수 있습니다."</string>
+ <string name="permlab_readCalendar">"캘린더 데이터 읽기"</string>
+ <string name="permdesc_readCalendar">"응용프로그램이 휴대전화에 저장된 모든 캘린더 일정을 읽을 수 있도록 합니다. 이 경우 악성 응용프로그램이 캘린더 일정을 다른 사람에게 보낼 수 있습니다."</string>
+ <string name="permlab_writeCalendar">"캘린더 데이터 작성"</string>
+ <string name="permdesc_writeCalendar">"응용프로그램이 휴대전화에 저장된 캘린더 일정을 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 캘린더 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_accessMockLocation">"테스트를 위해 위치 소스로 가장"</string>
+ <string name="permdesc_accessMockLocation">"테스트용 가짜 위치 소스를 만듭니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS, 네트워크 제공업체 같은 실제 위치 소스에서 반환한 위치 및/또는 상태를 덮어쓸 수 있습니다."</string>
+ <string name="permlab_accessLocationExtraCommands">"추가 위치 제공업체 명령 액세스"</string>
+ <string name="permdesc_accessLocationExtraCommands">"추가 위치 제공업체 명령에 액세스합니다. 단, 악성 응용프로그램이 이 기능을 이용하여 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"자세한 (GPS) 위치"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"가능한 경우 휴대전화에서 GPS(범지구 위치 측정 시스템) 등의 자세한 위치 소스에 액세스합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 확인하고 추가 배터리 전원을 소비할 수 있습니다."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"광범위한 네트워크 기반 위치"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"휴대전화의 대략적인 위치를 측정하기 위해 셀룰러 네트워크 데이터베이스와 같은 광범위한 위치 소스에 액세스합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 대략적으로 측정할 수 있습니다."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger 액세스"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"응용프로그램이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 합니다."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"프레임 버퍼 읽기"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"응용프로그램이 프레임 버퍼의 콘텐츠를 읽을 수 있도록 합니다."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"오디오 설정 변경"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"응용프로그램이 볼륨 및 경로 지정 같은 전체 오디오 설정을 수정할 수 있도록 합니다."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"오디오 녹음"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"응용프로그램이 오디오 레코드 경로에 액세스할 수 있도록 합니다."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"사진 촬영"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"응용프로그램이 카메라로 사진을 찍을 수 있도록 합니다. 이 경우 응용프로그램이 카메라에 표시되는 이미지를 언제든지 수집할 수 있습니다."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"휴대전화를 영구적으로 사용 중지"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"응용프로그램이 휴대전화를 영구적으로 사용 중지할 수 있게 합니다. 이 기능은 매우 위험합니다."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"휴대전화 강제로 다시 부팅"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"응용프로그램이 휴대전화를 강제로 다시 부팅할 수 있도록 합니다."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"파일시스템 마운트 및 마운트 해제"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"응용프로그램이 이동식 저장소의 파일 시스템을 마운트하고 마운트 해제할 수 있도록 합니다."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"외부 저장소 포맷"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"응용프로그램이 제거 가능한 저장소를 포맷하도록 합니다."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"진동 제어"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"응용프로그램이 진동을 제어할 수 있도록 합니다."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"손전등 제어"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"응용프로그램이 손전등을 제어할 수 있도록 합니다."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"하드웨어 테스트"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"응용프로그램이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있도록 합니다."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호로 직접 전화걸기"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"응용프로그램이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램으로 인해 예상치 못한 통화 요금이 부과될 수 있습니다. 이 권한으로 응용프로그램이 비상 전화를 걸게 할 수는 없습니다."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"전화번호로 직접 전화걸기"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"응용프로그램이 사용자의 조작 없이 비상 번호를 포함한 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램이 응급 서비스를 불필요하거나 불법적으로 호출할 수 있습니다."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"위치 업데이트 알림 제어"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"무선의 위치 업데이트 알림을 사용하거나 사용 중지할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"체크인 속성 액세스"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 액세스를 허용합니다. 일반 응용프로그램에서는 사용할 수 없습니다."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"위젯 선택"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"응용프로그램이 응용프로그램에서 사용할 수 있는 위젯을 시스템에 알릴 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 개인 정보에 대한 액세스 권한을 다른 응용프로그램에 부여할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"휴대전화 상태 수정"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"응용프로그램이 장치의 휴대전화 기능을 제어할 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나 휴대전화 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"응용프로그램이 휴대전화가 절전 모드로 전환되지 않도록 합니다."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"휴대전화 전원 켜고 끄기"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"응용프로그램이 휴대전화를 켜거나 끌 수 있도록 합니다."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"출고 테스트 모드로 실행"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"휴대전화 하드웨어에 대한 완전한 액세스를 허용하는 하위 수준의 제조업체 테스트로 실행됩니다. 휴대전화가 제조업체 테스트 모드로 실행 중일 때만 사용할 수 있습니다."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"배경화면 설정"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"응용프로그램이 시스템 배경화면을 설정할 수 있도록 합니다."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"배경화면 크기 힌트 설정"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"응용프로그램이 시스템 배경화면 크기 힌트를 설정할 수 있도록 합니다."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"시스템을 기본값으로 재설정"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"응용프로그램이 모든 데이터, 구성 및 설치된 응용프로그램을 지워서 시스템을 완전히 초기화할 수 있도록 합니다."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"표준시간대 설정"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"응용프로그램이 휴대전화의 표준시간대를 변경할 수 있도록 합니다."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"알려진 계정 검색"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"응용프로그램이 휴대전화에 알려진 계정 목록을 가져올 수 있도록 합니다."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"네트워크 상태 보기"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"응용프로그램이 모든 네트워크의 상태를 볼 수 있도록 합니다."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"인터넷에 완전히 액세스"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"응용프로그램이 네트워크 소켓을 만들 수 있도록 합니다."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"액세스포인트 이름 설정 쓰기"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"응용프로그램이 APN의 프록시 및 포트 같은 APN 설정을 수정할 수 있도록 합니다."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"네트워크 연결 변경"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"응용프로그램이 네트워크 연결 상태를 변경할 수 있도록 합니다."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"백그라운드 데이터 사용 설정 변경"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"응용프로그램이 백그라운드 데이터 사용 설정을 변경할 수 있도록 합니다."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi 상태 보기"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"응용프로그램이 Wi-Fi의 상태에 대한 정보를 볼 수 있도록 합니다."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi 상태 변경"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"응용프로그램이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있도록 합니다."</string>
+ <string name="permlab_accessFineLocation">"자세한 (GPS) 위치"</string>
+ <string name="permdesc_accessFineLocation">"가능한 경우 휴대전화에서 GPS(범지구 위치 측정 시스템) 등의 자세한 위치 소스에 액세스합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 확인하고 추가 배터리 전원을 소비할 수 있습니다."</string>
+ <string name="permlab_accessCoarseLocation">"광범위한 네트워크 기반 위치"</string>
+ <string name="permdesc_accessCoarseLocation">"휴대전화의 대략적인 위치를 측정하기 위해 셀룰러 네트워크 데이터베이스와 같은 광범위한 위치 소스에 액세스합니다. 이 경우 악성 응용프로그램이 사용자의 위치를 대략적으로 측정할 수 있습니다."</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlinger 액세스"</string>
+ <string name="permdesc_accessSurfaceFlinger">"응용프로그램이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있도록 합니다."</string>
+ <string name="permlab_readFrameBuffer">"프레임 버퍼 읽기"</string>
+ <string name="permdesc_readFrameBuffer">"응용프로그램이 프레임 버퍼의 콘텐츠를 읽을 수 있도록 합니다."</string>
+ <string name="permlab_modifyAudioSettings">"오디오 설정 변경"</string>
+ <string name="permdesc_modifyAudioSettings">"응용프로그램이 볼륨 및 경로 지정 같은 전체 오디오 설정을 수정할 수 있도록 합니다."</string>
+ <string name="permlab_recordAudio">"오디오 녹음"</string>
+ <string name="permdesc_recordAudio">"응용프로그램이 오디오 레코드 경로에 액세스할 수 있도록 합니다."</string>
+ <string name="permlab_camera">"사진 촬영"</string>
+ <string name="permdesc_camera">"응용프로그램이 카메라로 사진을 찍을 수 있도록 합니다. 이 경우 응용프로그램이 카메라에 표시되는 이미지를 언제든지 수집할 수 있습니다."</string>
+ <string name="permlab_brick">"휴대전화를 영구적으로 사용 중지"</string>
+ <string name="permdesc_brick">"응용프로그램이 휴대전화를 영구적으로 사용 중지할 수 있게 합니다. 이 기능은 매우 위험합니다."</string>
+ <string name="permlab_reboot">"휴대전화 강제로 다시 부팅"</string>
+ <string name="permdesc_reboot">"응용프로그램이 휴대전화를 강제로 다시 부팅할 수 있도록 합니다."</string>
+ <string name="permlab_mount_unmount_filesystems">"파일시스템 마운트 및 마운트 해제"</string>
+ <string name="permdesc_mount_unmount_filesystems">"응용프로그램이 이동식 저장소의 파일 시스템을 마운트하고 마운트 해제할 수 있도록 합니다."</string>
+ <string name="permlab_mount_format_filesystems">"외부 저장소 포맷"</string>
+ <string name="permdesc_mount_format_filesystems">"응용프로그램이 제거 가능한 저장소를 포맷하도록 합니다."</string>
+ <string name="permlab_vibrate">"진동 제어"</string>
+ <string name="permdesc_vibrate">"응용프로그램이 진동을 제어할 수 있도록 합니다."</string>
+ <string name="permlab_flashlight">"손전등 제어"</string>
+ <string name="permdesc_flashlight">"응용프로그램이 손전등을 제어할 수 있도록 합니다."</string>
+ <string name="permlab_hardware_test">"하드웨어 테스트"</string>
+ <string name="permdesc_hardware_test">"응용프로그램이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있도록 합니다."</string>
+ <string name="permlab_callPhone">"전화번호로 직접 전화걸기"</string>
+ <string name="permdesc_callPhone">"응용프로그램이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램으로 인해 예상치 못한 통화 요금이 부과될 수 있습니다. 이 권한으로 응용프로그램이 비상 전화를 걸게 할 수는 없습니다."</string>
+ <string name="permlab_callPrivileged">"전화번호로 직접 전화걸기"</string>
+ <string name="permdesc_callPrivileged">"응용프로그램이 사용자의 조작 없이 비상 번호를 포함한 전화번호로 전화를 걸 수 있도록 합니다. 이 경우 악성 응용프로그램이 응급 서비스를 불필요하거나 불법적으로 호출할 수 있습니다."</string>
+ <string name="permlab_locationUpdates">"위치 업데이트 알림 제어"</string>
+ <string name="permdesc_locationUpdates">"무선의 위치 업데이트 알림을 사용하거나 사용 중지할 수 있도록 합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_checkinProperties">"체크인 속성 액세스"</string>
+ <string name="permdesc_checkinProperties">"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 액세스를 허용합니다. 일반 응용프로그램에서는 사용할 수 없습니다."</string>
+ <string name="permlab_bindGadget">"위젯 선택"</string>
+ <string name="permdesc_bindGadget">"응용프로그램이 응용프로그램에서 사용할 수 있는 위젯을 시스템에 알릴 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 개인 정보에 대한 액세스 권한을 다른 응용프로그램에 부여할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_modifyPhoneState">"휴대전화 상태 수정"</string>
+ <string name="permdesc_modifyPhoneState">"응용프로그램이 장치의 휴대전화 기능을 제어할 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나 휴대전화 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
+ <string name="permlab_readPhoneState">"휴대전화 상태 읽기"</string>
+ <string name="permdesc_readPhoneState">"응용프로그램이 장치의 휴대전화 기능에 액세스할 수 있도록 합니다. 이 권한을 갖는 응용프로그램은 휴대전화의 전화번호, 통화가 활성인지 여부, 해당 통화가 연결된 번호 등을 확인할 수 있습니다."</string>
+ <string name="permlab_wakeLock">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
+ <string name="permdesc_wakeLock">"응용프로그램이 휴대전화가 절전 모드로 전환되지 않도록 합니다."</string>
+ <string name="permlab_devicePower">"휴대전화 전원 켜고 끄기"</string>
+ <string name="permdesc_devicePower">"응용프로그램이 휴대전화를 켜거나 끌 수 있도록 합니다."</string>
+ <string name="permlab_factoryTest">"출고 테스트 모드로 실행"</string>
+ <string name="permdesc_factoryTest">"휴대전화 하드웨어에 대한 완전한 액세스를 허용하는 하위 수준의 제조업체 테스트로 실행됩니다. 휴대전화가 제조업체 테스트 모드로 실행 중일 때만 사용할 수 있습니다."</string>
+ <string name="permlab_setWallpaper">"배경화면 설정"</string>
+ <string name="permdesc_setWallpaper">"응용프로그램이 시스템 배경화면을 설정할 수 있도록 합니다."</string>
+ <string name="permlab_setWallpaperHints">"배경화면 크기 힌트 설정"</string>
+ <string name="permdesc_setWallpaperHints">"응용프로그램이 시스템 배경화면 크기 힌트를 설정할 수 있도록 합니다."</string>
+ <string name="permlab_masterClear">"시스템을 기본값으로 재설정"</string>
+ <string name="permdesc_masterClear">"응용프로그램이 모든 데이터, 구성 및 설치된 응용프로그램을 지워서 시스템을 완전히 초기화할 수 있도록 합니다."</string>
+ <string name="permlab_setTimeZone">"표준시간대 설정"</string>
+ <string name="permdesc_setTimeZone">"응용프로그램이 휴대전화의 표준시간대를 변경할 수 있도록 합니다."</string>
+ <string name="permlab_getAccounts">"알려진 계정 검색"</string>
+ <string name="permdesc_getAccounts">"응용프로그램이 휴대전화에 알려진 계정 목록을 가져올 수 있도록 합니다."</string>
+ <string name="permlab_accessNetworkState">"네트워크 상태 보기"</string>
+ <string name="permdesc_accessNetworkState">"응용프로그램이 모든 네트워크의 상태를 볼 수 있도록 합니다."</string>
+ <string name="permlab_createNetworkSockets">"인터넷에 완전히 액세스"</string>
+ <string name="permdesc_createNetworkSockets">"응용프로그램이 네트워크 소켓을 만들 수 있도록 합니다."</string>
+ <string name="permlab_writeApnSettings">"액세스포인트 이름 설정 쓰기"</string>
+ <string name="permdesc_writeApnSettings">"응용프로그램이 APN의 프록시 및 포트 같은 APN 설정을 수정할 수 있도록 합니다."</string>
+ <string name="permlab_changeNetworkState">"네트워크 연결 변경"</string>
+ <string name="permdesc_changeNetworkState">"응용프로그램이 네트워크 연결 상태를 변경할 수 있도록 합니다."</string>
+ <string name="permlab_changeBackgroundDataSetting">"백그라운드 데이터 사용 설정 변경"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"응용프로그램이 백그라운드 데이터 사용 설정을 변경할 수 있도록 합니다."</string>
+ <string name="permlab_accessWifiState">"Wi-Fi 상태 보기"</string>
+ <string name="permdesc_accessWifiState">"응용프로그램이 Wi-Fi의 상태에 대한 정보를 볼 수 있도록 합니다."</string>
+ <string name="permlab_changeWifiState">"Wi-Fi 상태 변경"</string>
+ <string name="permdesc_changeWifiState">"응용프로그램이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있도록 합니다."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth 관리"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"응용프로그램이 로컬 Bluetooth 휴대전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있도록 합니다."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth 연결 만들기"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"응용프로그램이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하며 연결을 수락할 수 있도록 합니다."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"키 잠금 사용 중지"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"응용프로그램이 키 잠금 및 관련 비밀번호 보안을 사용 중지할 수 있도록 합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용 중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"응용프로그램이 주소록에 동기화를 사용할지 여부와 같은 동기화 설정을 읽을 수 있도록 합니다."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"동기화 설정 쓰기"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"응용프로그램이 주소록에 대해 동기화를 사용할지 여부 등의 동기화 설정을 수정할 수 있도록 합니다."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"동기화 통계 읽기"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"응용프로그램이 동기화 통계(예: 실행된 동기화 기록)을 읽을 수 있도록 합니다."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"가입된 피드 읽기"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"응용프로그램이 현재 동기화된 피드에 대한 세부정보를 가져올 수 있도록 합니다."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"가입 피드 작성"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"응용프로그램이 현재 동기화된 피드를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 동기화된 피드를 변경할 수 있습니다."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"사용자 정의 사전 읽기"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"응용프로그램이 사용자 사전에 보관되어 있는 비공개 단어, 이름 및 구문을 읽도록 합니다."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"상용자 정의 사전에 작성"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"응용프로그램이 사용자 사전에 새 단어를 입력할 수 있도록 합니다."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth 관리"</string>
+ <string name="permdesc_bluetoothAdmin">"응용프로그램이 로컬 Bluetooth 휴대전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있도록 합니다."</string>
+ <string name="permlab_bluetooth">"Bluetooth 연결 만들기"</string>
+ <string name="permdesc_bluetooth">"응용프로그램이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하며 연결을 수락할 수 있도록 합니다."</string>
+ <string name="permlab_disableKeyguard">"키 잠금 사용 중지"</string>
+ <string name="permdesc_disableKeyguard">"응용프로그램이 키 잠금 및 관련 비밀번호 보안을 사용 중지할 수 있도록 합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용 중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
+ <string name="permlab_readSyncSettings">"동기화 설정 읽기"</string>
+ <string name="permdesc_readSyncSettings">"응용프로그램이 주소록에 동기화를 사용할지 여부와 같은 동기화 설정을 읽을 수 있도록 합니다."</string>
+ <string name="permlab_writeSyncSettings">"동기화 설정 쓰기"</string>
+ <string name="permdesc_writeSyncSettings">"응용프로그램이 주소록에 대해 동기화를 사용할지 여부 등의 동기화 설정을 수정할 수 있도록 합니다."</string>
+ <string name="permlab_readSyncStats">"동기화 통계 읽기"</string>
+ <string name="permdesc_readSyncStats">"응용프로그램이 동기화 통계(예: 실행된 동기화 기록)을 읽을 수 있도록 합니다."</string>
+ <string name="permlab_subscribedFeedsRead">"가입된 피드 읽기"</string>
+ <string name="permdesc_subscribedFeedsRead">"응용프로그램이 현재 동기화된 피드에 대한 세부정보를 가져올 수 있도록 합니다."</string>
+ <string name="permlab_subscribedFeedsWrite">"가입 피드 작성"</string>
+ <string name="permdesc_subscribedFeedsWrite">"응용프로그램이 현재 동기화된 피드를 수정할 수 있도록 합니다. 이 경우 악성 응용프로그램이 동기화된 피드를 변경할 수 있습니다."</string>
+ <string name="permlab_readDictionary">"사용자 정의 사전 읽기"</string>
+ <string name="permdesc_readDictionary">"응용프로그램이 사용자 사전에 보관되어 있는 비공개 단어, 이름 및 구문을 읽도록 합니다."</string>
+ <string name="permlab_writeDictionary">"상용자 정의 사전에 작성"</string>
+ <string name="permdesc_writeDictionary">"응용프로그램이 사용자 사전에 새 단어를 입력할 수 있도록 합니다."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"집"</item>
- <item msgid="869923650527136615">"모바일"</item>
- <item msgid="7897544654242874543">"회사"</item>
- <item msgid="1103601433382158155">"회사 팩스"</item>
- <item msgid="1735177144948329370">"집(팩스)"</item>
- <item msgid="603878674477207394">"호출기"</item>
- <item msgid="1650824275177931637">"기타"</item>
- <item msgid="9192514806975898961">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"모바일"</item>
+ <item>"회사"</item>
+ <item>"회사 팩스"</item>
+ <item>"집(팩스)"</item>
+ <item>"호출기"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"집"</item>
- <item msgid="7084237356602625604">"회사"</item>
- <item msgid="1112044410659011023">"기타"</item>
- <item msgid="2374913952870110618">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"모바일"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"집"</item>
- <item msgid="5629153956045109251">"회사"</item>
- <item msgid="4966604264500343469">"기타"</item>
- <item msgid="4932682847595299369">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"집"</item>
- <item msgid="1359644565647383708">"회사"</item>
- <item msgid="7868549401053615677">"기타"</item>
- <item msgid="3145118944639869809">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"회사"</item>
- <item msgid="4378074129049520373">"기타"</item>
- <item msgid="3455047468583965104">"맞춤설정"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google 토크"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google 토크"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN 코드 입력"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN 코드가 잘못되었습니다."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"잠금해제하려면 메뉴를 누른 다음 0을 누릅니다."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"비상 전화번호"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(서비스 안됨)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"화면 잠김"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"잠금해제하려면 메뉴를 누르세요."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"잠금해제를 위해 패턴 그리기"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"비상 전화"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"맞습니다."</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"죄송합니다. 다시 시도하세요."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN 코드 입력"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 코드가 잘못되었습니다."</string>
+ <string name="keyguard_label_text">"잠금해제하려면 메뉴를 누른 다음 0을 누릅니다."</string>
+ <string name="emergency_call_dialog_number_for_display">"비상 전화번호"</string>
+ <string name="lockscreen_carrier_default">"(서비스 안됨)"</string>
+ <string name="lockscreen_screen_locked">"화면 잠김"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_pattern_instructions">"잠금해제를 위해 패턴 그리기"</string>
+ <string name="lockscreen_emergency_call">"비상 전화"</string>
+ <string name="lockscreen_pattern_correct">"맞습니다."</string>
+ <string name="lockscreen_pattern_wrong">"죄송합니다. 다시 시도하세요."</string>
+ <string name="lockscreen_plugged_in">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"충전기를 연결하세요."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIM 카드가 없습니다."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"휴대전화에 SIM 카드가 없습니다."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"SIM 카드를 삽입하세요."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"네트워크 잠김"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 카드의 PUK가 잠겨 있습니다."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"사용자 가이드를 참조하거나 고객지원팀에 문의하세요."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 카드가 잠겨 있습니다."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM 카드 잠금해제 중..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 Google 로그인을 통해 휴대전화를 잠금해제하도록 요청됩니다. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도하세요."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"패턴을 잊으셨나요?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"패턴을 너무 많이 시도했습니다."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"사용자 이름(이메일)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"비밀번호"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"로그인"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"충전기를 연결하세요."</string>
+ <string name="lockscreen_missing_sim_message_short">"SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_message">"휴대전화에 SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_instructions">"SIM 카드를 삽입하세요."</string>
+ <string name="lockscreen_network_locked_message">"네트워크 잠김"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM 카드의 PUK가 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"사용자 가이드를 참조하거나 고객지원팀에 문의하세요."</string>
+ <string name="lockscreen_sim_locked_message">"SIM 카드가 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM 카드 잠금해제 중..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 Google 로그인을 통해 휴대전화를 잠금해제하도록 요청됩니다. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"패턴을 잊으셨나요?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"패턴을 너무 많이 시도했습니다."</string>
+ <string name="lockscreen_glogin_instructions">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
+ <string name="lockscreen_glogin_username_hint">"사용자 이름(이메일)"</string>
+ <string name="lockscreen_glogin_password_hint">"비밀번호"</string>
+ <string name="lockscreen_glogin_submit_button">"로그인"</string>
+ <string name="lockscreen_glogin_invalid_input">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"충전 중..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"배터리 전원이 부족합니다."</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"<xliff:g id="NUMBER">%d%%</xliff:g> 미만 남음"</string>
+ <string name="status_bar_no_notifications_title">"알림 없음"</string>
+ <string name="status_bar_ongoing_events_title">"진행 중"</string>
+ <string name="status_bar_latest_events_title">"알림"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"충전 중..."</string>
+ <string name="battery_low_title">"충전기를 연결하세요."</string>
+ <string name="battery_low_subtitle">"배터리 전원이 부족합니다."</string>
+ <string name="battery_low_percent_format">"<xliff:g id="NUMBER">%d%%</xliff:g> 미만 남음"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"출고 테스트 불합격"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST 작업은 /system/app 디렉토리에 설치된 패키지에 대해서만 지원됩니다."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST 작업을 제공하는 패키지가 없습니다."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"다시 부팅"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"자바스크립트"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 선택하고 현재 페이지에 그대로 있으려면 \'취소\'를 선택하세요."</string>
- <string name="save_password_label" msgid="6860261758665825069">"확인"</string>
+ <string name="factorytest_failed">"출고 테스트 불합격"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST 작업은 /system/app 디렉토리에 설치된 패키지에 대해서만 지원됩니다."</string>
+ <string name="factorytest_no_action">"FACTORY_TEST 작업을 제공하는 패키지가 없습니다."</string>
+ <string name="factorytest_reboot">"다시 부팅"</string>
+ <string name="js_dialog_title">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
+ <string name="js_dialog_title_default">"자바스크립트"</string>
+ <string name="js_dialog_before_unload">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 선택하고 현재 페이지에 그대로 있으려면 \'취소\'를 선택하세요."</string>
+ <string name="save_password_label">"확인"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
- <string name="save_password_never" msgid="8274330296785855105">"안함"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"페이지를 열 수 있는 권한이 없습니다."</string>
- <string name="text_copied" msgid="4985729524670131385">"텍스트가 클립보드에 복사되었습니다."</string>
- <string name="more_item_label" msgid="4650918923083320495">"더보기"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"스페이스바"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"입력"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"삭제"</string>
- <string name="search_go" msgid="8298016669822141719">"검색"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
+ <string name="save_password_message">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
+ <string name="save_password_notnow">"나중에"</string>
+ <string name="save_password_remember">"저장"</string>
+ <string name="save_password_never">"안함"</string>
+ <string name="open_permission_deny">"페이지를 열 수 있는 권한이 없습니다."</string>
+ <string name="text_copied">"텍스트가 클립보드에 복사되었습니다."</string>
+ <string name="more_item_label">"더보기"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"스페이스바"</string>
+ <string name="menu_enter_shortcut_label">"입력"</string>
+ <string name="menu_delete_shortcut_label">"삭제"</string>
+ <string name="search_go">"검색"</string>
+ <string name="oneMonthDurationPast">"한 달 전"</string>
+ <string name="beforeOneMonthDurationPast">"한 달 전"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1초 전"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
+ <item quantity="one">"1초 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1분 전"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1시간 전"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"어제"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1초 내"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
+ <item quantity="one">"1초 내"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1분 후"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ <item quantity="one">"1분 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1시간 후"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ <item quantity="one">"1시간 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"내일"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
+ <item quantity="one">"내일"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1초 전"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
+ <item quantity="one">"1초 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1분 전"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1시간 전"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"어제"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1초 후"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
+ <item quantity="one">"1초 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1분 후"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ <item quantity="one">"1분 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1시간 후"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ <item quantity="one">"1시간 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"내일"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
+ <item quantity="one">"내일"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s년"</string>
- <string name="day" msgid="8144195776058119424">"일"</string>
- <string name="days" msgid="4774547661021344602">"일"</string>
- <string name="hour" msgid="2126771916426189481">"시간"</string>
- <string name="hours" msgid="894424005266852993">"시간"</string>
- <string name="minute" msgid="9148878657703769868">"분"</string>
- <string name="minutes" msgid="5646001005827034509">"분"</string>
- <string name="second" msgid="3184235808021478">"초"</string>
- <string name="seconds" msgid="3161515347216589235">"초"</string>
- <string name="week" msgid="5617961537173061583">"주"</string>
- <string name="weeks" msgid="6509623834583944518">"주"</string>
- <string name="year" msgid="4001118221013892076">"년"</string>
- <string name="years" msgid="6881577717993213522">"년"</string>
- <string name="every_weekday" msgid="8777593878457748503">"주중 매일(월-금)"</string>
- <string name="daily" msgid="5738949095624133403">"매일"</string>
- <string name="weekly" msgid="983428358394268344">"매주 <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"매월"</string>
- <string name="yearly" msgid="1519577999407493836">"매년"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"동영상 재생 안됨"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"죄송합니다. 이 기기로의 스트리밍에 적합하지 않은 동영상입니다."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"죄송합니다. 동영상을 재생할 수 없습니다."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"확인"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"정오"</string>
- <string name="Noon" msgid="3342127745230013127">"정오"</string>
- <string name="midnight" msgid="7166259508850457595">"자정"</string>
- <string name="Midnight" msgid="5630806906897892201">"자정"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"모두 선택"</string>
- <string name="selectText" msgid="3889149123626888637">"텍스트 선택"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"텍스트 선택 중지"</string>
- <string name="cut" msgid="3092569408438626261">"잘라내기"</string>
- <string name="cutAll" msgid="2436383270024931639">"모두 잘라내기"</string>
- <string name="copy" msgid="2681946229533511987">"복사"</string>
- <string name="copyAll" msgid="2590829068100113057">"모두 복사"</string>
- <string name="paste" msgid="5629880836805036433">"붙여넣기"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL 복사"</string>
- <string name="inputMethod" msgid="7673923508389094672">"입력 방법"</string>
- <string name="addToDictionary" msgid="726256909274177272">"사전에 \'%s\' 추가"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"텍스트 수정"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"저장공간 부족"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"휴대전화 저장공간이 부족합니다."</string>
- <string name="ok" msgid="5970060430562524910">"확인"</string>
- <string name="cancel" msgid="6442560571259935130">"취소"</string>
- <string name="yes" msgid="5362982303337969312">"확인"</string>
- <string name="no" msgid="5141531044935541497">"취소"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"주의"</string>
- <string name="capital_on" msgid="1544682755514494298">"사용"</string>
- <string name="capital_off" msgid="6815870386972805832">"사용 안함"</string>
- <string name="whichApplication" msgid="4533185947064773386">"작업을 수행할 때 사용하는 응용프로그램"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"이 작업에 대해 기본값으로 사용"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 > 응용프로그램 > 응용프로그램 관리에서 기본값을 지웁니다."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"작업 선택"</string>
- <string name="noApplications" msgid="1691104391758345586">"작업을 수행할 수 있는 응용프로그램이 없습니다."</string>
- <string name="aerr_title" msgid="653922989522758100">"죄송합니다."</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
- <string name="anr_title" msgid="3100070910664756057">"죄송합니다."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활동(<xliff:g id="ACTIVITY">%1$s</xliff:g> 응용프로그램)이 응답하지 않습니다."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."</string>
- <string name="force_close" msgid="3653416315450806396">"닫기"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s년"</string>
+ <string name="day">"일"</string>
+ <string name="days">"일"</string>
+ <string name="hour">"시간"</string>
+ <string name="hours">"시간"</string>
+ <string name="minute">"분"</string>
+ <string name="minutes">"분"</string>
+ <string name="second">"초"</string>
+ <string name="seconds">"초"</string>
+ <string name="week">"주"</string>
+ <string name="weeks">"주"</string>
+ <string name="year">"년"</string>
+ <string name="years">"년"</string>
+ <string name="every_weekday">"주중 매일(월-금)"</string>
+ <string name="daily">"매일"</string>
+ <string name="weekly">"매주 <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"매월"</string>
+ <string name="yearly">"매년"</string>
+ <string name="VideoView_error_title">"동영상 재생 안됨"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"죄송합니다. 이 기기로의 스트리밍에 적합하지 않은 동영상입니다."</string>
+ <string name="VideoView_error_text_unknown">"죄송합니다. 동영상을 재생할 수 없습니다."</string>
+ <string name="VideoView_error_button">"확인"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"정오"</string>
+ <string name="Noon">"정오"</string>
+ <string name="midnight">"자정"</string>
+ <string name="Midnight">"자정"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"모두 선택"</string>
+ <string name="selectText">"텍스트 선택"</string>
+ <string name="stopSelectingText">"텍스트 선택 중지"</string>
+ <string name="cut">"잘라내기"</string>
+ <string name="cutAll">"모두 잘라내기"</string>
+ <string name="copy">"복사"</string>
+ <string name="copyAll">"모두 복사"</string>
+ <string name="paste">"붙여넣기"</string>
+ <string name="copyUrl">"URL 복사"</string>
+ <string name="inputMethod">"입력 방법"</string>
+ <string name="addToDictionary">"사전에 \'%s\' 추가"</string>
+ <string name="editTextMenuTitle">"텍스트 수정"</string>
+ <string name="low_internal_storage_view_title">"저장공간 부족"</string>
+ <string name="low_internal_storage_view_text">"휴대전화 저장공간이 부족합니다."</string>
+ <string name="ok">"확인"</string>
+ <string name="cancel">"취소"</string>
+ <string name="yes">"확인"</string>
+ <string name="no">"취소"</string>
+ <string name="dialog_alert_title">"주의"</string>
+ <string name="capital_on">"사용"</string>
+ <string name="capital_off">"사용 안함"</string>
+ <string name="whichApplication">"작업을 수행할 때 사용하는 응용프로그램"</string>
+ <string name="alwaysUse">"이 작업에 대해 기본값으로 사용"</string>
+ <string name="clearDefaultHintMsg">"홈 설정 > 응용프로그램 > 응용프로그램 관리에서 기본값을 지웁니다."</string>
+ <string name="chooseActivity">"작업 선택"</string>
+ <string name="noApplications">"작업을 수행할 수 있는 응용프로그램이 없습니다."</string>
+ <string name="aerr_title">"죄송합니다."</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
+ <string name="anr_title">"죄송합니다."</string>
+ <string name="anr_activity_application">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활동(<xliff:g id="ACTIVITY">%1$s</xliff:g> 응용프로그램)이 응답하지 않습니다."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."</string>
+ <string name="force_close">"닫기"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"대기"</string>
- <string name="debug" msgid="9103374629678531849">"디버그"</string>
- <string name="sendText" msgid="5132506121645618310">"텍스트에 대한 작업 선택"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"벨소리 볼륨"</string>
- <string name="volume_music" msgid="5421651157138628171">"미디어 볼륨"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth를 통해 재생"</string>
- <string name="volume_call" msgid="3941680041282788711">"통화 볼륨"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth 통화 볼륨"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"알람 볼륨"</string>
- <string name="volume_notification" msgid="2422265656744276715">"알림 볼륨"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"볼륨"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"기본 벨소리"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"무음"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"벨소리"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"알 수 없는 벨소리"</string>
+ <string name="wait">"대기"</string>
+ <string name="debug">"디버그"</string>
+ <string name="sendText">"텍스트에 대한 작업 선택"</string>
+ <string name="volume_ringtone">"벨소리 볼륨"</string>
+ <string name="volume_music">"미디어 볼륨"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth를 통해 재생"</string>
+ <string name="volume_call">"통화 볼륨"</string>
+ <string name="volume_bluetooth_call">"Bluetooth 통화 볼륨"</string>
+ <string name="volume_alarm">"알람 볼륨"</string>
+ <string name="volume_notification">"알림 볼륨"</string>
+ <string name="volume_unknown">"볼륨"</string>
+ <string name="ringtone_default">"기본 벨소리"</string>
+ <string name="ringtone_default_with_actual">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"무음"</string>
+ <string name="ringtone_picker_title">"벨소리"</string>
+ <string name="ringtone_unknown">"알 수 없는 벨소리"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi 네트워크 사용 가능"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi 네트워크 사용 가능"</item>
+ <item quantity="one">"Wi-Fi 네트워크 사용 가능"</item>
+ <item quantity="other">"Wi-Fi 네트워크 사용 가능"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"개방형 Wi-Fi 네트워크 사용 가능"</item>
- <item quantity="other" msgid="7915895323644292768">"개방형 Wi-Fi 네트워크 사용 가능"</item>
+ <item quantity="one">"개방형 Wi-Fi 네트워크 사용 가능"</item>
+ <item quantity="other">"개방형 Wi-Fi 네트워크 사용 가능"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"알 수 없는 응용프로그램"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"여러 개의 SMS 메시지를 보내는 중입니다. 계속하려면 \'확인\'을 선택하고 전송을 중지하려면 \'취소\'를 선택하세요."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"확인"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"취소"</string>
- <string name="date_time_set" msgid="5777075614321087758">"설정"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"기본값"</string>
- <string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"숨기기"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"모두 표시"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"로드 중..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB 연결됨"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"USB를 통해 휴대전화를 컴퓨터에 연결했습니다. 컴퓨터와 휴대전화 SD 카드 간에 파일을 복사하려면 \'마운트\'를 선택하세요."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"마운트"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"마운트 안함"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"USB 저장소로 SD 카드를 사용하는 동안 문제가 발생했습니다."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 연결됨"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"컴퓨터에 파일을 복사하거나 컴퓨터의 파일을 복사하려면 선택합니다."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB 저장소 끄기"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB 저장소 끄기를 선택하세요."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB 저장소 끄기"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USB 저장소를 끄기 전에 반드시 USB 호스트에서 마운트 해제하세요. USB 저장소를 끄려면 \'끄기\'를 선택하세요."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"USB 저장소 끄기"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"취소"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USB 저장소를 끄는 동안 Weve에 문제가 발행했습니다. USB 호스트를 마운트 해제했는지 확인한 후 다시 시도하세요."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD 카드 포맷"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SD 카드를 포맷하시겠습니까? 포맷하면 카드의 모든 데이터를 잃게 됩니다."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"포맷"</string>
+ <string name="select_character">"문자 삽입"</string>
+ <string name="sms_control_default_app_name">"알 수 없는 응용프로그램"</string>
+ <string name="sms_control_title">"SMS 메시지를 보내는 중"</string>
+ <string name="sms_control_message">"여러 개의 SMS 메시지를 보내는 중입니다. 계속하려면 \'확인\'을 선택하고 전송을 중지하려면 \'취소\'를 선택하세요."</string>
+ <string name="sms_control_yes">"확인"</string>
+ <string name="sms_control_no">"취소"</string>
+ <string name="date_time_set">"설정"</string>
+ <string name="default_permission_group">"기본값"</string>
+ <string name="no_permissions">"권한 필요 없음"</string>
+ <string name="perms_hide"><b>"숨기기"</b></string>
+ <string name="perms_show_all"><b>"모두 표시"</b></string>
+ <string name="googlewebcontenthelper_loading">"로드 중..."</string>
+ <string name="usb_storage_title">"USB 연결됨"</string>
+ <string name="usb_storage_message">"USB를 통해 휴대전화를 컴퓨터에 연결했습니다. 컴퓨터와 휴대전화 SD 카드 간에 파일을 복사하려면 \'마운트\'를 선택하세요."</string>
+ <string name="usb_storage_button_mount">"마운트"</string>
+ <string name="usb_storage_button_unmount">"마운트 안함"</string>
+ <string name="usb_storage_error_message">"USB 저장소로 SD 카드를 사용하는 동안 문제가 발생했습니다."</string>
+ <string name="usb_storage_notification_title">"USB 연결됨"</string>
+ <string name="usb_storage_notification_message">"컴퓨터에 파일을 복사하거나 컴퓨터의 파일을 복사하려면 선택합니다."</string>
+ <string name="usb_storage_stop_notification_title">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_notification_message">"USB 저장소 끄기를 선택하세요."</string>
+ <string name="usb_storage_stop_title">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_message">"USB 저장소를 끄기 전에 반드시 USB 호스트에서 마운트 해제하세요. USB 저장소를 끄려면 \'끄기\'를 선택하세요."</string>
+ <string name="usb_storage_stop_button_mount">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_button_unmount">"취소"</string>
+ <string name="usb_storage_stop_error_message">"USB 저장소를 끄는 동안 Weve에 문제가 발행했습니다. USB 호스트를 마운트 해제했는지 확인한 후 다시 시도하세요."</string>
+ <string name="extmedia_format_title">"SD 카드 포맷"</string>
+ <string name="extmedia_format_message">"SD 카드를 포맷하시겠습니까? 포맷하면 카드의 모든 데이터를 잃게 됩니다."</string>
+ <string name="extmedia_format_button_format">"포맷"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"입력 방법 선택"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD 카드 준비 중"</string>
+ <string name="select_input_method">"입력 방법 선택"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"가능한 원인"</u></string>
+ <string name="ext_media_checking_notification_title">"SD 카드 준비 중"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"빈 SD 카드"</string>
+ <string name="ext_media_nofs_notification_title">"빈 SD 카드"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"손상된 SD 카드"</string>
+ <string name="ext_media_unmountable_notification_title">"손상된 SD 카드"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD 카드가 예상치 않게 제거되었습니다."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"데이터 손실을 피하려면 SD 카드를 제거하기 전에 마운트 해제합니다."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD 카드를 안전하게 제거할 수 있습니다."</string>
+ <string name="ext_media_badremoval_notification_title">"SD 카드가 예상치 않게 제거되었습니다."</string>
+ <string name="ext_media_badremoval_notification_message">"데이터 손실을 피하려면 SD 카드를 제거하기 전에 마운트 해제합니다."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD 카드를 안전하게 제거할 수 있습니다."</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD 카드를 제거했습니다."</string>
+ <string name="ext_media_nomedia_notification_title">"SD 카드를 제거했습니다."</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"일치하는 활동이 없습니다."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"구성 요소 사용 통계 업데이트"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"수집된 구성요소 사용 통계를 수정할 수 있는 권한을 부여합니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"확대/축소하려면 두 번 탭하세요."</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"위젯을 확장하는 동안 오류가 발생했습니다."</string>
- <string name="ime_action_go" msgid="8320845651737369027">"이동"</string>
- <string name="ime_action_search" msgid="658110271822807811">"검색"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"전송"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"다음"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"완료"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"실행"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"전화하기 "\n"<xliff:g id="NUMBER">%s</xliff:g>에 연결"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"전화번호부에"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
+ <string name="activity_list_empty">"일치하는 활동이 없습니다."</string>
+ <string name="permlab_pkgUsageStats">"구성 요소 사용 통계 업데이트"</string>
+ <string name="permdesc_pkgUsageStats">"수집된 구성요소 사용 통계를 수정할 수 있는 권한을 부여합니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"확대/축소하려면 두 번 탭하세요."</string>
+ <string name="gadget_host_error_inflating">"위젯을 확장하는 동안 오류가 발생했습니다."</string>
+ <string name="ime_action_go">"이동"</string>
+ <string name="ime_action_search">"검색"</string>
+ <string name="ime_action_send">"전송"</string>
+ <string name="ime_action_next">"다음"</string>
+ <string name="ime_action_done">"완료"</string>
+ <string name="ime_action_default">"실행"</string>
+ <string name="dial_number_using">"전화하기 "\n"<xliff:g id="NUMBER">%s</xliff:g>에 연결"</string>
+ <string name="create_contact_using">"전화번호부에"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-mcc204-cs/strings.xml b/core/res/res/values-mcc204-cs/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-cs/strings.xml
+++ b/core/res/res/values-mcc204-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-da/strings.xml b/core/res/res/values-mcc204-da/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-da/strings.xml
+++ b/core/res/res/values-mcc204-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-de/strings.xml b/core/res/res/values-mcc204-de/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-de/strings.xml
+++ b/core/res/res/values-mcc204-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-el/strings.xml b/core/res/res/values-mcc204-el/strings.xml
index f7ca3d2..97bfe65 100644
--- a/core/res/res/values-mcc204-el/strings.xml
+++ b/core/res/res/values-mcc204-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc204-es-rUS/strings.xml b/core/res/res/values-mcc204-es-rUS/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-es-rUS/strings.xml
+++ b/core/res/res/values-mcc204-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-es/strings.xml b/core/res/res/values-mcc204-es/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-es/strings.xml
+++ b/core/res/res/values-mcc204-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-fr/strings.xml b/core/res/res/values-mcc204-fr/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-fr/strings.xml
+++ b/core/res/res/values-mcc204-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-it/strings.xml b/core/res/res/values-mcc204-it/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-it/strings.xml
+++ b/core/res/res/values-mcc204-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ja/strings.xml b/core/res/res/values-mcc204-ja/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ja/strings.xml
+++ b/core/res/res/values-mcc204-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ko/strings.xml b/core/res/res/values-mcc204-ko/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ko/strings.xml
+++ b/core/res/res/values-mcc204-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-nl/strings.xml b/core/res/res/values-mcc204-nl/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-nl/strings.xml
+++ b/core/res/res/values-mcc204-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pl/strings.xml b/core/res/res/values-mcc204-pl/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pl/strings.xml
+++ b/core/res/res/values-mcc204-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pt-rPT/strings.xml b/core/res/res/values-mcc204-pt-rPT/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc204-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pt/strings.xml b/core/res/res/values-mcc204-pt/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pt/strings.xml
+++ b/core/res/res/values-mcc204-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ru/strings.xml b/core/res/res/values-mcc204-ru/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ru/strings.xml
+++ b/core/res/res/values-mcc204-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-sv/strings.xml b/core/res/res/values-mcc204-sv/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-sv/strings.xml
+++ b/core/res/res/values-mcc204-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-tr/strings.xml b/core/res/res/values-mcc204-tr/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-tr/strings.xml
+++ b/core/res/res/values-mcc204-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-zh-rCN/strings.xml b/core/res/res/values-mcc204-zh-rCN/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc204-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-zh-rTW/strings.xml b/core/res/res/values-mcc204-zh-rTW/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc204-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc230-cs/strings.xml b/core/res/res/values-mcc230-cs/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-cs/strings.xml
+++ b/core/res/res/values-mcc230-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-da/strings.xml b/core/res/res/values-mcc230-da/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-da/strings.xml
+++ b/core/res/res/values-mcc230-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-de/strings.xml b/core/res/res/values-mcc230-de/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-de/strings.xml
+++ b/core/res/res/values-mcc230-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-el/strings.xml b/core/res/res/values-mcc230-el/strings.xml
index 49ea9f3..97bfe65 100644
--- a/core/res/res/values-mcc230-el/strings.xml
+++ b/core/res/res/values-mcc230-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc230-es-rUS/strings.xml b/core/res/res/values-mcc230-es-rUS/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-es-rUS/strings.xml
+++ b/core/res/res/values-mcc230-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-es/strings.xml b/core/res/res/values-mcc230-es/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-es/strings.xml
+++ b/core/res/res/values-mcc230-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-fr/strings.xml b/core/res/res/values-mcc230-fr/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-fr/strings.xml
+++ b/core/res/res/values-mcc230-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-it/strings.xml b/core/res/res/values-mcc230-it/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-it/strings.xml
+++ b/core/res/res/values-mcc230-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ja/strings.xml b/core/res/res/values-mcc230-ja/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ja/strings.xml
+++ b/core/res/res/values-mcc230-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ko/strings.xml b/core/res/res/values-mcc230-ko/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ko/strings.xml
+++ b/core/res/res/values-mcc230-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-nl/strings.xml b/core/res/res/values-mcc230-nl/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-nl/strings.xml
+++ b/core/res/res/values-mcc230-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pl/strings.xml b/core/res/res/values-mcc230-pl/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pl/strings.xml
+++ b/core/res/res/values-mcc230-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pt-rPT/strings.xml b/core/res/res/values-mcc230-pt-rPT/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc230-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pt/strings.xml b/core/res/res/values-mcc230-pt/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pt/strings.xml
+++ b/core/res/res/values-mcc230-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ru/strings.xml b/core/res/res/values-mcc230-ru/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ru/strings.xml
+++ b/core/res/res/values-mcc230-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-sv/strings.xml b/core/res/res/values-mcc230-sv/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-sv/strings.xml
+++ b/core/res/res/values-mcc230-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-tr/strings.xml b/core/res/res/values-mcc230-tr/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-tr/strings.xml
+++ b/core/res/res/values-mcc230-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-zh-rCN/strings.xml b/core/res/res/values-mcc230-zh-rCN/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc230-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-zh-rTW/strings.xml b/core/res/res/values-mcc230-zh-rTW/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc230-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc232-cs/strings.xml b/core/res/res/values-mcc232-cs/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-cs/strings.xml
+++ b/core/res/res/values-mcc232-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-da/strings.xml b/core/res/res/values-mcc232-da/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-da/strings.xml
+++ b/core/res/res/values-mcc232-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-de/strings.xml b/core/res/res/values-mcc232-de/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-de/strings.xml
+++ b/core/res/res/values-mcc232-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-el/strings.xml b/core/res/res/values-mcc232-el/strings.xml
index 3698d2c..97bfe65 100644
--- a/core/res/res/values-mcc232-el/strings.xml
+++ b/core/res/res/values-mcc232-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc232-es-rUS/strings.xml b/core/res/res/values-mcc232-es-rUS/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-es-rUS/strings.xml
+++ b/core/res/res/values-mcc232-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-es/strings.xml b/core/res/res/values-mcc232-es/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-es/strings.xml
+++ b/core/res/res/values-mcc232-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-fr/strings.xml b/core/res/res/values-mcc232-fr/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-fr/strings.xml
+++ b/core/res/res/values-mcc232-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-it/strings.xml b/core/res/res/values-mcc232-it/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-it/strings.xml
+++ b/core/res/res/values-mcc232-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ja/strings.xml b/core/res/res/values-mcc232-ja/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ja/strings.xml
+++ b/core/res/res/values-mcc232-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ko/strings.xml b/core/res/res/values-mcc232-ko/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ko/strings.xml
+++ b/core/res/res/values-mcc232-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-nl/strings.xml b/core/res/res/values-mcc232-nl/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-nl/strings.xml
+++ b/core/res/res/values-mcc232-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pl/strings.xml b/core/res/res/values-mcc232-pl/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pl/strings.xml
+++ b/core/res/res/values-mcc232-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pt-rPT/strings.xml b/core/res/res/values-mcc232-pt-rPT/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc232-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pt/strings.xml b/core/res/res/values-mcc232-pt/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pt/strings.xml
+++ b/core/res/res/values-mcc232-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ru/strings.xml b/core/res/res/values-mcc232-ru/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ru/strings.xml
+++ b/core/res/res/values-mcc232-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-sv/strings.xml b/core/res/res/values-mcc232-sv/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-sv/strings.xml
+++ b/core/res/res/values-mcc232-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-tr/strings.xml b/core/res/res/values-mcc232-tr/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-tr/strings.xml
+++ b/core/res/res/values-mcc232-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-zh-rCN/strings.xml b/core/res/res/values-mcc232-zh-rCN/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc232-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-zh-rTW/strings.xml b/core/res/res/values-mcc232-zh-rTW/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc232-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc234-cs/strings.xml b/core/res/res/values-mcc234-cs/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-cs/strings.xml
+++ b/core/res/res/values-mcc234-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-da/strings.xml b/core/res/res/values-mcc234-da/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-da/strings.xml
+++ b/core/res/res/values-mcc234-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-de/strings.xml b/core/res/res/values-mcc234-de/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-de/strings.xml
+++ b/core/res/res/values-mcc234-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-el/strings.xml b/core/res/res/values-mcc234-el/strings.xml
index e04aa93..97bfe65 100644
--- a/core/res/res/values-mcc234-el/strings.xml
+++ b/core/res/res/values-mcc234-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc234-es-rUS/strings.xml b/core/res/res/values-mcc234-es-rUS/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-es-rUS/strings.xml
+++ b/core/res/res/values-mcc234-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-es/strings.xml b/core/res/res/values-mcc234-es/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-es/strings.xml
+++ b/core/res/res/values-mcc234-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-fr/strings.xml b/core/res/res/values-mcc234-fr/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-fr/strings.xml
+++ b/core/res/res/values-mcc234-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-it/strings.xml b/core/res/res/values-mcc234-it/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-it/strings.xml
+++ b/core/res/res/values-mcc234-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ja/strings.xml b/core/res/res/values-mcc234-ja/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ja/strings.xml
+++ b/core/res/res/values-mcc234-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ko/strings.xml b/core/res/res/values-mcc234-ko/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ko/strings.xml
+++ b/core/res/res/values-mcc234-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-nl/strings.xml b/core/res/res/values-mcc234-nl/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-nl/strings.xml
+++ b/core/res/res/values-mcc234-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pl/strings.xml b/core/res/res/values-mcc234-pl/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pl/strings.xml
+++ b/core/res/res/values-mcc234-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pt-rPT/strings.xml b/core/res/res/values-mcc234-pt-rPT/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc234-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pt/strings.xml b/core/res/res/values-mcc234-pt/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pt/strings.xml
+++ b/core/res/res/values-mcc234-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ru/strings.xml b/core/res/res/values-mcc234-ru/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ru/strings.xml
+++ b/core/res/res/values-mcc234-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-sv/strings.xml b/core/res/res/values-mcc234-sv/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-sv/strings.xml
+++ b/core/res/res/values-mcc234-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-tr/strings.xml b/core/res/res/values-mcc234-tr/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-tr/strings.xml
+++ b/core/res/res/values-mcc234-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-zh-rCN/strings.xml b/core/res/res/values-mcc234-zh-rCN/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc234-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-zh-rTW/strings.xml b/core/res/res/values-mcc234-zh-rTW/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc234-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc260-cs/strings.xml b/core/res/res/values-mcc260-cs/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-cs/strings.xml
+++ b/core/res/res/values-mcc260-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-da/strings.xml b/core/res/res/values-mcc260-da/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-da/strings.xml
+++ b/core/res/res/values-mcc260-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-de/strings.xml b/core/res/res/values-mcc260-de/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-de/strings.xml
+++ b/core/res/res/values-mcc260-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-el/strings.xml b/core/res/res/values-mcc260-el/strings.xml
index ea6f87b..97bfe65 100644
--- a/core/res/res/values-mcc260-el/strings.xml
+++ b/core/res/res/values-mcc260-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc260-es-rUS/strings.xml b/core/res/res/values-mcc260-es-rUS/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-es-rUS/strings.xml
+++ b/core/res/res/values-mcc260-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-es/strings.xml b/core/res/res/values-mcc260-es/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-es/strings.xml
+++ b/core/res/res/values-mcc260-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-fr/strings.xml b/core/res/res/values-mcc260-fr/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-fr/strings.xml
+++ b/core/res/res/values-mcc260-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-it/strings.xml b/core/res/res/values-mcc260-it/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-it/strings.xml
+++ b/core/res/res/values-mcc260-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ja/strings.xml b/core/res/res/values-mcc260-ja/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ja/strings.xml
+++ b/core/res/res/values-mcc260-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ko/strings.xml b/core/res/res/values-mcc260-ko/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ko/strings.xml
+++ b/core/res/res/values-mcc260-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-nl/strings.xml b/core/res/res/values-mcc260-nl/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-nl/strings.xml
+++ b/core/res/res/values-mcc260-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pl/strings.xml b/core/res/res/values-mcc260-pl/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pl/strings.xml
+++ b/core/res/res/values-mcc260-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pt-rPT/strings.xml b/core/res/res/values-mcc260-pt-rPT/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc260-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pt/strings.xml b/core/res/res/values-mcc260-pt/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pt/strings.xml
+++ b/core/res/res/values-mcc260-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ru/strings.xml b/core/res/res/values-mcc260-ru/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ru/strings.xml
+++ b/core/res/res/values-mcc260-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-sv/strings.xml b/core/res/res/values-mcc260-sv/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-sv/strings.xml
+++ b/core/res/res/values-mcc260-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-tr/strings.xml b/core/res/res/values-mcc260-tr/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-tr/strings.xml
+++ b/core/res/res/values-mcc260-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-zh-rCN/strings.xml b/core/res/res/values-mcc260-zh-rCN/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc260-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-zh-rTW/strings.xml b/core/res/res/values-mcc260-zh-rTW/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc260-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc262-cs/strings.xml b/core/res/res/values-mcc262-cs/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-cs/strings.xml
+++ b/core/res/res/values-mcc262-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-da/strings.xml b/core/res/res/values-mcc262-da/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-da/strings.xml
+++ b/core/res/res/values-mcc262-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-de/strings.xml b/core/res/res/values-mcc262-de/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-de/strings.xml
+++ b/core/res/res/values-mcc262-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-el/strings.xml b/core/res/res/values-mcc262-el/strings.xml
index 38827c5..97bfe65 100644
--- a/core/res/res/values-mcc262-el/strings.xml
+++ b/core/res/res/values-mcc262-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc262-es-rUS/strings.xml b/core/res/res/values-mcc262-es-rUS/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-es-rUS/strings.xml
+++ b/core/res/res/values-mcc262-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-es/strings.xml b/core/res/res/values-mcc262-es/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-es/strings.xml
+++ b/core/res/res/values-mcc262-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-fr/strings.xml b/core/res/res/values-mcc262-fr/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-fr/strings.xml
+++ b/core/res/res/values-mcc262-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-it/strings.xml b/core/res/res/values-mcc262-it/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-it/strings.xml
+++ b/core/res/res/values-mcc262-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ja/strings.xml b/core/res/res/values-mcc262-ja/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ja/strings.xml
+++ b/core/res/res/values-mcc262-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ko/strings.xml b/core/res/res/values-mcc262-ko/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ko/strings.xml
+++ b/core/res/res/values-mcc262-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-nl/strings.xml b/core/res/res/values-mcc262-nl/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-nl/strings.xml
+++ b/core/res/res/values-mcc262-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pl/strings.xml b/core/res/res/values-mcc262-pl/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pl/strings.xml
+++ b/core/res/res/values-mcc262-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pt-rPT/strings.xml b/core/res/res/values-mcc262-pt-rPT/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc262-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pt/strings.xml b/core/res/res/values-mcc262-pt/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pt/strings.xml
+++ b/core/res/res/values-mcc262-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ru/strings.xml b/core/res/res/values-mcc262-ru/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ru/strings.xml
+++ b/core/res/res/values-mcc262-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-sv/strings.xml b/core/res/res/values-mcc262-sv/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-sv/strings.xml
+++ b/core/res/res/values-mcc262-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-tr/strings.xml b/core/res/res/values-mcc262-tr/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-tr/strings.xml
+++ b/core/res/res/values-mcc262-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-zh-rCN/strings.xml b/core/res/res/values-mcc262-zh-rCN/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc262-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-zh-rTW/strings.xml b/core/res/res/values-mcc262-zh-rTW/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc262-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c19d057..dff943c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -15,697 +15,752 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<uten navn>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Mangler telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Ukjent)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Telefonsvarer"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjenesten ble aktivert."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjenesten ble aktivert for:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjenesten ble deaktivert."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen er vellykket."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Registreringen ble fjernet."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Ugyldig passord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI utført."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamle PIN-koden du skrev inn er feil."</string>
- <string name="badPuk" msgid="5702522162746042460">"PUK-koden du skrev inn er feil."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"PIN-kodene stemmer ikke overens."</string>
- <string name="invalidPin" msgid="3850018445187475377">"PIN-koden må være mellom fire og åtte siffer."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Inngående nummervisning"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Utgående nummervisning"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Viderekobling"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Samtale venter"</string>
- <string name="BaMmi" msgid="455193067926770581">"Samtaleblokkering"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Passordendring"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-kode-bytte"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Nummervisning tilgjengelig"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Nummervisning begrenset"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Telefonkonferanse"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Avvisning av uønskede samtaler"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Levering av nummervisning"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Ikke forstyrr"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummervisning er begrenset som standard. Neste anrop: Begrenset"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummervisning er begrenset som standard. Neste anrop: Ikke begrenset"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummervisning er ikke begrenset som standard. Neste anrop: Begrenset"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Kunne ikke endre innstilling for nummervisning."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Tilgangsbegrensning endret"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokkert."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokkert."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Tale-/SMS-tjenester er blokkert."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle tale-/SMS-tjenester er blokkert."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Tale"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"Fax"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkron"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkron"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakkedata"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roaming-indikator av"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roaming-indikator på"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roaming-indikator blinker"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Ute av nabolaget"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Ute av bygningen"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - foretrukket system"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - tilgjengelig system"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - alliansepartner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - gullpartner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - full tjenestefunksjoanlitet"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - delvis tjenestefunksjonalitet"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roaming-banner på"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roaming-banner av"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Leter etter tjeneste"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Funksjonskode utført."</string>
- <string name="fcError" msgid="3327560126588500777">"Tilkoblingsproblem eller ugyldig funksjonskode."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Nettsiden inneholder en feil."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Kunne ikke finne adressen."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Støtter ikke sidens autentiseringsmetode."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Autentiseringen feilet."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autentisering via mellomtjeneren feilet."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Kunne ikke koble til tjeneren."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Klarte ikke å kommunisere med tjeneren. Prøv igjen senere."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Det oppsto et tidsavbrudd under tilkobling til tjeneren."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Siden inneholder for mange videresendinger."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollen er ikke støttet."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Kunne ikke opprette en sikker tilkobling."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Kunne ikke åpne siden, siden adressen er ugyldig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Kunne ikke åpne filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Fant ikke den forespurte filen."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"For mange forespørsler blir behandlet. Prøv igjen senere."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkronisering"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisering"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagringsminne er fullt! Slett noen filer for å frigjøre plass."</string>
- <string name="me" msgid="6545696007631404292">"Meg"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefoninnstillinger"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Stillemodus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Slå på trådløst nett"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Slå av trådløst nett"</string>
- <string name="screen_lock" msgid="799094655496098153">"Lås skjermen"</string>
- <string name="power_off" msgid="4266614107412865048">"Slå av"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Avslutter…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefonen vil bli slått av."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Ingen nylig brukte applikasjoner."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefoninnstillinger"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stillemodus"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er av"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er på"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
- <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Lar applikasjoner utføre operasjoner som kan koste deg penger."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lese og skrive SMS, e-post og andre meldinger på telefonen."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Personlig informasjon"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkte tilgang til kontakter og kalendre lagret på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Plassering"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Overvåking av telefonens fysiske plassering"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Nettverkstilgang"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Gir applikasjoner tilgang til diverse nettverksfunksjoner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google-kontoer"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Tilgang til tilgjengelige Google-kontoer."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Maskinvarekontroll"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkte tilgang til maskinvaren på telefonen."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonsamtaler"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Overvåk, ta opp, og behandle telefonsamtaler."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemverktøy"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Lavnivå tilgang og kontroll over systemet."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utviklingsverktøy"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funksjonalitet kun utviklere trenger."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Tilgang til minnekortet."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Lar applikasjonen deaktivere statusfeltet, samt legge til og fjerne systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"utvide/slå sammen statusfeltet"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Lar applikasjonen utvide eller slå sammen statusfeltet."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"avskjære utgående anrop"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Lar applikasjonen behandle utgående anrop og endre nummeret som ringes. Ondsinnede applikasjoner kan overvåke, videresende, eller hindre utgående anrop."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"motta SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Lar applikasjonen motta og behandle SMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"motta MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Lar applikasjonen motta og behandle MMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"sende SMS-meldinger"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Lar applikasjonen sende SMS-meldinger. Ondsinnede applikasjoner kan koste deg penger ved å sende meldinger uten bekreftelse."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"lese SMS- og MMS-meldinger"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Lar applikasjonen lese SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan lese private meldinger."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"redigere SMS- og MMS-meldinger"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Lar applikasjonen skrive til SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan slette meldinger."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"motta WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Lar applikasjonen motta og behandle WAP-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"se kjørende applikasjoner"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"omordne kjørende applikasjoner"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver applikasjonsdebugging"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillater applikasjonen å endre gjeldende innstillinger, slik som språk eller skriftstørrelse."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"omstarte andre applikasjoner"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Lar applikasjonen tvinge andre applikasjoner til å starte på nytt."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinge applikasjoner til å lukkes"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Lar applikasjonen tvinge enhver aktivitet som er i forgrunnen til å lukkes og gå tilbake. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hente intern systemtilstand"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Lar applikasjonen hente intern tilstand fra systemet. Ondsinnede applikasjoner kan hente et bredt spekter av privat og sikker informasjon som de vanligvis aldri burde ha behov for."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"delvis avslutning"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Lar applikasjonen sette aktivitetshåndtereren i avslutningstilstand. Slår ikke systemet helt av."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre applikasjonsbytte"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Lar applikasjonen forhindre brukeren fra å bytte til en annen applikasjon."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"overvåke og kontrollere all applikasjonsoppstart"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Lar applikasjonen overvåke og kontrollere hvordan systemet starter applikasjoner. Ondsinnede applikasjoner kan ta over systemet helt. Denne rettigheten behøves bare for utvikling, aldri for vanlig bruk av telefonen."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kringkaste melding om fjernet pakke"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Lar applikasjonen kringkaste en melding om at en applikasjonspakke er blitt fjernet. Ondsinnede applikasjoner kan bruke dette til å drepe vilkårlige andre kjørende applikasjoner."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"kringkaste melding om mottatt SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Lar applikasjonen kringkaste en melding om at en SMS-melding er mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kringkaste melding om mottatt WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Lar applikasjonen kringkaste en melding om at en WAP-PUSH-melding er blitt mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske MMS-kvitteringer eller i det stille erstatte innholdet av vilkårlige nettsider med ondsinnede varianter."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begrense antallet kjørende prosesser"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Lar applikasjonen kontrollere maksimalt antall kjørende prosesser. Behøves aldri for vanlige applikasjoner."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"få alle bakgrunnsapplikasjoner til å lukkes"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Lar applikasjonen kontrollere om aktiviteter alltid avsluttes når de sendes til bakgrunnen. Behøves aldri for vanlige applikasjoner."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"endre batteristatistikk"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_backup" msgid="470013022865453920">"kontrollere backup og gjenoppretting"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Lar applikasjonen kontrollere systemets backup- og gjenopprettingsmekanisme. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserte vinduer"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vise advarsler på systemnivå"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Lar applikasjonen vise systemadvarselvinduer. Ondsinnede applikasjoner kan ta over hele skjermen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"endre global animasjonshastighet"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Lar applikasjonen endre den globale animasjonshastigheten (raskere eller tregere animasjoner) når som helst."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"styre applikasjonssymboler"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Lar applikasjoner lage og vedlikeholde sine egne symboler, noe som lar dem overstyre den vanlige Z-ordningen. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"trykke taster og kontrolknapper"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Lar applikasjonen levere sine egne inndatahendelser (tastetrykk osv.) til andre applikasjoner. Ondsinnede applikasjoner kan bruke dette til å ta over telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"ta opp hva som skrives og gjøres"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Lar applikasjonen overvåke tastetrykk selv når interaksjonen er med et annet program (som å skrive inn et passord). Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binde til en inndatametode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Lar applikasjonen binde til toppnivågrensesnittet for en inndatametode. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sende Linux-signaler til applikasjoner"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"forbli kjørende"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Lar applikasjonen gjøre deler av seg selv varig, så systemet ikke kan bruke det til andre applikasjoner."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"slette applikasjoner"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Lar applikasjonen slette Android-pakker. Ondsinnede applikasjoner kan bruke dette til å slette viktige applikasjoner."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"slette andre applikasjoners data"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Lar applikasjonen fjerne brukerdata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"slette andre applikasjoners hurtigbuffer"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Lar applikasjonen to slette hurtigbufferfiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"måle lagringsplass for applikasjon"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Lar applikasjonen hente kode-, data- og hurtigbufferstørrelser"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installere applikasjoner direkte"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Lar applikasjonen installere nye eller oppdaterte Android-pakker. Ondsinnede applikasjoner kan bruke dette til å legge til nye applikasjoner med vilkårlig kraftige rettigheter."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"slette hurtigbufferdata for alle applikasjoner"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"lese systemets loggfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Lar applikasjonen to lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Lar applikasjonen to lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivere eller deaktigere applikasjonskomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Lar applikasjonen endre om en komponent i en annen applikasjon er aktivert eller ikke. Ondsinnede applikasjoner kan bruke dette til å deaktivere viktige telefonfunksjoner. Denne rettigheten må brukes med forsiktighet, ettersom det er mulig å få applikasjonskomponenter inn i en ubrukelig, inkonsistent eller ustabil tilstand."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"velge foretrukne applikasjoner"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Lar applikasjonen endre valgene for foretrukne applikasjoner. Dette kan gi ondsinnede applikasjoner tilgang til i det stille å endre hvilke applikasjoner som kjøres, og slik gi seg ut til å være en eksisterende applikasjon og samle private data."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"endre globale systeminnstillinger"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Lar applikasjonen endre systemets innstillingsdata. Ondsinnede applikasjoner kan skade systemets innstillinger."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"endre sikre systeminnstillinger"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Lar applikasjonen endre systemets sikre innstillingsdata. Ikke ment for bruk av vanlige applikasjoner."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"redigere Google-tjenestekartet"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Lar applikasjonen redigere Google-tjenestekartet. Ikke ment for bruk av vanlige applikasjoner."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"starte automatisk sammen med systemet"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Lar applikasjonen sette opp at den selv skal starte så fort systemet er ferdig med å slå seg på. Dette kan gjøre at det tar lengre tid å starte telefonen, og at den kan bli tregere fordi applikasjonen alltid kjører."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sende varige kringkastinger"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Lar applikasjonen sende varige kringkastinger, som forblir på systemet etter at kringkastingen er avsluttet. Ondsinnede applikasjoner kan gjøre telefonen treg eller ustabil ved å få den til å bruke for mye minne."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"lese kontaktinformasjon"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Lar applikasjonen lese all kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende personlige data til andre."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skrive kontaktinformasjon"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Lar applikasjonen endre kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å redigere eller endre kontaktinformasjonen."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skrive eierinformasjon"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Lar applikasjonen endre dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å slette eller redigere telefonens eierdata."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"lese eierinformasjon"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Lar applikasjonen lese dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å lese telefonens eierdata."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"lese kalenderinformasjon"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Lar applikasjonen lese alle kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende kalenderhendelser til andre."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skrive kalenderinformasjon"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Lar applikasjonen endre kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å slette eller endre kalenderinformasjon."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"lage manuelle plasseringskilder for testing"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Lage manuelle plassingskilder for testing. Ondsinnede applikasjoner kan bruke dette til å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få tilgang til ekstra plasseringskommandoer"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Få tilgang til ekstra kommandoer for plasseringskilder. Ondsinnede applikasjoner kan bruke dette til å forstyrre GPS eller andre plasseringskilder."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"installere plasseringskilder"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Lar applikasjonen lage manuelle plasseringskilder for testing. Ondsinnede applikasjoner kan bruke dette til å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører, eller overvåke og rapportere plasseringen din til en tredjepart."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"nøyaktig (GPS-) plassering"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få tilgang til nøyaktige plasseringskilder som Global Positioning System (GPS) på telefonen, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette til å finne ut hvor du er, og kan bruke mer batteri."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (nettverksbasert) plassering"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få tilgang til grove plasseringskilder som databasen over basestasjoner til å finne ut omtrent hvor telefonen er, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette til å finne ut omtrent hvor du er."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få tilgang til SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Lar applikasjonen bruke lavnivåfunksjonalitet i SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lese skjermbufferet"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Lar applikasjonen lese innholdet i skjermbufferet."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"endre lydinnstillinger"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Lar applikasjonen endre globale lydinnstillinger som volum og ruting."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ta opp lyd"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Gir applikasjonen tilgang til opptaksstien for lyd."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"ta bilder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Lar applikasjonen ta bilder med kameraet. Dette gir applikasjonen til når som helst å se og lagre det kameraet ser."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"deaktivere telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Lar applikasjonen deaktivere hele telefonen permanent. Dette er svært farlig."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tvinge omstart av telefon"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montere og avmontere filsystemer"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatere ekstern lagringsplass"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Lar applikasjonen formatere ekstern lagringsplass."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrollere vibratoren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Lar applikasjonen kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Lar applikasjonen kontrollere lommelykten."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"teste maskinvare"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Lar applikasjonen ringe telefonnummer uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake uventede oppringinger på telefonregningen. Merk at dette ikke gir applikasjonen lov til å ringe nødnummer."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ringe vilkårlige telefonnummer direkte"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Lar applikasjonen ringe hvilket som helst telefonnummer, inkludert nødnummer, uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake unødvendige og ulovlige samtaler til nødtjenester."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrollere varsling for plasseringsendring"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"få tilgang til egenskaper for innsjekking"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"velg gadgeter"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"endre telefontilstand"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
+ <string name="untitled">"<uten navn>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Mangler telefonnummer)"</string>
+ <string name="unknownName">"(Ukjent)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Telefonsvarer"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
+ <string name="serviceEnabled">"Tjenesten ble aktivert."</string>
+ <string name="serviceEnabledFor">"Tjenesten ble aktivert for:"</string>
+ <string name="serviceDisabled">"Tjenesten ble deaktivert."</string>
+ <string name="serviceRegistered">"Registreringen er vellykket."</string>
+ <string name="serviceErased">"Registreringen ble fjernet."</string>
+ <string name="passwordIncorrect">"Ugyldig passord."</string>
+ <string name="mmiComplete">"MMI utført."</string>
+ <string name="badPin">"Den gamle PIN-koden du skrev inn er feil."</string>
+ <string name="badPuk">"PUK-koden du skrev inn er feil."</string>
+ <string name="mismatchPin">"PIN-kodene stemmer ikke overens."</string>
+ <string name="invalidPin">"PIN-koden må være mellom fire og åtte siffer."</string>
+ <string name="needPuk">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
+ <string name="needPuk2">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
+ <string name="ClipMmi">"Inngående nummervisning"</string>
+ <string name="ClirMmi">"Utgående nummervisning"</string>
+ <string name="CfMmi">"Viderekobling"</string>
+ <string name="CwMmi">"Samtale venter"</string>
+ <string name="BaMmi">"Samtaleblokkering"</string>
+ <string name="PwdMmi">"Passordbytte"</string>
+ <string name="PinMmi">"PIN-kode-bytte"</string>
+ <!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Lar applikasjonen forhindre telefonen fra å gå i hvilemodus."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"slå telefonen av eller på"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Lar applikasjonen skru telefonen av eller på."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kjøre i fabrikktestmodus"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Kjøre som en lavnivås produsenttest, med full tilgang til telefonens maskinvare. Kun tilgjengelig når telefonen kjører i produsenttestmodus."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"endre bakgrunnsbilde"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Lar applikasjonen sette systemets bakgrunnsbilde."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"sette størrelseshint for bakgrunn"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Lar applikasjonen sette størrelseshint for systemets bakgrunnsbilde."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"nullstille systemet til fabrikkinnstillinger"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Lar applikasjonen nullstille systemet til fabrikkinnstillinger, noe som vil fjerne alle data, alt oppsett, og alle installerte applikasjoner."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"endre tidssone"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Lar applikasjonen endre telefonens tidssone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"oppdage kjente kontoer"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Lar applikasjonen hente listen over kontoer telefonen kjenner til."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"se nettverkstilstand"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Lar applikasjonen se tilstanden til alle nettverk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"full internett-tilgang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Lar applikasjonen opprette vilkårlige nettverkstilkoblinger."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skrive APN-innstillinger"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"endre nettverkskonnektivitet"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"endre innstilling for bakgrunnsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"se tilstand for trådløse nettverk"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"endre tilstand for trådløse nettverk"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillat multicast for trådløse nettverk"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Lar applikasjonen motta pakker som ikke er adressert til enheten selv. Dette kan være nyttig ved leting etter nærliggende tjenester, men bruker mer strøm enn ikke-multicast-modus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-administrasjon"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"opprette Bluetooth-tilkoblinger"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"slå av tastaturlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lese synkroniseringsinnstillinger"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Lar applikasjonen lese synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skrive synkroniseringsinnstillinger"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Lar applikasjonen to endre på synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"lese synkroniseringsstatistikk"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Lar applikasjonen lese synkroniseringsstatistikk, som for eksempel historien over alle synkroniseringer utført."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lese abonnement på nyhetskilder"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"endre abonnement på nyhetskilder"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"lese brukerdefinert ordliste"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skrive til brukerdefinert ordliste"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"redigere/slette innhold på minnekort"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Lar applikasjonen skrive til minnekortet."</string>
+ <!-- no translation found for CnirMmi (3062102121430548731) -->
+ <skip />
+ <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
+ <skip />
+ <!-- no translation found for RuacMmi (7827887459138308886) -->
+ <skip />
+ <!-- no translation found for CndMmi (3116446237081575808) -->
+ <skip />
+ <!-- no translation found for DndMmi (1265478932418334331) -->
+ <skip />
+ <string name="CLIRDefaultOnNextCallOn">"Nummervisning er begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Nummervisning er begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Nummervisning er ikke begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="serviceNotProvisioned">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
+ <string name="CLIRPermanent">"Kunne ikke endre innstilling for nummervisning."</string>
+ <string name="RestrictedChangedTitle">"Endring i begrenset tilgang"</string>
+ <string name="RestrictedOnData">"Datatjenesten er blokkert."</string>
+ <string name="RestrictedOnEmergency">"Nødtjenesten er blokkert."</string>
+ <string name="RestrictedOnNormal">"Tale- og SMS-tjenesten er blokkert."</string>
+ <string name="RestrictedOnAll">"Alle tale- og SMS-tjenester er blokkert."</string>
+ <string name="serviceClassVoice">"Tale"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"Fax"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkron"</string>
+ <string name="serviceClassDataSync">"Synkron"</string>
+ <string name="serviceClassPacket">"Pakkedata"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <!-- no translation found for roamingText0 (7170335472198694945) -->
+ <skip />
+ <!-- no translation found for roamingText1 (5314861519752538922) -->
+ <skip />
+ <!-- no translation found for roamingText2 (8969929049081268115) -->
+ <skip />
+ <!-- no translation found for roamingText3 (5148255027043943317) -->
+ <skip />
+ <!-- no translation found for roamingText4 (8808456682550796530) -->
+ <skip />
+ <!-- no translation found for roamingText5 (7604063252850354350) -->
+ <skip />
+ <!-- no translation found for roamingText6 (2059440825782871513) -->
+ <skip />
+ <!-- no translation found for roamingText7 (7112078724097233605) -->
+ <skip />
+ <!-- no translation found for roamingText8 (5989569778604089291) -->
+ <skip />
+ <!-- no translation found for roamingText9 (7969296811355152491) -->
+ <skip />
+ <!-- no translation found for roamingText10 (3992906999815316417) -->
+ <skip />
+ <!-- no translation found for roamingText11 (4154476854426920970) -->
+ <skip />
+ <!-- no translation found for roamingText12 (1189071119992726320) -->
+ <skip />
+ <!-- no translation found for roamingTextSearching (8360141885972279963) -->
+ <skip />
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <!-- no translation found for fcComplete (3118848230966886575) -->
+ <skip />
+ <!-- no translation found for fcError (3327560126588500777) -->
+ <skip />
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Nettsiden inneholder en feil."</string>
+ <string name="httpErrorLookup">"Kunne ikke finne adressen."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Støtter ikke sidens autentiseringsmetode."</string>
+ <string name="httpErrorAuth">"Autentiseringen feilet."</string>
+ <string name="httpErrorProxyAuth">"Autentisering via mellomtjeneren feilet."</string>
+ <string name="httpErrorConnect">"Kunne ikke koble til tjeneren."</string>
+ <string name="httpErrorIO">"Klarte ikke å kommunisere med tjeneren. Prøv igjen senere."</string>
+ <string name="httpErrorTimeout">"Det oppsto et tidsavbrudd under tilkobling til tjeneren."</string>
+ <string name="httpErrorRedirectLoop">"Siden inneholder for mange videresendinger."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollen er ikke støttet."</string>
+ <string name="httpErrorFailedSslHandshake">"Kunne ikke opprette en sikker tilkobling."</string>
+ <string name="httpErrorBadUrl">"Kunne ikke åpne siden, siden adressen er ugyldig."</string>
+ <string name="httpErrorFile">"Kunne ikke åpne filen."</string>
+ <string name="httpErrorFileNotFound">"Fant ikke den forespurte filen."</string>
+ <string name="httpErrorTooManyRequests">"For mange forespørsler blir behandlet. Prøv igjen senere."</string>
+ <string name="contentServiceSync">"Synkronisering"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkronisering"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Telefonens lagringsminne er fullt! Slett noen filer for å frigjøre plass."</string>
+ <string name="me">"Meg"</string>
+ <string name="power_dialog">"Telefoninnstillinger"</string>
+ <string name="silent_mode">"Stillemodus"</string>
+ <string name="turn_on_radio">"Slå på trådløst nett"</string>
+ <string name="turn_off_radio">"Slå av trådløst nett"</string>
+ <string name="screen_lock">"Lås skjermen"</string>
+ <string name="power_off">"Slå av"</string>
+ <string name="shutdown_progress">"Avslutter…"</string>
+ <string name="shutdown_confirm">"Telefonen vil bli slått av."</string>
+ <string name="no_recent_tasks">"Ingen nylig brukte applikasjoner."</string>
+ <string name="global_actions">"Telefoninnstillinger"</string>
+ <string name="global_action_lock">"Lås skjermen"</string>
+ <string name="global_action_power_off">"Slå av"</string>
+ <string name="global_action_toggle_silent_mode">"Stillemodus"</string>
+ <string name="global_action_silent_mode_on_status">"Lyden er av"</string>
+ <string name="global_action_silent_mode_off_status">"Lyden er på"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flymodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flymodus er på"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flymodus er av"</string>
+ <string name="safeMode">"Sikkermodus"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Betaltjenester"</string>
+ <string name="permgroupdesc_costMoney">"Lar applikasjoner utføre operasjoner som kan koste deg penger."</string>
+ <string name="permgrouplab_messages">"Meldinger"</string>
+ <string name="permgroupdesc_messages">"Lese og skrive SMS, e-post og andre meldinger på telefonen."</string>
+ <string name="permgrouplab_personalInfo">"Personlig informasjon"</string>
+ <string name="permgroupdesc_personalInfo">"Direkte tilgang til kontakter og kalendre lagret på telefonen."</string>
+ <string name="permgrouplab_location">"Plassering"</string>
+ <string name="permgroupdesc_location">"Overvåking av telefonens fysiske plassering"</string>
+ <string name="permgrouplab_network">"Nettverkstilgang"</string>
+ <string name="permgroupdesc_network">"Gir applikasjoner tilgang til diverse nettverksfunksjoner."</string>
+ <string name="permgrouplab_accounts">"Google-kontoer"</string>
+ <string name="permgroupdesc_accounts">"Tilgang til tilgjengelige Google-kontoer."</string>
+ <string name="permgrouplab_hardwareControls">"Maskinvarekontroll"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkte tilgang til maskinvaren på telefonen."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonsamtaler"</string>
+ <string name="permgroupdesc_phoneCalls">"Overvåk, ta opp, og behandle telefonsamtaler."</string>
+ <string name="permgrouplab_systemTools">"Systemverktøy"</string>
+ <string name="permgroupdesc_systemTools">"Lavnivå tilgang og kontroll over systemet."</string>
+ <string name="permgrouplab_developmentTools">"Utviklingsverktøy"</string>
+ <string name="permgroupdesc_developmentTools">"Funksjonalitet kun utviklere trenger."</string>
+ <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
+ <skip />
+ <string name="permlab_statusBar">"deaktivere eller endre statusfeltet"</string>
+ <string name="permdesc_statusBar">"Lar applikasjonen deaktivere statusfeltet, samt legge til og fjerne systemikoner."</string>
+ <string name="permlab_expandStatusBar">"utvide/slå sammen statusfeltet"</string>
+ <string name="permdesc_expandStatusBar">"Lar applikasjonen utvide eller slå sammen statusfeltet."</string>
+ <string name="permlab_processOutgoingCalls">"avskjære utgående anrop"</string>
+ <string name="permdesc_processOutgoingCalls">"Lar applikasjonen behandle utgående anrop og endre nummeret som ringes. Ondsinnede applikasjoner kan overvåke, videresende, eller hindre utgående anrop."</string>
+ <string name="permlab_receiveSms">"motta SMS"</string>
+ <string name="permdesc_receiveSms">"Lar applikasjonen motta og behandle SMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_receiveMms">"motta MMS"</string>
+ <string name="permdesc_receiveMms">"Lar applikasjonen motta og behandle MMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_sendSms">"sende SMS-meldinger"</string>
+ <string name="permdesc_sendSms">"Lar applikasjonen sende SMS-meldinger. Ondsinnede applikasjoner kan koste deg penger ved å sende meldinger uten bekreftelse."</string>
+ <string name="permlab_readSms">"lese SMS- og MMS-meldinger"</string>
+ <string name="permdesc_readSms">"Lar applikasjonen lese SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan lese private meldinger."</string>
+ <string name="permlab_writeSms">"redigere SMS- og MMS-meldinger"</string>
+ <string name="permdesc_writeSms">"Lar applikasjonen skrive til SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan slette meldinger."</string>
+ <string name="permlab_receiveWapPush">"motta WAP"</string>
+ <string name="permdesc_receiveWapPush">"Lar applikasjonen motta og behandle WAP-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_getTasks">"se kjørende applikasjoner"</string>
+ <string name="permdesc_getTasks">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
+ <string name="permlab_reorderTasks">"omordne kjørende applikasjoner"</string>
+ <string name="permdesc_reorderTasks">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
+ <string name="permlab_setDebugApp">"aktiver applikasjonsdebugging"</string>
+ <string name="permdesc_setDebugApp">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
+ <string name="permlab_changeConfiguration">"endre innstillingene for brukergrensesnitt"</string>
+ <string name="permdesc_changeConfiguration">"Tillater applikasjonen å endre gjeldende innstillinger, slik som språk eller skriftstørrelse."</string>
+ <string name="permlab_restartPackages">"omstarte andre applikasjoner"</string>
+ <string name="permdesc_restartPackages">"Lar applikasjonen tvinge andre applikasjoner til å starte på nytt."</string>
+ <string name="permlab_forceBack">"tvinge applikasjoner til å lukkes"</string>
+ <string name="permdesc_forceBack">"Lar applikasjonen tvinge enhver aktivitet som er i forgrunnen til å lukkes og gå tilbake. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_dump">"hente intern systemtilstand"</string>
+ <string name="permdesc_dump">"Lar applikasjonen hente intern tilstand fra systemet. Onsdinnede applikasjoner kan hente et bredt spekter av privat og sikker informasjon som de vanligvis aldri burde ha behov for."</string>
+ <!-- no translation found for permlab_shutdown (7185747824038909016) -->
+ <skip />
+ <!-- no translation found for permdesc_shutdown (7046500838746291775) -->
+ <skip />
+ <!-- no translation found for permlab_stopAppSwitches (4138608610717425573) -->
+ <skip />
+ <!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
+ <skip />
+ <string name="permlab_runSetActivityWatcher">"overvåke og kontrollere all applikasjonsoppstart"</string>
+ <string name="permdesc_runSetActivityWatcher">"Lar applikasjonen overvåke og kontrollere hvordan systemet starter applikasjoner. Ondsinnede applikasjoner kan ta over systemet helt. Denne rettigheten behøves bare for utvikling, aldri for vanlig bruk av telefonen."</string>
+ <string name="permlab_broadcastPackageRemoved">"kringkaste melding om fjernet pakke"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Lar applikasjonen kringkaste en melding om at en applikasjonspakke er blitt fjernet. Ondsinnede applikasjoner kan bruke dette til å drepe vilkårlige andre kjørende applikasjoner."</string>
+ <string name="permlab_broadcastSmsReceived">"kringkaste melding om mottatt SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Lar applikasjonen kringkaste en melding om at en SMS-melding er mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
+ <string name="permlab_broadcastWapPush">"kringkaste melding om mottatt WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Lar applikasjonen kringkaste en melding om at en WAP-PUSH-melding er blitt mottatt. Ondsinnede applikasjoner kan bruke dette for å forfalske MMS-kvitteringer eller i det stille erstatte innholdet av vilkårlige nettsider med ondsinnede varianter."</string>
+ <string name="permlab_setProcessLimit">"begrense antallet kjørende prosesser"</string>
+ <string name="permdesc_setProcessLimit">"Lar applikasjonen kontrollere maksimalt antall kjørende prosesser. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_setAlwaysFinish">"få alle bakgrunnsapplikasjoner til å lukkes"</string>
+ <string name="permdesc_setAlwaysFinish">"Lar applikasjonen kontrollere om aktiviteter alltid avsluttes når de sendes til bakgrunnen. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_batteryStats">"endre batteristatistikk"</string>
+ <string name="permdesc_batteryStats">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
+ <!-- no translation found for permlab_backup (470013022865453920) -->
+ <skip />
+ <!-- no translation found for permdesc_backup (2305432853944929371) -->
+ <skip />
+ <string name="permlab_internalSystemWindow">"vis uautoriserte vinduer"</string>
+ <string name="permdesc_internalSystemWindow">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_systemAlertWindow">"vise advarsler på systemnivå"</string>
+ <string name="permdesc_systemAlertWindow">"Lar applikasjonen vise systemadvarselvinduer. Ondsinnede applikasjoner kan ta over hele skjermen."</string>
+ <string name="permlab_setAnimationScale">"endre global animasjonshastighet"</string>
+ <string name="permdesc_setAnimationScale">"Lar applikasjonen endre den globale animasjonshastigheten (raskere eller tregere animasjoner) når som helst."</string>
+ <string name="permlab_manageAppTokens">"styre applikasjonssymboler"</string>
+ <string name="permdesc_manageAppTokens">"Lar applikasjoner lage og vedlikeholde sine egne symboler, noe som lar dem overstyre den vanlige Z-ordningen. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_injectEvents">"trykke taster og kontrolknapper"</string>
+ <string name="permdesc_injectEvents">"Lar applikasjonen levere sine egne inndatahendelser (tastetrykk osv.) til andre applikasjoner. Ondsinnede applikasjoner kan bruke dette for å ta over telefonen."</string>
+ <string name="permlab_readInputState">"ta opp hva som skrives og gjøres"</string>
+ <string name="permdesc_readInputState">"Lar applikasjonen overvåke tastetrykk selv når interaksjonen er med et annet program (som å skrive inn et passord). Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_bindInputMethod">"binde til en inndatametode"</string>
+ <string name="permdesc_bindInputMethod">"Lar applikasjonen binde til toppnivågrensesnittet for en inndatametode. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_setOrientation">"snu skjermen"</string>
+ <string name="permdesc_setOrientation">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_signalPersistentProcesses">"sende Linux-signaler til applikasjoner"</string>
+ <string name="permdesc_signalPersistentProcesses">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
+ <string name="permlab_persistentActivity">"forbli kjørende"</string>
+ <string name="permdesc_persistentActivity">"Lar applikasjonen gjøre deler av seg selv varig, så systemet ikke kan bruke det til andre applikasjoner."</string>
+ <string name="permlab_deletePackages">"slette applikasjoner"</string>
+ <string name="permdesc_deletePackages">"Lar applikasjonen slette Android-pakker. Ondsinnede applikasjoner kan bruke dette for å slette viktige applikasjoner."</string>
+ <string name="permlab_clearAppUserData">"slette andre applikasjoners data"</string>
+ <string name="permdesc_clearAppUserData">"Lar applikasjonen fjerne brukerdata."</string>
+ <string name="permlab_deleteCacheFiles">"slette andre applikasjoners hurtigbuffer"</string>
+ <string name="permdesc_deleteCacheFiles">"Lar applikasjonen to slette hurtigbufferfiler."</string>
+ <string name="permlab_getPackageSize">"måle lagringsplass for applikasjon"</string>
+ <string name="permdesc_getPackageSize">"Lar applikasjonen hente kode-, data- og hurtigbufferstørrelser"</string>
+ <string name="permlab_installPackages">"installere applikasjoner direkte"</string>
+ <string name="permdesc_installPackages">"Lar applikasjonen installere nye eller oppdaterte Android-pakker. Ondsinnede applikasjoner kan bruke dette for å legge til nye applikasjoner med vilkårlig kraftige rettigheter."</string>
+ <string name="permlab_clearAppCache">"slette hurtigbufferdata for alle applikasjoner"</string>
+ <string name="permdesc_clearAppCache">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
+ <string name="permlab_readLogs">"lese systemets loggfiler"</string>
+ <string name="permdesc_readLogs">"Lar applikasjonen to lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
+ <string name="permlab_diagnostic">"lese/skrive ressurser eid av diag"</string>
+ <string name="permdesc_diagnostic">"Lar applikasjonen to lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
+ <string name="permlab_changeComponentState">"aktivere eller deaktigere applikasjonskomponenter"</string>
+ <string name="permdesc_changeComponentState">"Lar applikasjonen endre om en komponent i en annen applikasjon er aktivert eller ikke. Ondsinnede applikasjoner kan bruke dette for å deaktivere viktige telefonfunksjoner. Denne rettigheten må brukes med forsiktighet, ettersom det er mulig å få applikasjonskomponenter inn i en ubrukelig, inkonsistent eller ustabil tilstand."</string>
+ <string name="permlab_setPreferredApplications">"velge foretrukne applikasjoner"</string>
+ <string name="permdesc_setPreferredApplications">"Lar applikasjonen endre valgene for foretrukne applikasjoner. Dette kan gi ondsinnede applikasjoner tilgang til i det stille å endre hvilke applikasjoner som kjøres, og slik gi seg ut for å være en eksisterende applikasjon og samle private data."</string>
+ <string name="permlab_writeSettings">"endre globale systeminnstillinger"</string>
+ <string name="permdesc_writeSettings">"Lar applikasjonen endre systemets innstillingsdata. Ondsinnede applikasjoner kan skade systemets innstillinger."</string>
+ <string name="permlab_writeSecureSettings">"endre sikre systeminnstillinger"</string>
+ <string name="permdesc_writeSecureSettings">"Lar applikasjonen endre systemets sikre innstillingsdata. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_writeGservices">"redigere Google-tjenestekartet"</string>
+ <string name="permdesc_writeGservices">"Lar applikasjonen redigere Google-tjenestekartet. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_receiveBootCompleted">"starte automatisk sammen med systemet"</string>
+ <string name="permdesc_receiveBootCompleted">"Lar applikasjonen sette opp at den selv skal starte så fort systemet er ferdig med å slå seg på. Dette kan gjøre at det tar lengre tid å starte telefonen, og at den kan bli tregere fordi applikasjonen alltid kjører."</string>
+ <string name="permlab_broadcastSticky">"sende varige kringkastinger"</string>
+ <string name="permdesc_broadcastSticky">"Lar applikasjonen sende varige kringkastinger, som forblir på systemet etter at kringkastingen er avsluttet. Ondsinnede applikasjoner kan gjøre telefonen treg eller ustabil ved å få den til å bruke for mye minne."</string>
+ <string name="permlab_readContacts">"lese kontaktinformasjon"</string>
+ <string name="permdesc_readContacts">"Lar applikasjonen lese all kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å sende personlige data til andre."</string>
+ <string name="permlab_writeContacts">"skrive kontaktinformasjon"</string>
+ <string name="permdesc_writeContacts">"Lar applikasjonen endre kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å redigere eller endre kontaktinformasjonen."</string>
+ <string name="permlab_writeOwnerData">"skrive eierinformasjon"</string>
+ <string name="permdesc_writeOwnerData">"Lar applikasjonen endre dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å slette eller redigere telefonens eierdata."</string>
+ <string name="permlab_readOwnerData">"lese eierinformasjon"</string>
+ <string name="permdesc_readOwnerData">"Lar applikasjonen lese dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å lese telefonens eierdata."</string>
+ <string name="permlab_readCalendar">"lese kalenderinformasjon"</string>
+ <string name="permdesc_readCalendar">"Lar applikasjonen lese alle kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende kalenderhendelser til andre."</string>
+ <string name="permlab_writeCalendar">"skrive kalenderinformasjon"</string>
+ <string name="permdesc_writeCalendar">"Lar applikasjonen endre kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å slette eller endre kalenderinformasjon."</string>
+ <string name="permlab_accessMockLocation">"lage falske plasseringskilder for testing"</string>
+ <string name="permdesc_accessMockLocation">"Lage falske plassingskilder for testing. Ondsinnede applikasjoner kan bruke dette for å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører."</string>
+ <string name="permlab_accessLocationExtraCommands">"få tilgang til ekstra plasseringskommandoer"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få tilgang til ekstra kommandoer for plasseringskilder. Ondsinnede applikasjoner kan bruke dette til å forstyrre GPS eller andre plasseringskilder."</string>
+ <!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
+ <skip />
+ <!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
+ <skip />
+ <string name="permlab_accessFineLocation">"nøyaktig (GPS-) plassering"</string>
+ <string name="permdesc_accessFineLocation">"Få tilgang til nøyaktige plasseringskilder som Global Positioning System (GPS) på telefonen, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut hvor du er, og kan bruke mer batteri."</string>
+ <string name="permlab_accessCoarseLocation">"grov (nettverksbasert) plassering"</string>
+ <string name="permdesc_accessCoarseLocation">"Få tilgang til grove plasseringskilder som databasen over basestasjoner for å finne ut omtrent hvor telefonen er, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut omtrent hvor du er."</string>
+ <string name="permlab_accessSurfaceFlinger">"få tilgang til SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Lar applikasjonen bruke lavnivåfunksjonalitet i SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"lese skjermbufferet"</string>
+ <string name="permdesc_readFrameBuffer">"Lar applikasjonen lese innholdet i skjermbufferet."</string>
+ <string name="permlab_modifyAudioSettings">"endre lydinnstillinger"</string>
+ <string name="permdesc_modifyAudioSettings">"Lar applikasjonen endre globale lydinnstillinger som volum og ruting."</string>
+ <string name="permlab_recordAudio">"ta opp lyd"</string>
+ <string name="permdesc_recordAudio">"Gir applikasjonen tilgang til opptaksstien for lyd."</string>
+ <string name="permlab_camera">"ta bilder"</string>
+ <string name="permdesc_camera">"Lar applikasjonen ta bilder med kameraet. Dette gir applikasjonen til når som helst å se og lagre det kameraet ser."</string>
+ <string name="permlab_brick">"deaktivere telefonen permanent"</string>
+ <string name="permdesc_brick">"Lar applikasjonen deaktivere hele telefonen permanent. Dette er svært farlig."</string>
+ <string name="permlab_reboot">"tvinge omstart av telefon"</string>
+ <string name="permdesc_reboot">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
+ <string name="permlab_mount_unmount_filesystems">"montere og avmontere filsystemer"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
+ <string name="permlab_mount_format_filesystems">"formatere ekstern lagringsplass"</string>
+ <string name="permdesc_mount_format_filesystems">"Lar applikasjonen formatere ekstern lagringsplass."</string>
+ <string name="permlab_vibrate">"kontrollere vibratoren"</string>
+ <string name="permdesc_vibrate">"Lar applikasjonen kontrollere vibratoren."</string>
+ <string name="permlab_flashlight">"kontrollere lommelykten"</string>
+ <string name="permdesc_flashlight">"Lar applikasjonen kontrollere lommelykten."</string>
+ <string name="permlab_hardware_test">"teste maskinvare"</string>
+ <string name="permdesc_hardware_test">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
+ <string name="permlab_callPhone">"ringe telefonnummer direkte"</string>
+ <string name="permdesc_callPhone">"Lar applikasjonen ringe telefonnummer uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake uventede oppringinger på telefonregningen. Merk at dette ikke gir applikasjonen lov til å ringe nødnummer."</string>
+ <string name="permlab_callPrivileged">"ringe vilkårlige telefonnummer direkte"</string>
+ <string name="permdesc_callPrivileged">"Lar applikasjonen ringe hvilket som helst telefonnummer, inkludert nødnummer, uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake unødvendige og ulovlige samtaler til nødtjenester."</string>
+ <string name="permlab_locationUpdates">"kontrollere varsling for plasseringsendring"</string>
+ <string name="permdesc_locationUpdates">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_checkinProperties">"få tilgang til egenskaper for innsjekking"</string>
+ <string name="permdesc_checkinProperties">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_bindGadget">"velg gadgeter"</string>
+ <string name="permdesc_bindGadget">"Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_modifyPhoneState">"endre telefontilstand"</string>
+ <string name="permdesc_modifyPhoneState">"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."</string>
+ <string name="permlab_readPhoneState">"lese telefontilstand"</string>
+ <string name="permdesc_readPhoneState">"Lar applikasjonen få tilgang til telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan få vite enhetens telefonnummer, om en samtale pågår, nummeret samtalen er koblet til og lignende."</string>
+ <string name="permlab_wakeLock">"forhindre telefonen fra å sove"</string>
+ <string name="permdesc_wakeLock">"Lar applikasjonen forhindre telefonen fra å gå i hvilemodus."</string>
+ <string name="permlab_devicePower">"slå telefonen av eller på"</string>
+ <string name="permdesc_devicePower">"Lar applikasjonen skru telefonen av eller på."</string>
+ <string name="permlab_factoryTest">"kjøre i fabrikktestmodus"</string>
+ <string name="permdesc_factoryTest">"Kjøre som en lavnivås produsenttest, med full tilgang til telefonens maskinvare. Kun tilgjengelig når telefonen kjører i produsenttestmodus."</string>
+ <string name="permlab_setWallpaper">"endre bakgrunnsbilde"</string>
+ <string name="permdesc_setWallpaper">"Lar applikasjonen sette systemets bakgrunnsbilde."</string>
+ <string name="permlab_setWallpaperHints">"sette størrelseshint for bakgrunn"</string>
+ <string name="permdesc_setWallpaperHints">"Lar applikasjonen sette størrelseshint for systemets bakgrunnsbilde."</string>
+ <string name="permlab_masterClear">"nullstille systemet til fabrikkinnstillinger"</string>
+ <string name="permdesc_masterClear">"Lar applikasjonen nullstille systemet til fabrikkinnstillinger, noe som vil fjerne alle data, alt oppsett, og alle installerte applikasjoner."</string>
+ <string name="permlab_setTimeZone">"endre tidssone"</string>
+ <string name="permdesc_setTimeZone">"Lar applikasjonen endre telefonens tidssone."</string>
+ <string name="permlab_getAccounts">"oppdage kjente kontoer"</string>
+ <string name="permdesc_getAccounts">"Lar applikasjonen hente listen over kontoer telefonen kjenner til."</string>
+ <string name="permlab_accessNetworkState">"se nettverkstilstand"</string>
+ <string name="permdesc_accessNetworkState">"Lar applikasjonen se tilstanden til alle nettverk."</string>
+ <string name="permlab_createNetworkSockets">"full internett-tilgang"</string>
+ <string name="permdesc_createNetworkSockets">"Lar applikasjonen opprette vilkårlige nettverkstilkoblinger."</string>
+ <string name="permlab_writeApnSettings">"skrive APN-innstillinger"</string>
+ <string name="permdesc_writeApnSettings">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
+ <string name="permlab_changeNetworkState">"endre nettverkskonnektivitet"</string>
+ <string name="permdesc_changeNetworkState">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
+ <string name="permlab_changeBackgroundDataSetting">"endre innstilling for bakgrunnsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
+ <string name="permlab_accessWifiState">"se tilstand for trådløse nettverk"</string>
+ <string name="permdesc_accessWifiState">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
+ <string name="permlab_changeWifiState">"endre tilstand for trådløse nettverk"</string>
+ <string name="permdesc_changeWifiState">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
+ <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
+ <skip />
+ <string name="permlab_bluetoothAdmin">"Bluetooth-administrasjon"</string>
+ <string name="permdesc_bluetoothAdmin">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
+ <string name="permlab_bluetooth">"opprette Bluetooth-tilkoblinger"</string>
+ <string name="permdesc_bluetooth">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
+ <string name="permlab_disableKeyguard">"slå av tastaturlås"</string>
+ <string name="permdesc_disableKeyguard">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
+ <string name="permlab_readSyncSettings">"lese synkroniseringsinnstillinger"</string>
+ <string name="permdesc_readSyncSettings">"Lar applikasjonen lese synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_writeSyncSettings">"skrive synkroniseringsinnstillinger"</string>
+ <string name="permdesc_writeSyncSettings">"Lar applikasjonen to endre på synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_readSyncStats">"lese synkroniseringsstatistikk"</string>
+ <string name="permdesc_readSyncStats">"Lar applikasjonen lese synkroniseringsstatistikk, som for eksempel historien over alle synkroniseringer utført."</string>
+ <string name="permlab_subscribedFeedsRead">"lese abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsRead">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_subscribedFeedsWrite">"endre abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_readDictionary">"lese brukerdefinert ordliste"</string>
+ <string name="permdesc_readDictionary">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
+ <string name="permlab_writeDictionary">"skrive til brukerdefinert ordliste"</string>
+ <string name="permdesc_writeDictionary">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
+ <!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
+ <skip />
+ <!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
+ <skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Hjemmenummer"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbeid"</item>
- <item msgid="1103601433382158155">"Faks arbeid"</item>
- <item msgid="1735177144948329370">"Faks hjemme"</item>
- <item msgid="603878674477207394">"Personsøker"</item>
- <item msgid="1650824275177931637">"Annen"</item>
- <item msgid="9192514806975898961">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Mobil"</item>
+ <item>"Arbeid"</item>
+ <item>"Faks arbeid"</item>
+ <item>"Faks hjemme"</item>
+ <item>"Personsøker"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Hjemme"</item>
- <item msgid="7084237356602625604">"Arbeid"</item>
- <item msgid="1112044410659011023">"Annen"</item>
- <item msgid="2374913952870110618">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
+ <!-- no translation found for mobileEmailTypeName (2858957283716687707) -->
+ <skip />
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Hjemme"</item>
- <item msgid="5629153956045109251">"Arbeid"</item>
- <item msgid="4966604264500343469">"Annen"</item>
- <item msgid="4932682847595299369">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Hjemme"</item>
- <item msgid="1359644565647383708">"Arbeid"</item>
- <item msgid="7868549401053615677">"Annen"</item>
- <item msgid="3145118944639869809">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbeid"</item>
- <item msgid="4378074129049520373">"Annen"</item>
- <item msgid="3455047468583965104">"Egendefinert…"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Skriv inn PIN-kode:"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Gal PIN-kode!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"For å låse opp, trykk på Meny og deretter 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen operatør)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skjermen er låst"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Trykk på menyknappen for å låse opp."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Tegn mønster for å låse opp"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nødanrop"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Riktig!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Beklager, prøv igjen:"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Lader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Fullt ladet"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Koble til en batterilader."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Mangler SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Ikke noe SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Sett inn et SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Nettverk ikke tillatt"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kortet er PUK-låst."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se manualen eller kontakt kundeservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser opp SIM-kort…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glemt mønsteret?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"For mange mønsterforsøk!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"For å låse opp, logg på med Google-kontoen din"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Brukernavn (e-post)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logg inn"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldig brukernavn eller passord."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Fjern"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Lader…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Koble til en lader"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er nesten tomt:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Hvorfor?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Factory test failed"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No package was found that provides the FACTORY_TEST action."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reboot"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Siden \'<xliff:g id="TITLE">%s</xliff:g> sier:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lese nettleserens historie og bokmerker"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Lar applikasjonen lese alle adresser nettleseren har besøkt, og alle nettleserens bokmerker."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skrive til nettleserens historie og bokmerker"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Lar applikasjonen endre nettleserens historie og bokmerker lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å fjerne eller redigere nettleserens data."</string>
- <string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldri"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har ikke de nødvendige rettighetene til å åpne denne siden."</string>
- <string name="text_copied" msgid="4985729524670131385">"Kopierte tekst til utklippstavlen."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"menyknapp+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mellomrom"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"slett"</string>
- <string name="search_go" msgid="8298016669822141719">"Søk"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
+ <string name="keyguard_password_enter_pin_code">"Skriv inn PIN-kode:"</string>
+ <string name="keyguard_password_wrong_pin_code">"Gal PIN-kode!"</string>
+ <string name="keyguard_label_text">"For å låse opp, trykk menuknappen fulgt av 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nødnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen operatør)"</string>
+ <string name="lockscreen_screen_locked">"Skjermen er låst"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Trykk på menyknappen for å låse opp."</string>
+ <string name="lockscreen_pattern_instructions">"Tegn mønster for å låse opp"</string>
+ <string name="lockscreen_emergency_call">"Nødanrop"</string>
+ <string name="lockscreen_pattern_correct">"Riktig!"</string>
+ <string name="lockscreen_pattern_wrong">"Beklager, prøv igjen:"</string>
+ <string name="lockscreen_plugged_in">"Lader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Koble til en batterilader."</string>
+ <string name="lockscreen_missing_sim_message_short">"Mangler SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Ikke noe SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Sett inn et SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Nettverk ikke tillatt"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kortet er PUK-låst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se manualen eller kontakt kundeservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet er låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser opp SIM-kort…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Glemt mønsteret?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"For mange mønsterforsøk!"</string>
+ <string name="lockscreen_glogin_instructions">"For å låse opp, logg inn med Google-kontoen din"</string>
+ <string name="lockscreen_glogin_username_hint">"Brukernavn (e-post)"</string>
+ <string name="lockscreen_glogin_password_hint">"Passord"</string>
+ <string name="lockscreen_glogin_submit_button">"Logg inn"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ugyldig brukernavn eller passord."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Ingen varslinger"</string>
+ <string name="status_bar_ongoing_events_title">"Aktiviteter"</string>
+ <string name="status_bar_latest_events_title">"Varslinger"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Lader…"</string>
+ <string name="battery_low_title">"Koble til en lader"</string>
+ <string name="battery_low_subtitle">"Batteriet er nesten tomt:"</string>
+ <string name="battery_low_percent_format">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
+ <!-- no translation found for battery_low_why (7655196144309694753) -->
+ <skip />
+ <string name="factorytest_failed">"Factory test failed"</string>
+ <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
+ <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
+ <string name="factorytest_reboot">"Reboot"</string>
+ <string name="js_dialog_title">"Siden \'<xliff:g id="TITLE">%s</xliff:g> sier:\""</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
+ <string name="save_password_label">"Bekreft"</string>
+ <!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
+ <skip />
+ <!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
+ <skip />
+ <!-- no translation found for permlab_writeHistoryBookmarks (9009434109836280374) -->
+ <skip />
+ <!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
+ <skip />
+ <string name="save_password_message">"Ønsker du at nettleseren skal huske dette passordet?"</string>
+ <string name="save_password_notnow">"Ikke nå"</string>
+ <string name="save_password_remember">"Husk"</string>
+ <string name="save_password_never">"Aldri"</string>
+ <string name="open_permission_deny">"Du har ikke de nødvendige rettighetene til å åpne denne siden."</string>
+ <string name="text_copied">"Kopierte tekst til utklippstavlen."</string>
+ <string name="more_item_label">"Mer"</string>
+ <string name="prepend_shortcut_label">"menyknapp+"</string>
+ <string name="menu_space_shortcut_label">"mellomrom"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"slett"</string>
+ <string name="search_go">"Søk"</string>
+ <string name="oneMonthDurationPast">"For en måned siden"</string>
+ <string name="beforeOneMonthDurationPast">"For over en måned siden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"for et sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
+ <item quantity="one">"for et sekund siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"for et minutt siden"</item>
- <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
+ <item quantity="one">"for et minutt siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"for en time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"for en time siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om et sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om et sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om et minutt"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om et minutt"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sek siden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
+ <item quantity="one">"1 sek siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min siden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
+ <item quantity="one">"1 min siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 t siden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
+ <item quantity="one">"1 t siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
+ <item quantity="one">"om 1 sek"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"om 1 min"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 t"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
+ <item quantity="one">"om 1 t"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dager"</string>
- <string name="hour" msgid="2126771916426189481">"time"</string>
- <string name="hours" msgid="894424005266852993">"timer"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"uke"</string>
- <string name="weeks" msgid="6509623834583944518">"uker"</string>
- <string name="year" msgid="4001118221013892076">"år"</string>
- <string name="years" msgid="6881577717993213522">"år"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hverdager (man–fre)"</string>
- <string name="daily" msgid="5738949095624133403">"Hver dag"</string>
- <string name="weekly" msgid="983428358394268344">"Hver <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"En gang i måneden"</string>
- <string name="yearly" msgid="1519577999407493836">"En gang i året"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Kan ikke spille video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Beklager, denne videoen er ikke gyldig for streaming til denne enheten."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Beklager, kan ikke spille denne videoen."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"middag"</string>
- <string name="Noon" msgid="3342127745230013127">"Middag"</string>
- <string name="midnight" msgid="7166259508850457595">"midnatt"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Merk alt"</string>
- <string name="selectText" msgid="3889149123626888637">"Merk tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Slutt å merke tekst"</string>
- <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klipp ut alt"</string>
- <string name="copy" msgid="2681946229533511987">"Kopier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopier alt"</string>
- <string name="paste" msgid="5629880836805036433">"Lim inn"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopier URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Inndatametode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Legg «%s» til ordlisten"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Rediger tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Lite plass"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Det begynner å bli lite lagringsplass på telefonen."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Merk"</string>
- <string name="capital_on" msgid="1544682755514494298">"På"</string>
- <string name="capital_off" msgid="6815870386972805832">"Av"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Complete action using"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Clear default in Home Settings > Applications > Manage applications."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Select an action"</string>
- <string name="noApplications" msgid="1691104391758345586">"No applications can perform this action."</string>
- <string name="aerr_title" msgid="653922989522758100">"Sorry!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
- <string name="aerr_process" msgid="1551785535966089511">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
- <string name="anr_title" msgid="3100070910664756057">"Sorry!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_process" msgid="1246866008169975783">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
- <string name="force_close" msgid="3653416315450806396">"Force close"</string>
- <string name="report" msgid="4060218260984795706">"Rapportér"</string>
- <string name="wait" msgid="7147118217226317732">"Wait"</string>
- <string name="debug" msgid="9103374629678531849">"Debug"</string>
- <string name="sendText" msgid="5132506121645618310">"Select an action for text"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ringetonevolum"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medievolum"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spiller over Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Samtalevolum"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth-samtalevolum"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmvolum"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Varslingsvolum"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volum"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Stille"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Ukjent ringetone"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dager"</string>
+ <string name="hour">"time"</string>
+ <string name="hours">"timer"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"uke"</string>
+ <string name="weeks">"uker"</string>
+ <string name="year">"år"</string>
+ <string name="years">"år"</string>
+ <string name="every_weekday">"Hverdager (man–fre)"</string>
+ <string name="daily">"Hver dag"</string>
+ <string name="weekly">"Hver <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"En gang i måneden"</string>
+ <string name="yearly">"En gang i året"</string>
+ <string name="VideoView_error_title">"Kan ikke spille video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Beklager, denne videoen er ikke gyldig for streaming til denne enheten."</string>
+ <string name="VideoView_error_text_unknown">"Beklager, kan ikke spille denne videoen."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"middag"</string>
+ <string name="Noon">"Middag"</string>
+ <string name="midnight">"midnatt"</string>
+ <string name="Midnight">"Midnatt"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Merk alt"</string>
+ <string name="selectText">"Merk tekst"</string>
+ <string name="stopSelectingText">"Slutt å merke tekst"</string>
+ <string name="cut">"Klipp ut"</string>
+ <string name="cutAll">"Klipp ut alt"</string>
+ <string name="copy">"Kopier"</string>
+ <string name="copyAll">"Kopier alt"</string>
+ <string name="paste">"Lim inn"</string>
+ <string name="copyUrl">"Kopier URL"</string>
+ <string name="inputMethod">"Inndatametode"</string>
+ <string name="addToDictionary">"Legg \\\"%s\\\" til ordlisten"</string>
+ <string name="editTextMenuTitle">"Rediger tekst"</string>
+ <string name="low_internal_storage_view_title">"Lite plass"</string>
+ <string name="low_internal_storage_view_text">"Det begynner å bli lite lagringsplass på telefonen."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Avbryt"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Avbryt"</string>
+ <string name="dialog_alert_title">"Merk"</string>
+ <string name="capital_on">"På"</string>
+ <string name="capital_off">"Av"</string>
+ <string name="whichApplication">"Complete action using"</string>
+ <string name="alwaysUse">"Use by default for this action."</string>
+ <string name="clearDefaultHintMsg">"Clear default in Home Settings > Applications > Manage applications."</string>
+ <string name="chooseActivity">"Select an action"</string>
+ <string name="noApplications">"No applications can perform this action."</string>
+ <string name="aerr_title">"Sorry!"</string>
+ <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
+ <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
+ <string name="anr_title">"Sorry!"</string>
+ <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
+ <string name="force_close">"Force close"</string>
+ <!-- no translation found for report (4060218260984795706) -->
+ <skip />
+ <string name="wait">"Wait"</string>
+ <string name="debug">"Debug"</string>
+ <string name="sendText">"Select an action for text"</string>
+ <string name="volume_ringtone">"Ringetonevolum"</string>
+ <string name="volume_music">"Medievolum"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spiller over Bluetooth"</string>
+ <string name="volume_call">"Samtalevolum"</string>
+ <string name="volume_bluetooth_call">"Bluetooth-samtalevolum"</string>
+ <string name="volume_alarm">"Alarmvolum"</string>
+ <string name="volume_notification">"Varslingsvolum"</string>
+ <string name="volume_unknown">"Volum"</string>
+ <string name="ringtone_default">"Standard ringetone"</string>
+ <string name="ringtone_default_with_actual">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Stille"</string>
+ <string name="ringtone_picker_title">"Ringetoner"</string>
+ <string name="ringtone_unknown">"Ukjent ringetone"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Trådløsnett i nærheten"</item>
- <item quantity="other" msgid="4192424489168397386">"Trådløsnett i nærheten"</item>
+ <item quantity="one">"Trådløsnett i nærheten"</item>
+ <item quantity="other">"Trådløsnett i nærheten"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Åpent trådløsnett i nærheten"</item>
- <item quantity="other" msgid="7915895323644292768">"Åpne trådløsnett i nærheten"</item>
+ <item quantity="one">"Åpent trådløsnett i nærheten"</item>
+ <item quantity="other">"Åpne trådløsnett i nærheten"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Ukjent applikasjon"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Et stort antall SMS-meldinger blir sendt. Velg «OK» for å fortsette, eller «Avbryt» for å avbryte sendingen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Lagre"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skjul"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Laster inn…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB koblet til"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har koblet telefonen til en datamaskin via USB. Velg «Montér» dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montér"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Ikke montér"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB tilkoblet"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Slå av USB-lagring"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Velg for å slå av USB-lagring."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Slå av USB-lagring"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Slå av"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Avbryt"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatere minnekort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-debugging tilkoblet"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"En datamaskin er koblet til telefonen."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Velg inndatametode"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
- <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Forbereder minnekort"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Sjekker for feil."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tomt minnekort"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Minnekortet er tomt eller har et ikke-støttet filsystem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Skadet minnekort"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Minnekortet er skadet. Du må kanskje formatere det."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Minnekortet ble tatt ut uventet"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Trygt å ta ut minnekort"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Det er trygt å ta ut minnekortet."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Minnekortet ble tatt ut"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Minnekortet ble fjernet. Sett inn et nytt."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Fant ingen tilsvarende aktiviteter"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"oppdater statistikk over komponentbruk"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trykk to ganger for zoomkontroll"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Feil under oppakking av gadget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Gå"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Søk"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Send"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Neste"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Utført"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Utfør"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Ring nummeret"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Lag kontakt"\n"med nummeret <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"valgt"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"ikke valgt"</string>
+ <string name="select_character">"Sett inn tegn"</string>
+ <string name="sms_control_default_app_name">"Ukjent applikasjon"</string>
+ <string name="sms_control_title">"Sending SMS messages"</string>
+ <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Avbryt"</string>
+ <string name="date_time_set">"Lagre"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Trenger ingen rettigheter"</string>
+ <string name="perms_hide"><b>"Skjul"</b></string>
+ <string name="perms_show_all"><b>"Vis alle"</b></string>
+ <string name="googlewebcontenthelper_loading">"Laster inn…"</string>
+ <string name="usb_storage_title">"USB koblet til"</string>
+ <string name="usb_storage_message">"Du har koblet telefonen til en datamaskin via USB. Velg \"Monter\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Ikke monter"</string>
+ <string name="usb_storage_error_message">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB tilkoblet"</string>
+ <string name="usb_storage_notification_message">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
+ <string name="usb_storage_stop_notification_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_notification_message">"Velg for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_message">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_button_mount">"Slå av"</string>
+ <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+ <string name="usb_storage_stop_error_message">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
+ <string name="extmedia_format_title">"Formatere minnekort"</string>
+ <string name="extmedia_format_message">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Velg inndatametode"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="candidates_style">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
+ <string name="ext_media_checking_notification_title">"Forbereder minnekort"</string>
+ <!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
+ <skip />
+ <string name="ext_media_nofs_notification_title">"Tomt minnekort"</string>
+ <!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
+ <skip />
+ <string name="ext_media_unmountable_notification_title">"Skadet minnekort"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
+ <skip />
+ <string name="ext_media_badremoval_notification_title">"Minnekortet ble tatt ut uventet"</string>
+ <string name="ext_media_badremoval_notification_message">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Trygt å ta ut minnekort"</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
+ <skip />
+ <string name="ext_media_nomedia_notification_title">"Minnekortet ble tatt ut"</string>
+ <!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
+ <skip />
+ <string name="activity_list_empty">"Fant ingen tilsvarende aktiviteter"</string>
+ <string name="permlab_pkgUsageStats">"oppdater statistikk over komponentbruk"</string>
+ <string name="permdesc_pkgUsageStats">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Trykk to ganger for zoomkontroll"</string>
+ <string name="gadget_host_error_inflating">"Feil under oppakking av gadget"</string>
+ <string name="ime_action_go">"Gå"</string>
+ <string name="ime_action_search">"Søk"</string>
+ <string name="ime_action_send">"Send"</string>
+ <string name="ime_action_next">"Neste"</string>
+ <string name="ime_action_done">"Utført"</string>
+ <string name="ime_action_default">"Utfør"</string>
+ <!-- no translation found for dial_number_using (5789176425167573586) -->
+ <skip />
+ <!-- no translation found for create_contact_using (4947405226788104538) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 00b03d8..2bbd02d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<zonder titel>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen telefoonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Onbekend)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Verbindingsprobleem of ongeldige MMI-code."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Service is ingeschakeld."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Service is ingeschakeld voor:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Service is uitgeschakeld."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"De registratie is voltooid."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Wissen uitgevoerd."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Onjuist wachtwoord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI voltooid."</string>
- <string name="badPin" msgid="5085454289896032547">"De oude PIN-code die u heeft ingevoerd, is onjuist."</string>
- <string name="badPuk" msgid="5702522162746042460">"De PUK-code die u heeft ingevoerd, is onjuist."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"De PIN-codes die u heeft ingevoerd, komen niet overeen."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Voer een PIN-code van 4 tot 8 cijfers in."</string>
- <string name="needPuk" msgid="919668385956251611">"Uw SIM-kaart is vergrendeld met de PUK-code. Typ de PUK-code om te ontgrendelen."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Inkomende beller-id"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Uitgaande beller-id"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Oproep doorschakelen"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Wisselgesprek"</string>
- <string name="BaMmi" msgid="455193067926770581">"Oproep blokkeren"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Wachtwoordwijziging"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-wijziging"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Nummer van beller beschikbaar"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Nummer van beller beperkt"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Driewegs bellen"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Ongewenste, vervelende oproepen weigeren"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Weergave van nummer van beller"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Niet storen"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: beperkt."</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: onbeperkt."</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: beperkt."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service niet voorzien."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"De instelling voor beller-id kan niet worden gewijzigd."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang gewijzigd"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Gegevensservice is geblokkeerd."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Alarmservice is geblokkeerd."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Spraak-/SMS-service is geblokkeerd."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle spraak-/SMS-services zijn geblokkeerd."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Spraak"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Gegevens"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchroon"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchroniseren"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roamingaanduiding aan"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roamingaanduiding uit"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roamingaanduiding knippert"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Uit de buurt"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Buiten het gebouw"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Voorkeurssysteem"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Beschikbaar systeem"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Alliance-partner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Premium-partner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Volledige servicefunctionaliteit"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Gedeeltelijke servicefunctionaliteit"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roamingbanner aan"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roamingbanner uit"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Service zoeken"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Functiecode voltooid."</string>
- <string name="fcError" msgid="3327560126588500777">"Verbindingsprobleem of ongeldige functiecode."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"De webpagina bevat een fout."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"De URL kan niet worden gevonden."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Het schema voor de siteverificatie wordt niet ondersteund."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Verificatie mislukt."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Verificatie via de proxyserver is mislukt."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Er kan geen verbinding met de server worden gemaakt."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"De server kan niet communiceren. Probeer het later opnieuw."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Er is een time-out voor de serververbinding opgetreden."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"De pagina bevat te veel serveromleidingen."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Het protocol wordt niet ondersteund."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Er kan geen beveiligde verbinding tot stand worden gebracht."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"De pagina kan niet worden geopend, omdat de URL ongeldig is."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Het bestand kan niet worden geopend."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Het opgevraagde bestand is niet gevonden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Er worden te veel aanvragen verwerkt. Probeer het later opnieuw."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchroniseren"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniseren"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefoongeheugen is vol! Verwijder enkele bestanden om ruimte vrij te maken."</string>
- <string name="me" msgid="6545696007631404292">"Ik"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefoonopties"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Stille modus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Draadloos inschakelen"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Draadloos uitschakelen"</string>
- <string name="screen_lock" msgid="799094655496098153">"Schermvergrendeling"</string>
- <string name="power_off" msgid="4266614107412865048">"Uitschakelen"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Uitschakelen..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Uw telefoon wordt uitgeschakeld."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Geen recente toepassingen."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefoonopties"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
- <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services waarvoor u moet betalen"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Toepassingen toestaan activiteiten uit te voeren waarvoor mogelijk kosten in rekening worden gebracht."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Uw berichten"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS, e-mail en andere berichten lezen en schrijven."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Uw persoonlijke informatie"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contacten en agenda."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Uw locatie"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Uw fysieke locatie bijhouden"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netwerkcommunicatie"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Toepassingen toestaan verschillende netwerkfuncties te openen."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Uw Google-accounts"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Toegang tot de beschikbare Google-accounts."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Bedieningselementen hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Rechtstreekse toegang tot hardware op de handset."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefoonoproepen"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Oproepen bijhouden, registreren en verwerken."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systeemhulpprogramma\'s"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Toegang tot en beheer van het systeem op lager niveau."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ontwikkelingshulpprogramma\'s"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Functies die alleen door toepassingsontwikkelaars worden gebruikt."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Opslagruimte"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Toegang tot de SD-kaart."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"statusbalk uitvouwen/samenvouwen"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"uitgaande oproepen onderscheppen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS ontvangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS ontvangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS-berichten verzenden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS of MMS lezen"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS of MMS bewerken"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP ontvangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"actieve toepassingen ophalen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"actieve toepassingen opnieuw indelen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"foutopsporing in toepassingen inschakelen"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"andere toepassingen opnieuw starten"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Hiermee kan een toepassing andere toepassingen opnieuw starten."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"toepassing nu sluiten"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"interne systeemstatus ophalen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen toepassingen voorkomen"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"alle startende toepassingen bijhouden en beheren"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"melding over ontvangen SMS-bericht verzenden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle achtergrondtoepassingen sluiten"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"accustatistieken aanpassen"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_backup" msgid="470013022865453920">"systeemback-up en -herstel beheren"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"niet-geautoriseerde vensters weergeven"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"waarschuwingen op systeemniveau weergeven"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"algemene animatiesnelheid wijzigen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"toepassingstokens beheren"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"drukken op toetsen en bedieningselementen"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"uw invoer en acties vastleggen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"verbinden aan een invoermethode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"toepassing altijd laten uitvoeren"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"toepassingen verwijderen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"gegevens van andere toepassingen verwijderen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"caches van andere toepassingen verwijderen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van toepassing bepalen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"toepassingen rechtstreeks installeren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van toepassing verwijderen"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"systeemlogbestanden lezen"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"voorkeurstoepassingen instellen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"algemene systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"beveiligde systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"de Google-serviceskaart wijzigen"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatisch starten bij opstarten"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sticky broadcast verzenden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"contactgegevens lezen"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"contactgegevens schrijven"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"gegevens eigenaar schrijven"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar wijzigen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar verwijderen of wijzigen."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"gegevens eigenaar lezen"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar lezen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar lezen."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"agendagegevens lezen"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"agendagegevens schrijven"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Hiermee kan een toepassing de op uw telefoon opgeslagen agendagebeurtenissen wijzigen. Schadelijke toepassingen kunnen hiermee uw agendagegevens verwijderen of wijzigen."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"neplocatiebronnen voor test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang opdrachten aanbieder extra locaties"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Toegang tot opdrachten aanbieder extra locaties. Schadelijke toepassingen kunnen hiervan gebruik maken om de werking van GPS of andere locatiebronnen te verstoren."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"toestemming om een locatieprovider te installeren"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen, zoals GPS of netwerkaanbieders, wordt aangegeven of om uw locatie bij te houden en te rapporteren aan externe bronnen."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"nauwkeurige (GPS) locatie"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Toegang tot exacte locatiebronnen, zoals het Global Positioning System op de telefoon, indien beschikbaar. Schadelijke toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en mogelijk extra acculading verbruiken."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"globale (netwerkgebaseerde) locatie"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"toegang tot SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"uw audio-instellingen wijzigen"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"audio opnemen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"foto\'s maken"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Hiermee kan een toepassing foto\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment foto\'s verzamelen van wat de camera ziet."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"telefoon nu opnieuw opstarten"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"bestandssystemen koppelen en ontkoppelen"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"externe opslag formatteren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de toepassing de externe opslag formatteren."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"trilstand beheren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de toepassing de trilstand beheren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de toepassing de zaklamp bedienen."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"alle telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"meldingen over locatie-updates beheren"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"toegang tot checkin-eigenschappen"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"widgets kiezen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefoonstatus wijzigen"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"uitvoeren in fabriekstestmodus"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"achtergrond instellen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"grootte achtergrond instellen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"systeem terugzetten op fabrieksinstellingen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"tijdzone instellen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bekende accounts zoeken"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"netwerkstatus bekijken"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"volledige internettoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een toepassing netwerksockets maken."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"instellingen voor toegangspuntnaam schrijven"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"netwerkverbinding wijzigen"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Hiermee kan een toepassing de verbindingsstatus van het netwerk wijzigen."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi-status bekijken"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi-status wijzigen"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi Multicast-ontvangst toestaan"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-beheer"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-verbindingen maken"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"toetsvergrendeling uitschakelen"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"synchronisatie-instellingen schrijven"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"geabonneerde feeds lezen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"geabonneerde feeds schrijven"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"door gebruiker gedefinieerd woordenboek lezen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<zonder titel>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Geen telefoonnummer)"</string>
+ <string name="unknownName">"(Onbekend)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Verbindingsprobleem of ongeldige MMI-code."</string>
+ <string name="serviceEnabled">"Service is ingeschakeld."</string>
+ <string name="serviceEnabledFor">"Service is ingeschakeld voor:"</string>
+ <string name="serviceDisabled">"Service is uitgeschakeld."</string>
+ <string name="serviceRegistered">"De registratie is voltooid."</string>
+ <string name="serviceErased">"Wissen uitgevoerd."</string>
+ <string name="passwordIncorrect">"Onjuist wachtwoord."</string>
+ <string name="mmiComplete">"MMI voltooid."</string>
+ <string name="badPin">"De oude PIN-code die u heeft ingevoerd, is onjuist."</string>
+ <string name="badPuk">"De PUK-code die u heeft ingevoerd, is onjuist."</string>
+ <string name="mismatchPin">"De PIN-codes die u heeft ingevoerd, komen niet overeen."</string>
+ <string name="invalidPin">"Voer een PIN-code van 4 tot 8 cijfers in."</string>
+ <string name="needPuk">"Uw SIM-kaart is vergrendeld met de PUK-code. Typ de PUK-code om te ontgrendelen."</string>
+ <string name="needPuk2">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
+ <string name="ClipMmi">"Inkomende beller-id"</string>
+ <string name="ClirMmi">"Uitgaande beller-id"</string>
+ <string name="CfMmi">"Oproep doorschakelen"</string>
+ <string name="CwMmi">"Wisselgesprek"</string>
+ <string name="BaMmi">"Oproep blokkeren"</string>
+ <string name="PwdMmi">"Wachtwoordwijziging"</string>
+ <string name="PinMmi">"PIN-wijziging"</string>
+ <string name="CnipMmi">"Nummer van beller beschikbaar"</string>
+ <string name="CnirMmi">"Nummer van beller beperkt"</string>
+ <string name="ThreeWCMmi">"Driewegs bellen"</string>
+ <string name="RuacMmi">"Ongewenste, vervelende oproepen weigeren"</string>
+ <string name="CndMmi">"Weergave van nummer van beller"</string>
+ <string name="DndMmi">"Niet storen"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: beperkt."</string>
+ <string name="CLIRDefaultOnNextCallOff">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: onbeperkt."</string>
+ <string name="CLIRDefaultOffNextCallOn">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: beperkt."</string>
+ <string name="CLIRDefaultOffNextCallOff">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
+ <string name="serviceNotProvisioned">"Service niet voorzien."</string>
+ <string name="CLIRPermanent">"De instelling voor beller-id kan niet worden gewijzigd."</string>
+ <string name="RestrictedChangedTitle">"Beperkte toegang gewijzigd"</string>
+ <string name="RestrictedOnData">"Gegevensservice is geblokkeerd."</string>
+ <string name="RestrictedOnEmergency">"Alarmservice is geblokkeerd."</string>
+ <string name="RestrictedOnNormal">"Spraak-/SMS-service is geblokkeerd."</string>
+ <string name="RestrictedOnAll">"Alle spraak-/SMS-services zijn geblokkeerd."</string>
+ <string name="serviceClassVoice">"Spraak"</string>
+ <string name="serviceClassData">"Gegevens"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchroon"</string>
+ <string name="serviceClassDataSync">"Synchroniseren"</string>
+ <string name="serviceClassPacket">"Pakket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Roamingaanduiding aan"</string>
+ <string name="roamingText1">"Roamingaanduiding uit"</string>
+ <string name="roamingText2">"Roamingaanduiding knippert"</string>
+ <string name="roamingText3">"Uit de buurt"</string>
+ <string name="roamingText4">"Buiten het gebouw"</string>
+ <string name="roamingText5">"Roaming - Voorkeurssysteem"</string>
+ <string name="roamingText6">"Roaming - Beschikbaar systeem"</string>
+ <string name="roamingText7">"Roaming - Alliance-partner"</string>
+ <string name="roamingText8">"Roaming - Premium-partner"</string>
+ <string name="roamingText9">"Roaming - Volledige servicefunctionaliteit"</string>
+ <string name="roamingText10">"Roaming - Gedeeltelijke servicefunctionaliteit"</string>
+ <string name="roamingText11">"Roamingbanner aan"</string>
+ <string name="roamingText12">"Roamingbanner uit"</string>
+ <string name="roamingTextSearching">"Service zoeken"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="fcComplete">"Functiecode voltooid."</string>
+ <string name="fcError">"Verbindingsprobleem of ongeldige functiecode."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"De webpagina bevat een fout."</string>
+ <string name="httpErrorLookup">"De URL kan niet worden gevonden."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Het schema voor de siteverificatie wordt niet ondersteund."</string>
+ <string name="httpErrorAuth">"Verificatie mislukt."</string>
+ <string name="httpErrorProxyAuth">"Verificatie via de proxyserver is mislukt."</string>
+ <string name="httpErrorConnect">"Er kan geen verbinding met de server worden gemaakt."</string>
+ <string name="httpErrorIO">"De server kan niet communiceren. Probeer het later opnieuw."</string>
+ <string name="httpErrorTimeout">"Er is een time-out voor de serververbinding opgetreden."</string>
+ <string name="httpErrorRedirectLoop">"De pagina bevat te veel serveromleidingen."</string>
+ <string name="httpErrorUnsupportedScheme">"Het protocol wordt niet ondersteund."</string>
+ <string name="httpErrorFailedSslHandshake">"Er kan geen beveiligde verbinding tot stand worden gebracht."</string>
+ <string name="httpErrorBadUrl">"De pagina kan niet worden geopend, omdat de URL ongeldig is."</string>
+ <string name="httpErrorFile">"Het bestand kan niet worden geopend."</string>
+ <string name="httpErrorFileNotFound">"Het opgevraagde bestand is niet gevonden."</string>
+ <string name="httpErrorTooManyRequests">"Er worden te veel aanvragen verwerkt. Probeer het later opnieuw."</string>
+ <string name="contentServiceSync">"Synchroniseren"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchroniseren"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Telefoongeheugen is vol! Verwijder enkele bestanden om ruimte vrij te maken."</string>
+ <string name="me">"Ik"</string>
+ <string name="power_dialog">"Telefoonopties"</string>
+ <string name="silent_mode">"Stille modus"</string>
+ <string name="turn_on_radio">"Draadloos inschakelen"</string>
+ <string name="turn_off_radio">"Draadloos uitschakelen"</string>
+ <string name="screen_lock">"Schermvergrendeling"</string>
+ <string name="power_off">"Uitschakelen"</string>
+ <string name="shutdown_progress">"Uitschakelen..."</string>
+ <string name="shutdown_confirm">"Uw telefoon wordt uitgeschakeld."</string>
+ <string name="no_recent_tasks">"Geen recente toepassingen."</string>
+ <string name="global_actions">"Telefoonopties"</string>
+ <string name="global_action_lock">"Schermvergrendeling"</string>
+ <string name="global_action_power_off">"Uitschakelen"</string>
+ <string name="global_action_toggle_silent_mode">"Stille modus"</string>
+ <string name="global_action_silent_mode_on_status">"Geluid is UIT"</string>
+ <string name="global_action_silent_mode_off_status">"Geluid is AAN"</string>
+ <string name="global_actions_toggle_airplane_mode">"Vliegmodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Vliegmodus is AAN"</string>
+ <string name="global_actions_airplane_mode_off_status">"Vliegmodus is UIT"</string>
+ <string name="safeMode">"Veilige modus"</string>
+ <string name="android_system_label">"Android-systeem"</string>
+ <string name="permgrouplab_costMoney">"Services waarvoor u moet betalen"</string>
+ <string name="permgroupdesc_costMoney">"Toepassingen toestaan activiteiten uit te voeren waarvoor mogelijk kosten in rekening worden gebracht."</string>
+ <string name="permgrouplab_messages">"Uw berichten"</string>
+ <string name="permgroupdesc_messages">"SMS, e-mail en andere berichten lezen en schrijven."</string>
+ <string name="permgrouplab_personalInfo">"Uw persoonlijke informatie"</string>
+ <string name="permgroupdesc_personalInfo">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contacten en agenda."</string>
+ <string name="permgrouplab_location">"Uw locatie"</string>
+ <string name="permgroupdesc_location">"Uw fysieke locatie bijhouden"</string>
+ <string name="permgrouplab_network">"Netwerkcommunicatie"</string>
+ <string name="permgroupdesc_network">"Toepassingen toestaan verschillende netwerkfuncties te openen."</string>
+ <string name="permgrouplab_accounts">"Uw Google-accounts"</string>
+ <string name="permgroupdesc_accounts">"Toegang tot de beschikbare Google-accounts."</string>
+ <string name="permgrouplab_hardwareControls">"Bedieningselementen hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Rechtstreekse toegang tot hardware op de handset."</string>
+ <string name="permgrouplab_phoneCalls">"Telefoonoproepen"</string>
+ <string name="permgroupdesc_phoneCalls">"Oproepen bijhouden, registreren en verwerken."</string>
+ <string name="permgrouplab_systemTools">"Systeemhulpprogramma\'s"</string>
+ <string name="permgroupdesc_systemTools">"Toegang tot en beheer van het systeem op lager niveau."</string>
+ <string name="permgrouplab_developmentTools">"Ontwikkelingshulpprogramma\'s"</string>
+ <string name="permgroupdesc_developmentTools">"Functies die alleen door toepassingsontwikkelaars worden gebruikt."</string>
+ <string name="permgrouplab_storage">"Opslagruimte"</string>
+ <string name="permgroupdesc_storage">"Toegang tot de SD-kaart."</string>
+ <string name="permlab_statusBar">"statusbalk uitschakelen of wijzigen"</string>
+ <string name="permdesc_statusBar">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
+ <string name="permlab_expandStatusBar">"statusbalk uitvouwen/samenvouwen"</string>
+ <string name="permdesc_expandStatusBar">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
+ <string name="permlab_processOutgoingCalls">"uitgaande oproepen onderscheppen"</string>
+ <string name="permdesc_processOutgoingCalls">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
+ <string name="permlab_receiveSms">"SMS ontvangen"</string>
+ <string name="permdesc_receiveSms">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_receiveMms">"MMS ontvangen"</string>
+ <string name="permdesc_receiveMms">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_sendSms">"SMS-berichten verzenden"</string>
+ <string name="permdesc_sendSms">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
+ <string name="permlab_readSms">"SMS of MMS lezen"</string>
+ <string name="permdesc_readSms">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
+ <string name="permlab_writeSms">"SMS of MMS bewerken"</string>
+ <string name="permdesc_writeSms">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
+ <string name="permlab_receiveWapPush">"WAP ontvangen"</string>
+ <string name="permdesc_receiveWapPush">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_getTasks">"actieve toepassingen ophalen"</string>
+ <string name="permdesc_getTasks">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
+ <string name="permlab_reorderTasks">"actieve toepassingen opnieuw indelen"</string>
+ <string name="permdesc_reorderTasks">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
+ <string name="permlab_setDebugApp">"foutopsporing in toepassingen inschakelen"</string>
+ <string name="permdesc_setDebugApp">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
+ <string name="permlab_changeConfiguration">"uw UI-instellingen wijzigen"</string>
+ <string name="permdesc_changeConfiguration">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
+ <string name="permlab_restartPackages">"andere toepassingen opnieuw starten"</string>
+ <string name="permdesc_restartPackages">"Hiermee kan een toepassing andere toepassingen opnieuw starten."</string>
+ <string name="permlab_forceBack">"toepassing nu sluiten"</string>
+ <string name="permdesc_forceBack">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_dump">"interne systeemstatus ophalen"</string>
+ <string name="permdesc_dump">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
+ <string name="permlab_shutdown">"gedeeltelijke uitschakeling"</string>
+ <string name="permdesc_shutdown">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
+ <string name="permlab_stopAppSwitches">"schakelen tussen toepassingen voorkomen"</string>
+ <string name="permdesc_stopAppSwitches">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
+ <string name="permlab_runSetActivityWatcher">"alle startende toepassingen bijhouden en beheren"</string>
+ <string name="permdesc_runSetActivityWatcher">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
+ <string name="permlab_broadcastPackageRemoved">"melding verzenden dat pakket is verwijderd"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
+ <string name="permlab_broadcastSmsReceived">"melding over ontvangen SMS-bericht verzenden"</string>
+ <string name="permdesc_broadcastSmsReceived">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
+ <string name="permlab_broadcastWapPush">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
+ <string name="permdesc_broadcastWapPush">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
+ <string name="permlab_setProcessLimit">"aantal actieve processen beperken"</string>
+ <string name="permdesc_setProcessLimit">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_setAlwaysFinish">"alle achtergrondtoepassingen sluiten"</string>
+ <string name="permdesc_setAlwaysFinish">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
+ <string name="permlab_batteryStats">"accustatistieken aanpassen"</string>
+ <string name="permdesc_batteryStats">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_backup">"systeemback-up en -herstel beheren"</string>
+ <string name="permdesc_backup">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_internalSystemWindow">"niet-geautoriseerde vensters weergeven"</string>
+ <string name="permdesc_internalSystemWindow">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_systemAlertWindow">"waarschuwingen op systeemniveau weergeven"</string>
+ <string name="permdesc_systemAlertWindow">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
+ <string name="permlab_setAnimationScale">"algemene animatiesnelheid wijzigen"</string>
+ <string name="permdesc_setAnimationScale">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
+ <string name="permlab_manageAppTokens">"toepassingstokens beheren"</string>
+ <string name="permdesc_manageAppTokens">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
+ <string name="permlab_injectEvents">"drukken op toetsen en bedieningselementen"</string>
+ <string name="permdesc_injectEvents">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
+ <string name="permlab_readInputState">"uw invoer en acties vastleggen"</string>
+ <string name="permdesc_readInputState">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_bindInputMethod">"verbinden aan een invoermethode"</string>
+ <string name="permdesc_bindInputMethod">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_setOrientation">"schermstand wijzigen"</string>
+ <string name="permdesc_setOrientation">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_signalPersistentProcesses">"Linux-signalen verzenden naar toepassingen"</string>
+ <string name="permdesc_signalPersistentProcesses">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
+ <string name="permlab_persistentActivity">"toepassing altijd laten uitvoeren"</string>
+ <string name="permdesc_persistentActivity">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
+ <string name="permlab_deletePackages">"toepassingen verwijderen"</string>
+ <string name="permdesc_deletePackages">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
+ <string name="permlab_clearAppUserData">"gegevens van andere toepassingen verwijderen"</string>
+ <string name="permdesc_clearAppUserData">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
+ <string name="permlab_deleteCacheFiles">"caches van andere toepassingen verwijderen"</string>
+ <string name="permdesc_deleteCacheFiles">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
+ <string name="permlab_getPackageSize">"opslagruimte van toepassing bepalen"</string>
+ <string name="permdesc_getPackageSize">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
+ <string name="permlab_installPackages">"toepassingen rechtstreeks installeren"</string>
+ <string name="permdesc_installPackages">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
+ <string name="permlab_clearAppCache">"alle cachegegevens van toepassing verwijderen"</string>
+ <string name="permdesc_clearAppCache">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
+ <string name="permlab_readLogs">"systeemlogbestanden lezen"</string>
+ <string name="permdesc_readLogs">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string>
+ <string name="permlab_diagnostic">"lezen/schrijven naar bronnen van diag"</string>
+ <string name="permdesc_diagnostic">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
+ <string name="permlab_changeComponentState">"toepassingscomponenten in- of uitschakelen"</string>
+ <string name="permdesc_changeComponentState">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
+ <string name="permlab_setPreferredApplications">"voorkeurstoepassingen instellen"</string>
+ <string name="permdesc_setPreferredApplications">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
+ <string name="permlab_writeSettings">"algemene systeeminstellingen wijzigen"</string>
+ <string name="permdesc_writeSettings">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
+ <string name="permlab_writeSecureSettings">"beveiligde systeeminstellingen wijzigen"</string>
+ <string name="permdesc_writeSecureSettings">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_writeGservices">"de Google-serviceskaart wijzigen"</string>
+ <string name="permdesc_writeGservices">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_receiveBootCompleted">"automatisch starten bij opstarten"</string>
+ <string name="permdesc_receiveBootCompleted">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
+ <string name="permlab_broadcastSticky">"sticky broadcast verzenden"</string>
+ <string name="permdesc_broadcastSticky">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
+ <string name="permlab_readContacts">"contactgegevens lezen"</string>
+ <string name="permdesc_readContacts">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
+ <string name="permlab_writeContacts">"contactgegevens schrijven"</string>
+ <string name="permdesc_writeContacts">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
+ <string name="permlab_writeOwnerData">"gegevens eigenaar schrijven"</string>
+ <string name="permdesc_writeOwnerData">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar wijzigen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar verwijderen of wijzigen."</string>
+ <string name="permlab_readOwnerData">"gegevens eigenaar lezen"</string>
+ <string name="permdesc_readOwnerData">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar lezen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar lezen."</string>
+ <string name="permlab_readCalendar">"agendagegevens lezen"</string>
+ <string name="permdesc_readCalendar">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
+ <string name="permlab_writeCalendar">"agendagegevens schrijven"</string>
+ <string name="permdesc_writeCalendar">"Hiermee kan een toepassing de op uw telefoon opgeslagen agendagebeurtenissen wijzigen. Schadelijke toepassingen kunnen hiermee uw agendagegevens verwijderen of wijzigen."</string>
+ <string name="permlab_accessMockLocation">"neplocatiebronnen voor test"</string>
+ <string name="permdesc_accessMockLocation">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
+ <string name="permlab_accessLocationExtraCommands">"toegang opdrachten aanbieder extra locaties"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Toegang tot opdrachten aanbieder extra locaties. Schadelijke toepassingen kunnen hiervan gebruik maken om de werking van GPS of andere locatiebronnen te verstoren."</string>
+ <string name="permlab_installLocationProvider">"toestemming om een locatieprovider te installeren"</string>
+ <string name="permdesc_installLocationProvider">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen, zoals GPS of netwerkaanbieders, wordt aangegeven of om uw locatie bij te houden en te rapporteren aan externe bronnen."</string>
+ <string name="permlab_accessFineLocation">"nauwkeurige (GPS) locatie"</string>
+ <string name="permdesc_accessFineLocation">"Toegang tot exacte locatiebronnen, zoals het Global Positioning System op de telefoon, indien beschikbaar. Schadelijke toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en mogelijk extra acculading verbruiken."</string>
+ <string name="permlab_accessCoarseLocation">"globale (netwerkgebaseerde) locatie"</string>
+ <string name="permdesc_accessCoarseLocation">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
+ <string name="permlab_accessSurfaceFlinger">"toegang tot SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
+ <string name="permlab_readFrameBuffer">"framebuffer lezen"</string>
+ <string name="permdesc_readFrameBuffer">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
+ <string name="permlab_modifyAudioSettings">"uw audio-instellingen wijzigen"</string>
+ <string name="permdesc_modifyAudioSettings">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
+ <string name="permlab_recordAudio">"audio opnemen"</string>
+ <string name="permdesc_recordAudio">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
+ <string name="permlab_camera">"foto\'s maken"</string>
+ <string name="permdesc_camera">"Hiermee kan een toepassing foto\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment foto\'s verzamelen van wat de camera ziet."</string>
+ <string name="permlab_brick">"telefoon permanent uitschakelen"</string>
+ <string name="permdesc_brick">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
+ <string name="permlab_reboot">"telefoon nu opnieuw opstarten"</string>
+ <string name="permdesc_reboot">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
+ <string name="permlab_mount_unmount_filesystems">"bestandssystemen koppelen en ontkoppelen"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
+ <string name="permlab_mount_format_filesystems">"externe opslag formatteren"</string>
+ <string name="permdesc_mount_format_filesystems">"Hiermee kan de toepassing de externe opslag formatteren."</string>
+ <string name="permlab_vibrate">"trilstand beheren"</string>
+ <string name="permdesc_vibrate">"Hiermee kan de toepassing de trilstand beheren."</string>
+ <string name="permlab_flashlight">"zaklamp bedienen"</string>
+ <string name="permdesc_flashlight">"Hiermee kan de toepassing de zaklamp bedienen."</string>
+ <string name="permlab_hardware_test">"hardware testen"</string>
+ <string name="permdesc_hardware_test">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
+ <string name="permlab_callPhone">"telefoonnummers rechtstreeks bellen"</string>
+ <string name="permdesc_callPhone">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
+ <string name="permlab_callPrivileged">"alle telefoonnummers rechtstreeks bellen"</string>
+ <string name="permdesc_callPrivileged">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
+ <string name="permlab_locationUpdates">"meldingen over locatie-updates beheren"</string>
+ <string name="permdesc_locationUpdates">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_checkinProperties">"toegang tot checkin-eigenschappen"</string>
+ <string name="permdesc_checkinProperties">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_bindGadget">"widgets kiezen"</string>
+ <string name="permdesc_bindGadget">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_modifyPhoneState">"telefoonstatus wijzigen"</string>
+ <string name="permdesc_modifyPhoneState">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
+ <string name="permlab_readPhoneState">"telefoonstatus lezen"</string>
+ <string name="permdesc_readPhoneState">"Hiermee krijgt de toepassing toegang tot de telefoonfuncties van het apparaat. Een toepassing met de betreffende machtiging kan het telefoonnummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
+ <string name="permlab_wakeLock">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
+ <string name="permdesc_wakeLock">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permlab_devicePower">"telefoon in- of uitschakelen"</string>
+ <string name="permdesc_devicePower">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
+ <string name="permlab_factoryTest">"uitvoeren in fabriekstestmodus"</string>
+ <string name="permdesc_factoryTest">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
+ <string name="permlab_setWallpaper">"achtergrond instellen"</string>
+ <string name="permdesc_setWallpaper">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
+ <string name="permlab_setWallpaperHints">"grootte achtergrond instellen"</string>
+ <string name="permdesc_setWallpaperHints">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
+ <string name="permlab_masterClear">"systeem terugzetten op fabrieksinstellingen"</string>
+ <string name="permdesc_masterClear">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
+ <string name="permlab_setTimeZone">"tijdzone instellen"</string>
+ <string name="permdesc_setTimeZone">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
+ <string name="permlab_getAccounts">"bekende accounts zoeken"</string>
+ <string name="permdesc_getAccounts">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
+ <string name="permlab_accessNetworkState">"netwerkstatus bekijken"</string>
+ <string name="permdesc_accessNetworkState">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
+ <string name="permlab_createNetworkSockets">"volledige internettoegang"</string>
+ <string name="permdesc_createNetworkSockets">"Hiermee kan een toepassing netwerksockets maken."</string>
+ <string name="permlab_writeApnSettings">"instellingen voor toegangspuntnaam schrijven"</string>
+ <string name="permdesc_writeApnSettings">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
+ <string name="permlab_changeNetworkState">"netwerkverbinding wijzigen"</string>
+ <string name="permdesc_changeNetworkState">"Hiermee kan een toepassing de verbindingsstatus van het netwerk wijzigen."</string>
+ <string name="permlab_changeBackgroundDataSetting">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
+ <string name="permlab_accessWifiState">"Wi-Fi-status bekijken"</string>
+ <string name="permdesc_accessWifiState">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
+ <string name="permlab_changeWifiState">"Wi-Fi-status wijzigen"</string>
+ <string name="permdesc_changeWifiState">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
+ <string name="permlab_changeWifiMulticastState">"Wi-Fi Multicast-ontvangst toestaan"</string>
+ <string name="permdesc_changeWifiMulticastState">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth-beheer"</string>
+ <string name="permdesc_bluetoothAdmin">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
+ <string name="permlab_bluetooth">"Bluetooth-verbindingen maken"</string>
+ <string name="permdesc_bluetooth">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
+ <string name="permlab_disableKeyguard">"toetsvergrendeling uitschakelen"</string>
+ <string name="permdesc_disableKeyguard">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
+ <string name="permlab_readSyncSettings">"synchronisatie-instellingen lezen"</string>
+ <string name="permdesc_readSyncSettings">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permlab_writeSyncSettings">"synchronisatie-instellingen schrijven"</string>
+ <string name="permdesc_writeSyncSettings">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permlab_readSyncStats">"synchronisatiestatistieken lezen"</string>
+ <string name="permdesc_readSyncStats">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
+ <string name="permlab_subscribedFeedsRead">"geabonneerde feeds lezen"</string>
+ <string name="permdesc_subscribedFeedsRead">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
+ <string name="permlab_subscribedFeedsWrite">"geabonneerde feeds schrijven"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
+ <string name="permlab_readDictionary">"door gebruiker gedefinieerd woordenboek lezen"</string>
+ <string name="permdesc_readDictionary">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
+ <string name="permlab_writeDictionary">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
+ <string name="permdesc_writeDictionary">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
+ <string name="permlab_sdcardWrite">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
+ <string name="permdesc_sdcardWrite">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Thuis"</item>
- <item msgid="869923650527136615">"Mobiel"</item>
- <item msgid="7897544654242874543">"Werk"</item>
- <item msgid="1103601433382158155">"Fax werk"</item>
- <item msgid="1735177144948329370">"Fax thuis"</item>
- <item msgid="603878674477207394">"Semafoon"</item>
- <item msgid="1650824275177931637">"Overig"</item>
- <item msgid="9192514806975898961">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Mobiel"</item>
+ <item>"Werk"</item>
+ <item>"Fax werk"</item>
+ <item>"Fax thuis"</item>
+ <item>"Semafoon"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Thuis"</item>
- <item msgid="7084237356602625604">"Werk"</item>
- <item msgid="1112044410659011023">"Overig"</item>
- <item msgid="2374913952870110618">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobiel"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Thuis"</item>
- <item msgid="5629153956045109251">"Werk"</item>
- <item msgid="4966604264500343469">"Overig"</item>
- <item msgid="4932682847595299369">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Thuis"</item>
- <item msgid="1359644565647383708">"Werk"</item>
- <item msgid="7868549401053615677">"Overig"</item>
- <item msgid="3145118944639869809">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Werk"</item>
- <item msgid="4378074129049520373">"Overig"</item>
- <item msgid="3455047468583965104">"Aangepast"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-code invoeren"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Onjuiste PIN-code!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Alarmnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Geen service)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Scherm vergrendeld."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Druk op \'Menu\' om te ontgrendelen."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Patroon tekenen om te ontgrendelen"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Noodoproep"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Juist!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Probeer het opnieuw"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Opladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Opgeladen."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Sluit de oplader aan."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Geen SIM-kaart."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Geen SIM-kaart in telefoon."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Plaats een SIM-kaart."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netwerk vergrendeld"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kaart is vergrendeld met PUK-code."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Raadpleeg de gebruikershandleiding of neem contact op met de klantenservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kaart is vergrendeld."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kaart ontgrendelen..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Patroon vergeten?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Te veel patroonpogingen!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Om te ontgrendelen, moet U zich eerst bij uw Google-account aanmelden"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Aanmelden"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Gebruikersnaam of wachtwoord ongeldig."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Opladen..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Sluit de oplader aan"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"De accu raakt op:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Waarom?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabriekstest mislukt"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Opnieuw opstarten"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' zegt:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies OK om door te gaan of Annuleren om op de huidige pagina te blijven."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"browsergeschiedenis en bladwijzers schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
- <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nooit"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"U heeft geen toestemming om deze pagina te openen."</string>
- <string name="text_copied" msgid="4985729524670131385">"Tekst naar klembord gekopieerd."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Meer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ruimte"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"invoeren"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"verwijderen"</string>
- <string name="search_go" msgid="8298016669822141719">"Zoeken"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN-code invoeren"</string>
+ <string name="keyguard_password_wrong_pin_code">"Onjuiste PIN-code!"</string>
+ <string name="keyguard_label_text">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
+ <string name="emergency_call_dialog_number_for_display">"Alarmnummer"</string>
+ <string name="lockscreen_carrier_default">"(Geen service)"</string>
+ <string name="lockscreen_screen_locked">"Scherm vergrendeld."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Druk op \'Menu\' om te ontgrendelen."</string>
+ <string name="lockscreen_pattern_instructions">"Patroon tekenen om te ontgrendelen"</string>
+ <string name="lockscreen_emergency_call">"Noodoproep"</string>
+ <string name="lockscreen_pattern_correct">"Juist!"</string>
+ <string name="lockscreen_pattern_wrong">"Probeer het opnieuw"</string>
+ <string name="lockscreen_plugged_in">"Opladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Sluit de oplader aan."</string>
+ <string name="lockscreen_missing_sim_message_short">"Geen SIM-kaart."</string>
+ <string name="lockscreen_missing_sim_message">"Geen SIM-kaart in telefoon."</string>
+ <string name="lockscreen_missing_sim_instructions">"Plaats een SIM-kaart."</string>
+ <string name="lockscreen_network_locked_message">"Netwerk vergrendeld"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kaart is vergrendeld met PUK-code."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Raadpleeg de gebruikershandleiding of neem contact op met de klantenservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kaart is vergrendeld."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-kaart ontgrendelen..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Patroon vergeten?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Te veel patroonpogingen!"</string>
+ <string name="lockscreen_glogin_instructions">"Om te ontgrendelen, moet U zich eerst bij uw Google-account aanmelden"</string>
+ <string name="lockscreen_glogin_username_hint">"Gebruikersnaam (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Wachtwoord"</string>
+ <string name="lockscreen_glogin_submit_button">"Aanmelden"</string>
+ <string name="lockscreen_glogin_invalid_input">"Gebruikersnaam of wachtwoord ongeldig."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Geen meldingen"</string>
+ <string name="status_bar_ongoing_events_title">"Actief"</string>
+ <string name="status_bar_latest_events_title">"Meldingen"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Opladen..."</string>
+ <string name="battery_low_title">"Sluit de oplader aan"</string>
+ <string name="battery_low_subtitle">"De accu raakt op:"</string>
+ <string name="battery_low_percent_format">"minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend."</string>
+ <string name="battery_low_why">"Waarom?"</string>
+ <string name="factorytest_failed">"Fabriekstest mislukt"</string>
+ <string name="factorytest_not_system">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
+ <string name="factorytest_no_action">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
+ <string name="factorytest_reboot">"Opnieuw opstarten"</string>
+ <string name="js_dialog_title">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' zegt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies OK om door te gaan of Annuleren om op de huidige pagina te blijven."</string>
+ <string name="save_password_label">"Bevestigen"</string>
+ <string name="permlab_readHistoryBookmarks">"browsergeschiedenis en bladwijzers lezen"</string>
+ <string name="permdesc_readHistoryBookmarks">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
+ <string name="permlab_writeHistoryBookmarks">"browsergeschiedenis en bladwijzers schrijven"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
+ <string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
+ <string name="save_password_notnow">"Niet nu"</string>
+ <string name="save_password_remember">"Onthouden"</string>
+ <string name="save_password_never">"Nooit"</string>
+ <string name="open_permission_deny">"U heeft geen toestemming om deze pagina te openen."</string>
+ <string name="text_copied">"Tekst naar klembord gekopieerd."</string>
+ <string name="more_item_label">"Meer"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"ruimte"</string>
+ <string name="menu_enter_shortcut_label">"invoeren"</string>
+ <string name="menu_delete_shortcut_label">"verwijderen"</string>
+ <string name="search_go">"Zoeken"</string>
+ <string name="oneMonthDurationPast">"1 maand geleden"</string>
+ <string name="beforeOneMonthDurationPast">"Meer dan 1 maand geleden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 seconde geleden"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
+ <item quantity="one">"1 seconde geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuut geleden"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
+ <item quantity="one">"1 minuut geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 uur geleden"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
+ <item quantity="one">"1 uur geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"gisteren"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
+ <item quantity="one">"gisteren"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"over 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ <item quantity="one">"over 1 seconde"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"over 1 minuut"</item>
- <item quantity="other" msgid="3330713936399448749">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ <item quantity="one">"over 1 minuut"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"over 1 uur"</item>
- <item quantity="other" msgid="547290677353727389">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ <item quantity="one">"over 1 uur"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seconde geleden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
+ <item quantity="one">"1 seconde geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuut geleden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
+ <item quantity="one">"1 minuut geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 uur geleden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
+ <item quantity="one">"1 uur geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"gisteren"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
+ <item quantity="one">"gisteren"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"over 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ <item quantity="one">"over 1 seconde"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"over 1 minuut"</item>
- <item quantity="other" msgid="4216113292706568726">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ <item quantity="one">"over 1 minuut"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"over 1 uur"</item>
- <item quantity="other" msgid="3705373766798013406">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ <item quantity="one">"over 1 uur"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"op %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"om %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"in %s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dagen"</string>
- <string name="hour" msgid="2126771916426189481">"uur"</string>
- <string name="hours" msgid="894424005266852993">"uren"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minuten"</string>
- <string name="second" msgid="3184235808021478">"sec"</string>
- <string name="seconds" msgid="3161515347216589235">"seconden"</string>
- <string name="week" msgid="5617961537173061583">"week"</string>
- <string name="weeks" msgid="6509623834583944518">"weken"</string>
- <string name="year" msgid="4001118221013892076">"jaar"</string>
- <string name="years" msgid="6881577717993213522">"jaren"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Elke weekdag (ma-vr)"</string>
- <string name="daily" msgid="5738949095624133403">"Dagelijks"</string>
- <string name="weekly" msgid="983428358394268344">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Maandelijks"</string>
- <string name="yearly" msgid="1519577999407493836">"Jaarlijks"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kan niet worden afgespeeld"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Deze video kan helaas niet worden gestreamd naar dit apparaat."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Deze video kan niet worden afgespeeld."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"twaalf uur \'s middags"</string>
- <string name="Noon" msgid="3342127745230013127">"Twaalf uur \'s middags"</string>
- <string name="midnight" msgid="7166259508850457595">"middernacht"</string>
- <string name="Midnight" msgid="5630806906897892201">"Middernacht"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string>
- <string name="selectText" msgid="3889149123626888637">"Tekst selecteren"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Stoppen met tekst selecteren"</string>
- <string name="cut" msgid="3092569408438626261">"Knippen"</string>
- <string name="cutAll" msgid="2436383270024931639">"Alles knippen"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiëren"</string>
- <string name="copyAll" msgid="2590829068100113057">"Alles kopiëren"</string>
- <string name="paste" msgid="5629880836805036433">"Plakken"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL kopiëren"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Invoermethode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"%s\' toevoegen aan woordenboek"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Tekst bewerken"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Weinig ruimte"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Opslagruimte van telefoon raakt op."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuleren"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Let op"</string>
- <string name="capital_on" msgid="1544682755514494298">"AAN"</string>
- <string name="capital_off" msgid="6815870386972805832">"UIT"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Actie voltooien met"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wis standaardinstelling via startscherm: \'Instellingen\' > \'Toepassingen\' > \'Toepassingen beheren\'."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Een actie selecteren"</string>
- <string name="noApplications" msgid="1691104391758345586">"Geen enkele toepassing kan deze actie uitvoeren."</string>
- <string name="aerr_title" msgid="653922989522758100">"Helaas!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
- <string name="anr_title" msgid="3100070910664756057">"Helaas!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
- <string name="force_close" msgid="3653416315450806396">"Nu sluiten"</string>
- <string name="report" msgid="4060218260984795706">"Rapport"</string>
- <string name="wait" msgid="7147118217226317732">"Wachten"</string>
- <string name="debug" msgid="9103374629678531849">"Foutopsporing"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecteer een actie voor tekst"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
- <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Afspelen via Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume inkomende oproep"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume tijdens gesprek in Bluetooth-modus"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmvolume"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Meldingsvolume"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Stil"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende beltoon"</string>
+ <string name="preposition_for_date">"op %s"</string>
+ <string name="preposition_for_time">"om %s"</string>
+ <string name="preposition_for_year">"in %s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dagen"</string>
+ <string name="hour">"uur"</string>
+ <string name="hours">"uren"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minuten"</string>
+ <string name="second">"sec"</string>
+ <string name="seconds">"seconden"</string>
+ <string name="week">"week"</string>
+ <string name="weeks">"weken"</string>
+ <string name="year">"jaar"</string>
+ <string name="years">"jaren"</string>
+ <string name="every_weekday">"Elke weekdag (ma-vr)"</string>
+ <string name="daily">"Dagelijks"</string>
+ <string name="weekly">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Maandelijks"</string>
+ <string name="yearly">"Jaarlijks"</string>
+ <string name="VideoView_error_title">"Video kan niet worden afgespeeld"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Deze video kan helaas niet worden gestreamd naar dit apparaat."</string>
+ <string name="VideoView_error_text_unknown">"Deze video kan niet worden afgespeeld."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"twaalf uur \'s middags"</string>
+ <string name="Noon">"Twaalf uur \'s middags"</string>
+ <string name="midnight">"middernacht"</string>
+ <string name="Midnight">"Middernacht"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Alles selecteren"</string>
+ <string name="selectText">"Tekst selecteren"</string>
+ <string name="stopSelectingText">"Stoppen met tekst selecteren"</string>
+ <string name="cut">"Knippen"</string>
+ <string name="cutAll">"Alles knippen"</string>
+ <string name="copy">"Kopiëren"</string>
+ <string name="copyAll">"Alles kopiëren"</string>
+ <string name="paste">"Plakken"</string>
+ <string name="copyUrl">"URL kopiëren"</string>
+ <string name="inputMethod">"Invoermethode"</string>
+ <string name="addToDictionary">"%s\' toevoegen aan woordenboek"</string>
+ <string name="editTextMenuTitle">"Tekst bewerken"</string>
+ <string name="low_internal_storage_view_title">"Weinig ruimte"</string>
+ <string name="low_internal_storage_view_text">"Opslagruimte van telefoon raakt op."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuleren"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuleren"</string>
+ <string name="dialog_alert_title">"Let op"</string>
+ <string name="capital_on">"AAN"</string>
+ <string name="capital_off">"UIT"</string>
+ <string name="whichApplication">"Actie voltooien met"</string>
+ <string name="alwaysUse">"Standaard gebruiken voor deze actie."</string>
+ <string name="clearDefaultHintMsg">"Wis standaardinstelling via startscherm: \'Instellingen\' > \'Toepassingen\' > \'Toepassingen beheren\'."</string>
+ <string name="chooseActivity">"Een actie selecteren"</string>
+ <string name="noApplications">"Geen enkele toepassing kan deze actie uitvoeren."</string>
+ <string name="aerr_title">"Helaas!"</string>
+ <string name="aerr_application">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="aerr_process">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="anr_title">"Helaas!"</string>
+ <string name="anr_activity_application">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_activity_process">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_application_process">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
+ <string name="force_close">"Nu sluiten"</string>
+ <string name="report">"Rapport"</string>
+ <string name="wait">"Wachten"</string>
+ <string name="debug">"Foutopsporing"</string>
+ <string name="sendText">"Selecteer een actie voor tekst"</string>
+ <string name="volume_ringtone">"Belvolume"</string>
+ <string name="volume_music">"Mediavolume"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Afspelen via Bluetooth"</string>
+ <string name="volume_call">"Volume inkomende oproep"</string>
+ <string name="volume_bluetooth_call">"Volume tijdens gesprek in Bluetooth-modus"</string>
+ <string name="volume_alarm">"Alarmvolume"</string>
+ <string name="volume_notification">"Meldingsvolume"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Standaardbeltoon"</string>
+ <string name="ringtone_default_with_actual">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Stil"</string>
+ <string name="ringtone_picker_title">"Beltonen"</string>
+ <string name="ringtone_unknown">"Onbekende beltoon"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netwerk beschikbaar"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi-netwerken beschikbaar"</item>
+ <item quantity="one">"Wi-Fi-netwerk beschikbaar"</item>
+ <item quantity="other">"Wi-Fi-netwerken beschikbaar"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Open Wi-Fi-netwerk beschikbaar"</item>
- <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
+ <item quantity="one">"Open Wi-Fi-netwerk beschikbaar"</item>
+ <item quantity="other">"Open Wi-Fi-netwerken beschikbaar"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende toepassing"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuleren"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Instellen"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standaard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Verbergen"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Alles weergeven"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Laden..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-verbinding"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer \'Koppelen\' als u bestanden tussen uw computer en de SD-kaart van uw telefoon wilt kopiëren."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Koppelen"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Niet koppelen"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-opslag."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-verbinding"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Selecteer dit om bestanden naar/van uw computer te kopiëren."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-opslag uitschakelen"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Selecteer dit om USB-opslag uit te schakelen."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB-opslag uitschakelen"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Voordat u de USB-opslag uitschakelt, moet u de koppeling met de USB-host verbreken. Selecteer \'Uitschakelen\' om USB-opslag uit te schakelen."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Uitschakelen"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuleren"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Er is een probleem opgetreden tijdens het uitschakelen van USB-opslag. Controleer of u de USB-host heeft losgekoppeld en probeer het opnieuw."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD-kaart formatteren"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Weet u zeker dat u de SD-kaart wilt formatteren? Alle gegevens op uw kaart gaan dan verloren."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatteren"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Uw telefoon heeft verbinding met een computer."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Invoermethode selecteren"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD-kaart voorbereiden"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Controleren op fouten."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Lege SD-kaart"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD-kaart is leeg of heeft een niet-ondersteund bestandssysteem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beschadigde SD-kaart"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SD-kaart beschadigd. U moet de kaart mogelijk opnieuw formatteren."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kaart onverwachts verwijderd"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Ontkoppel de SD-kaart voordat u deze verwijdert om gegevensverlies te voorkomen."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"De SD-kaart kan veilig worden verwijderd"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"U kunt de SD-kaart veilig verwijderen."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-kaart is verwijderd"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD-kaart verwijderd. Plaats een nieuwe."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Geen overeenkomende activiteiten gevonden"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"gebruiksstatistieken van component bijwerken"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Hiermee kunnen verzamelde gebruiksstatistieken van een component worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tik twee keer voor zoomregeling"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fout bij uitbreiden van widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ga"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Zoeken"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Verzenden"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Volgende"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Gereed"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Uitvoeren"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Nummer bellen"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Contact maken"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"aangevinkt"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"niet aangevinkt"</string>
+ <string name="select_character">"Teken invoegen"</string>
+ <string name="sms_control_default_app_name">"Onbekende toepassing"</string>
+ <string name="sms_control_title">"SMS-berichten verzenden"</string>
+ <string name="sms_control_message">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuleren"</string>
+ <string name="date_time_set">"Instellen"</string>
+ <string name="default_permission_group">"Standaard"</string>
+ <string name="no_permissions">"Geen machtigingen vereist"</string>
+ <string name="perms_hide"><b>"Verbergen"</b></string>
+ <string name="perms_show_all"><b>"Alles weergeven"</b></string>
+ <string name="googlewebcontenthelper_loading">"Laden..."</string>
+ <string name="usb_storage_title">"USB-verbinding"</string>
+ <string name="usb_storage_message">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer \'Koppelen\' als u bestanden tussen uw computer en de SD-kaart van uw telefoon wilt kopiëren."</string>
+ <string name="usb_storage_button_mount">"Koppelen"</string>
+ <string name="usb_storage_button_unmount">"Niet koppelen"</string>
+ <string name="usb_storage_error_message">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-opslag."</string>
+ <string name="usb_storage_notification_title">"USB-verbinding"</string>
+ <string name="usb_storage_notification_message">"Selecteer dit om bestanden naar/van uw computer te kopiëren."</string>
+ <string name="usb_storage_stop_notification_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_notification_message">"Selecteer dit om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_message">"Voordat u de USB-opslag uitschakelt, moet u de koppeling met de USB-host verbreken. Selecteer \'Uitschakelen\' om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_button_mount">"Uitschakelen"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuleren"</string>
+ <string name="usb_storage_stop_error_message">"Er is een probleem opgetreden tijdens het uitschakelen van USB-opslag. Controleer of u de USB-host heeft losgekoppeld en probeer het opnieuw."</string>
+ <string name="extmedia_format_title">"SD-kaart formatteren"</string>
+ <string name="extmedia_format_message">"Weet u zeker dat u de SD-kaart wilt formatteren? Alle gegevens op uw kaart gaan dan verloren."</string>
+ <string name="extmedia_format_button_format">"Formatteren"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Invoermethode selecteren"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-kaart voorbereiden"</string>
+ <string name="ext_media_checking_notification_message">"Controleren op fouten."</string>
+ <string name="ext_media_nofs_notification_title">"Lege SD-kaart"</string>
+ <string name="ext_media_nofs_notification_message">"SD-kaart is leeg of heeft een niet-ondersteund bestandssysteem."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschadigde SD-kaart"</string>
+ <string name="ext_media_unmountable_notification_message">"SD-kaart beschadigd. U moet de kaart mogelijk opnieuw formatteren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kaart onverwachts verwijderd"</string>
+ <string name="ext_media_badremoval_notification_message">"Ontkoppel de SD-kaart voordat u deze verwijdert om gegevensverlies te voorkomen."</string>
+ <string name="ext_media_safe_unmount_notification_title">"De SD-kaart kan veilig worden verwijderd"</string>
+ <string name="ext_media_safe_unmount_notification_message">"U kunt de SD-kaart veilig verwijderen."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-kaart is verwijderd"</string>
+ <string name="ext_media_nomedia_notification_message">"SD-kaart verwijderd. Plaats een nieuwe."</string>
+ <string name="activity_list_empty">"Geen overeenkomende activiteiten gevonden"</string>
+ <string name="permlab_pkgUsageStats">"gebruiksstatistieken van component bijwerken"</string>
+ <string name="permdesc_pkgUsageStats">"Hiermee kunnen verzamelde gebruiksstatistieken van een component worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tik twee keer voor zoomregeling"</string>
+ <string name="gadget_host_error_inflating">"Fout bij uitbreiden van widget"</string>
+ <string name="ime_action_go">"Ga"</string>
+ <string name="ime_action_search">"Zoeken"</string>
+ <string name="ime_action_send">"Verzenden"</string>
+ <string name="ime_action_next">"Volgende"</string>
+ <string name="ime_action_done">"Gereed"</string>
+ <string name="ime_action_default">"Uitvoeren"</string>
+ <string name="dial_number_using">"Nummer bellen"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Contact maken"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"aangevinkt"</string>
+ <string name="accessibility_compound_button_unselected">"niet aangevinkt"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 45e0795..3f7921d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"<bez nazwy>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Brak numeru telefonu)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Nieznany)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Poczta głosowa"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problem z połączeniem lub błędny kod MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Usługa była włączona."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Usługa została włączona dla:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Usługa została wyłączona."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Rejestracja powiodła się."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Wymazywanie zakończone pomyślnie."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Błędne hasło."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI zakończone."</string>
- <string name="badPin" msgid="5085454289896032547">"Wprowadzony stary kod PIN jest nieprawidłowy."</string>
- <string name="badPuk" msgid="5702522162746042460">"Wprowadzony kod PUK jest nieprawidłowy."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Wprowadzone kody PIN nie są identyczne."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string>
- <string name="needPuk" msgid="919668385956251611">"Karta SIM jest zablokowana kodem PUK. Wprowadź kod PUK, aby odblokować kartę."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Identyfikator rozmówcy przy połączeniach przychodzących"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Identyfikator rozmówcy przy połączeniach wychodzących"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Przekierowania połączeń"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Połączenia oczekujące"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blokada dzwonienia"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Zmiana hasła"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Zmiana kodu PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Numer telefonu, z którego wykonywane jest połączenie, widoczny"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numer telefonujący zastrzeżony"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Połączenie dla trzech abonentów"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Odrzucanie niepożądanych, irytujących połączeń"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Dostarczanie numeru telefonującego"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Nie przeszkadzać"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Identyfikator rozmówcy ustawiony jest domyślnie na „zastrzeżony”. Następne połączenie: zastrzeżony"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Identyfikator rozmówcy ustawiony jest domyślnie na „zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Identyfikator rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: zastrzeżony"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Identyfikator rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usługa nie jest świadczona."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Nie można zmienić ustawienia identyfikatora rozmówcy."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Zmieniono ograniczenie dostępu"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Usługa transmisji danych jest zablokowana."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usługa połączeń alarmowych jest zablokowana."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Usługa głosowa/SMS jest zablokowana."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Wszystkie usługi głosowe/SMS są zablokowane."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Głos"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dane"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Dane asynchroniczne"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchronizacja"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakiet"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Wskaźnik roamingu włączony"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Wskaźnik roamingu wyłączony"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Migający wskaźnik roamingu"</string>
- <string name="roamingText3" msgid="5148255027043943317">"W innej okolicy"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Poza biurem"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming – preferowany system"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming – dostępny system"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming – partner stowarzyszony"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming – partner Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming – pełna funkcjonalność usługi"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming – częściowa funkcjonalność usługi"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Baner roamingu włączony"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Baner roamingu wyłączony"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Wyszukiwanie usługi"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Wykonano kod funkcji."</string>
- <string name="fcError" msgid="3327560126588500777">"Problem z połączeniem lub nieprawidłowy kod funkcji."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Strona sieci Web zawiera błąd."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Nie można odszukać adresu URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schemat uwierzytelniania strony nie jest obsługiwany."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Nieudane uwierzytelnianie."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autoryzacja przez serwer proxy zakończyła się niepowodzeniem."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Nieudane połączenie z serwerem."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Nie udało się połączyć z serwerem. Spróbuj ponownie później."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Zbyt długi czas oczekiwania na połączenie z serwerem."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Strona zawiera zbyt wiele przekierowań do serwerów."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokół nie jest obsługiwany"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Nie można ustanowić bezpiecznego połączenia."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Nie można otworzyć strony, ponieważ adres URL jest nieprawidłowy."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Nie można uzyskać dostępu do pliku."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Nie znaleziono żądanego pliku."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Zbyt wiele żądań jest przetwarzanych. Spróbuj ponownie później."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronizacja"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizuj"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Pamięć telefonu jest pełna! Usuń niektóre pliki, aby zwolnić miejsce."</string>
- <string name="me" msgid="6545696007631404292">"Ja"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opcje telefonu"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tryb cichy"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Włącz połączenia bezprzewodowe"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Wyłącz połączenia bezprzewodowe"</string>
- <string name="screen_lock" msgid="799094655496098153">"Blokada ekranu"</string>
- <string name="power_off" msgid="4266614107412865048">"Wyłącz"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Wyłączanie..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefon zostanie wyłączony"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Brak ostatnio używanych aplikacji."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opcje telefonu"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tryb cichy"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Dźwięk jest wyłączony"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Dźwięk jest włączony"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
- <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
- <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usługi płatne"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Pozwól aplikacjom na wykonywanie płatnych operacji."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Twoje wiadomości"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Czytanie i zapisywanie wiadomości SMS, e-mail i innych"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Informacje osobiste"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Bezpośredni dostęp do kontaktów i kalendarza zapisanych w telefonie."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Twoja lokalizacja"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorowanie fizycznej lokalizacji"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Połączenia sieciowe"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Pozwól aplikacjom na dostęp do różnych funkcji sieci."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Twoje konta Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Uzyskaj dostęp do dostępnych kont Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Sterowanie sprzętowe"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Bezpośredni dostęp do elementów sprzętowych telefonu."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Połączenia telefoniczne"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorowanie, nagrywanie i przetwarzanie połączeń telefonicznych."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Narzędzia systemowe"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Dostęp i kontrola systemu niższego poziomu."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Narzędzia programistyczne"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funkcje potrzebne jedynie programistom"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Pamięć"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Dostęp do karty SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Pozwala aplikacjom na wyłączenie paska stanu lub dodawanie i usuwanie ikon systemowych."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"rozwijanie/zwijanie paska stanu"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Pozwala aplikacji na rozwijanie lub zwijanie paska stanu."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"przechwytywanie połączeń wychodzących"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Szkodliwe aplikacje mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"odbieranie wiadomości SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości SMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"odbieranie wiadomości MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Pozwala aplikacji na odbieranie i przetwarzanie wiadomości MMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez pokazywania ich użytkownikowi."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"wysyłanie wiadomości SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Pozwól aplikacjom na wysyłanie wiadomości SMS. Szkodliwe aplikacje mogą generować koszty, wysyłając wiadomości bez wiedzy użytkownika."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"czytanie wiadomości SMS lub MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Pozwala aplikacji na czytanie wiadomości SMS zapisanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą czytać poufne wiadomości."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"edytowanie wiadomości SMS lub MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Pozwala aplikacji na zapisywanie wiadomości SMS przechowywanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą usunąć wiadomości."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"odbieranie WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości WAP. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"pobieranie uruchomionych aplikacji"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Umożliwia aplikacji pobieranie informacji na temat obecnie i ostatnio uruchomionych zadań. Może pozwolić szkodliwym aplikacjom na uzyskanie prywatnych informacji na temat innych aplikacji."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"zmienianie porządku uruchomionych aplikacji"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Pozwala aplikacji na przenoszenie zadań z tła na pierwszy plan. Szkodliwe aplikacje mogą wymusić działanie pierwszoplanowe bez kontroli użytkownika."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"włączenie debugowania aplikacji"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Szkodliwe aplikacje mogą to wykorzystać do wyłączenia innych programów."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Pozwala aplikacji zmieniać bieżącą konfigurację, na przykład lokalny lub globalny rozmiar czcionki."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"resetowanie innych aplikacji"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Pozwala aplikacji na wymuszenie ponownego uruchomienia innych aplikacji."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"wymuszanie zamknięcia aplikacji"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Pozwala aplikacji na wymuszenie zamknięcia i cofnięcia dowolnej operacji działającej na pierwszym planie. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"pobieranie informacji o wewnętrznym stanie systemu"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Pozwala aplikacjom na pobieranie informacji o wewnętrznym stanie systemu. Szkodliwe aplikacje mogą pobrać szeroką gamę osobistych i zabezpieczonych informacji, które normalnie nie powinny im być nigdy potrzebne."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"częściowe wyłączenie"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Zapobiega przełączaniu aplikacji na inną przez użytkownika."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu, w jaki w systemie uruchamiane są różne działania. Szkodliwe aplikacje mogą całkowicie przejąć system. Te uprawnienia potrzebne są tylko programistom, nigdy w przypadku normalnego wykorzystywania telefonu."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Pozwala aplikacji na wysyłanie powiadomienia, że pakiet aplikacji został usunięty. Szkodliwe aplikacje mogą z niego skorzystać w celu wyłączania innych działających aplikacji."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"wysyłanie transmisji otrzymanych w wiadomości SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Szkodliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Pozwala aplikacji na nadanie powiadomienia o otrzymaniu wiadomości WAP PUSH. Szkodliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograniczanie liczby uruchomionych procesów"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"zamykanie wszystkich aplikacji działających w tle"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Pozwala aplikacji na kontrolowanie, czy czynności są zawsze kończone, kiedy zaczynają działać w tle. Nigdy nie jest potrzebne normalnym aplikacjom."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"zmienianie statystyk dotyczących baterii"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Pozwala na zmianę zebranych statystyk dotyczących baterii. Nie do wykorzystania przez normalne aplikacje."</string>
- <string name="permlab_backup" msgid="470013022865453920">"kontrolowanie tworzenia i przywracania kopii zapasowych systemu"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Umożliwia aplikacji kontrolowanie mechanizmu tworzenia i przywracania kopii zapasowych systemu. Nie jest przeznaczone do użytku dla zwykłych aplikacji."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"wyświetlanie nieuwierzytelnionych okien"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Pozwala na tworzenie okien, które przeznaczone są do wykorzystania przez wewnętrzny interfejs użytkownika systemu. Nie do wykorzystania przez normalne aplikacje."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"wyświetlanie ostrzeżeń systemowych"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Pozwala aplikacji na pokazywanie okien alarmów systemowych. Szkodliwe aplikacje mogą przejąć kontrolę nad całym ekranem telefonu."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"zmienianie ogólnej prędkości animacji"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Pozwala aplikacji na zmianę ogólnej prędkości animacji (szybsze lub wolniejsze animacje) w dowolnym momencie."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"zarządzanie tokenami aplikacji"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Pozwala aplikacjom na tworzenie własnych tokenów i zarządzanie nimi z pominięciem zwykłego porządku warstw. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"naciskanie klawiszy oraz przycisków sterujących"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Pozwala aplikacjom na dostarczanie własnych zdarzeń wprowadzania danych (naciśnięcie klawisza itp.) do innych aplikacji. Szkodliwe aplikacje mogą to wykorzystać do przejęcia kontroli nad telefonem."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"zapamiętywanie wpisywanych znaków oraz wykonywanych czynności"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Pozwala aplikacjom na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"tworzenie powiązania z metodą wejściową"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu metody wejściowej. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Dzięki temu uprawnieniu część elementów aplikacji może być trwała, przez co system nie może ich wykorzystać do innych aplikacji."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"usuwanie aplikacji"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Pozwala aplikacjom na usuwanie pakietów systemu Android. Szkodliwe aplikacje mogą wykorzystać to do usuwania ważnych aplikacji."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"usuwanie danych innych aplikacji"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Pozwala aplikacji na czyszczenie danych użytkowników."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"usuwanie pamięci podręcznej innych aplikacji"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Pozwala aplikacji na usuwanie plików z pamięci podręcznej."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"mierzenie rozmiaru pamięci aplikacji"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Pozwala aplikacji na pobieranie własnego kodu, danych oraz rozmiarów pamięci podręcznej"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"bezpośrednie instalowanie aplikacji"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Pozwala aplikacji na instalowanie nowych lub zaktualizowanych pakietów systemu Android. Szkodliwe aplikacje mogą to wykorzystać, aby dodać nowe aplikacje z arbitralnie nadanymi rozległymi uprawnieniami."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"usuwanie wszystkich danych aplikacji z pamięci podręcznej"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"czytanie plików dziennika systemu"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"włączanie lub wyłączanie składników aplikacji"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Pozwala aplikacji na włączenie lub wyłączenie składnika innej aplikacji. Szkodliwe aplikacje mogą wykorzystać to uprawnienie do wyłączenia ważnych funkcji telefonu. Przy włączaniu uprawnienia należy zachować ostrożność, ponieważ istnieje możliwość wprowadzenia składników aplikacji w stan nieużywalności, niespójności lub niestabilności."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ustawianie preferowanych aplikacji"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Umożliwia aplikacji zmianę preferowanych programów użytkownika. Może to pozwolić szkodliwym aplikacjom na niezauważalną podmianę uruchamianych programów, aby zbierać prywatne dane użytkownika."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modyfikowanie ogólnych ustawień systemu"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Pozwala aplikacji na zmianę danych ustawień systemowych. Szkodliwe aplikacje mogą uszkodzić konfigurację systemu."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modyfikowanie ustawień systemu dotyczących zabezpieczeń"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Pozwala aplikacji na modyfikowanie danych ustawień zabezpieczeń systemu. To uprawnienie nie jest wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"zmienianie mapy usług Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Pozwala aplikacji na modyfikowanie mapy usług Google. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatyczne uruchamianie podczas uruchamiania urządzenia"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Pozwala aplikacji na samoczynne uruchamianie zaraz po zakończeniu uruchamiania systemu. Może to spowodować, że telefon będzie się dłużej uruchamiał oraz może ogólnie spowolnić działanie urządzenia, ponieważ aplikacja będzie cały czas uruchomiona."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"wysyłanie transmisji trwałej"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Pozwala aplikacji na wysyłanie transmisji trwałych, które pozostają aktywne po zakończeniu połączenia. Szkodliwe aplikacje mogą spowolnić lub zdestabilizować telefon, przez wymuszenie zbyt dużego zużycia pamięci."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"czytanie danych kontaktów"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Pozwala aplikacji na czytanie wszystkich danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wysyłać dane użytkownika do innych ludzi."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"zapisywanie danych kontaktowych"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Pozwala aplikacji na zmianę danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane kontaktowe."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"zapisywanie danych właściciela"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Pozwala aplikacji na zmianę danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wymazać lub zmienić dane właściciela."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"czytanie danych właściciela"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Pozwala aplikacji na czytanie danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do odczytania danych właściciela."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"czytanie danych kalendarza"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Pozwala aplikacji na odczytywanie wszystkich wydarzeń z kalendarza, zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do rozsyłania wydarzeń z kalendarza do innych ludzi."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"zapisywanie danych kalendarza"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Pozwala aplikacji na zmianę wydarzeń z kalendarza zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane w kalendarzu."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"udawanie źródeł położenia dla testów"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Tworzenie pozorowanych źródeł ustalania położenia dla testów. Szkodliwe aplikacje mogą to wykorzystać, aby zastąpić prawdziwe położenie i/lub stan zwracany przez prawdziwe źródła, takie jak GPS lub dostawcy usługi sieciowej."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji. Szkodliwe aplikacje mogą go wykorzystać, aby wpływać na działanie urządzenia GPS lub innych źródeł ustalania lokalizacji."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"uprawnienia do instalowania dostawcy danych o lokalizacji"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Utwórz sztuczne źródła danych o lokalizacji na potrzeby testowania. Złośliwe aplikacje mogą korzystać z tej opcji w celu zastępowania danych o lokalizacji i/lub stanie zwracanych przez prawdziwe źródła danych o lokalizacji, takie jak odbiornik GPS lub dostawcy sieciowi, bądź monitorowania i zgłaszania lokalizacji do źródeł zewnętrznych."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"dokładna lokalizacja (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Uzyskiwanie dostępu do dokładnych źródeł ustalania położenia w telefonie, takich jak system GPS, tam, gdzie są one dostępne. Szkodliwe aplikacje mogą to wykorzystać do określenia położenia użytkownika oraz mogą zużywać więcej energii baterii."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"przybliżone ustalanie lokalizacji (oparte o sieć)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Dostęp do źródeł, takich jak bazy danych sieci komórkowych, jeśli są dostępne, które pozwalają określić przybliżoną lokalizację telefonu. Szkodliwe aplikacje mogą go wykorzystać do określenia, gdzie w przybliżeniu znajduje się użytkownik."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"dostęp do usługi SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"czytanie bufora ramki"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Pozwala aplikacji na wykorzystanie odczytanej zawartości bufora ramki."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmienianie ustawień audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Pozwala aplikacjom na zmianę globalnych ustawień audio, takich jak głośność i routing."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"nagrywanie dźwięku"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Pozwala aplikacji na dostęp do ścieżki nagrywania dźwięku."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"robienie zdjęć"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Pozwala aplikacji na wykonywanie zdjęć za pomocą aparatu. Dzięki temu może ona pobierać zdjęcia z aparatu w dowolnym momencie."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"wyłączenie telefonu na stałe"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Pozwala aplikacji na wyłączenie całego telefonu na stałe. Jest to bardzo niebezpieczne."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"wymuszanie ponownego uruchomienia telefonu"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Pozwala aplikacji na wymuszenie ponownego uruchomienia telefonu."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"podłączanie i odłączanie systemów plików"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Pozwala aplikacjom na podłączanie i odłączanie systemów plików w pamięciach przenośnych."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatowanie pamięci zewnętrznej"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Zezwala aplikacji na formatowanie wymiennych nośników."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrolowanie wibracji"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Pozwala aplikacji kontrolować latarkę."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testowanie sprzętu"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Pozwala aplikacji na kontrolowanie różnych urządzeń peryferyjnych w celu testowania sprzętu."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Pozwala aplikacjom na dzwonienie pod numery telefonów bez interwencji użytkownika. Szkodliwe aplikacje mogą powodować występowanie niespodziewanych połączeń na rachunku telefonicznym. Należy zauważyć, że aplikacje nie mogą dzwonić na numery alarmowe."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"bezpośrednie wybieranie dowolnych numerów telefonu"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Pozwala aplikacji dzwonić na dowolny numer telefonu, włącznie z numerami alarmowymi, bez interwencji użytkownika. Szkodliwe aplikacje mogą wykonywać niepotrzebne i nielegalne połączenia z usługami alarmowymi."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrolowanie powiadomień o aktualizacjach lokalizacji"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Pozwala włączyć/wyłączyć powiadomienia o aktualizacjach lokalizacji przez sieć bezprzewodową. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"dostęp do właściwości usługi rezerwacji"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"wybieranie widżetów"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Zezwala aplikacjom na wskazywanie systemowi, które widżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"zmiana stanu telefonu"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Pozwala aplikacji na zapobieganie przejściu telefonu w stan uśpienia."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"włączanie lub wyłączanie telefonu"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Pozwala aplikacji włączać i wyłączać telefon."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"uruchamianie w trybie testu fabrycznego"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Uruchom jako niskopoziomowy test producenta, pozwalając na całkowity dostęp do elementów sprzętowych telefonu. Dostępne tylko jeśli telefon działa w trybie testu producenta."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"ustawianie tapety"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Pozwala aplikacji na ustawianie tapety systemu."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"ustawianie wskazówek dotyczących rozmiaru tapety"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Pozwala aplikacji na ustawianie wskazówek dotyczących rozmiaru tapety."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"resetowanie systemu do ustawień fabrycznych"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Pozwala aplikacji na całkowite zresetowanie systemu do ustawień fabrycznych, z wymazaniem wszystkich danych, konfiguracji oraz zainstalowanych aplikacji."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"ustawianie strefy czasowej"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Pozwala aplikacji na zmianę strefy czasowej w telefonie."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"wykrywanie znanych kont"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Pozwala aplikacji na pobranie listy kont zapisanych w telefonie."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"wyświetlanie stanu sieci"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Pozwala aplikacji na wyświetlanie stanu wszystkich sieci."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"pełen dostęp do internetu"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Pozwala aplikacji na tworzenie gniazd sieciowych."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"zapisywanie ustawień nazwy punktu dostępowego (APN, Access Point Name)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Pozwala aplikacji na zmianę ustawień APN, takich jak serwer proxy oraz port dowolnego APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"zmienianie połączeń sieci"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Pozwala aplikacji na zmianę stanu połączeń sieciowych."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"zmienianie ustawienia używania danych w tle"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Zezwala aplikacji na zmianę ustawień użycia danych w tle."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"wyświetlanie stanu Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Pozwala aplikacji na wyświetlanie informacji o stanie Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"zmiana stanu Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Pozwala aplikacji na łączenie i rozłączanie z punktami dostępowymi Wi-Fi oraz na dokonywanie zmian skonfigurowanych sieci Wi-Fi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Umożliwia aplikacji odbieranie pakietów nieskierowanych bezpośrednio do Twojego urządzenia. Może to być przydatne przy wykrywaniu usług oferowanych w okolicy. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrowanie Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Pozwala aplikacji na konfigurowanie lokalnego telefonu Bluetooth, wyszukiwanie urządzeń zdalnych i łączenie się z nimi."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"tworzenie połączeń Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Pozwala aplikacji na wyświetlanie konfiguracji lokalnego telefonu Bluetooth oraz na tworzenie i akceptowanie połączeń ze sparowanymi urządzeniami."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"wyłączanie blokady klawiatury"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Typowym przykładem takiego działania jest wyłączanie blokady klawiatury, gdy pojawia się połączenie przychodzące, a następnie ponowne jej włączanie po zakończeniu połączenia."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"czytanie ustawień synchronizowania"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Pozwala aplikacji na czytanie ustawień synchronizacji, takich jak informacje, czy synchronizacja kontaktów jest włączona."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"zapisywanie ustawień synchronizowania"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Pozwala aplikacji na zmianę ustawień synchronizowania, takich jak ustalenie, czy synchronizacja dla kontaktów ma być włączona."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"czytanie statystyk dotyczących synchronizowania"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Pozwala aplikacji na czytanie statystyk synchronizowania, np. historii przeprowadzonych synchronizacji."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"czytanie subskrybowanych źródeł"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zapisywanie subskrybowanych źródeł"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"odczytywanie słownika zdefiniowanego przez użytkownika"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Zezwala aplikacji na odczytywanie wszelkich prywatnych słów, nazw i wyrażeń zapisanych przez użytkownika w swoim słowniku."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"zapisywanie w słowniku zdefiniowanym przez użytkownika"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Zezwala aplikacjom na zapisywanie nowych słów w słowniku użytkownika."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modyfikowanie/usuwanie zawartości karty SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Umożliwia aplikacji zapis na karcie SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"<bez nazwy>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Brak numeru telefonu)"</string>
+ <string name="unknownName">"(Nieznany)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Poczta głosowa"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problem z połączeniem lub błędny kod MMI."</string>
+ <string name="serviceEnabled">"Usługa była włączona."</string>
+ <string name="serviceEnabledFor">"Usługa została włączona dla:"</string>
+ <string name="serviceDisabled">"Usługa została wyłączona."</string>
+ <string name="serviceRegistered">"Rejestracja powiodła się."</string>
+ <string name="serviceErased">"Wymazywanie zakończone pomyślnie."</string>
+ <string name="passwordIncorrect">"Błędne hasło."</string>
+ <string name="mmiComplete">"MMI zakończone."</string>
+ <string name="badPin">"Wprowadzony stary kod PIN jest nieprawidłowy."</string>
+ <string name="badPuk">"Wprowadzony kod PUK jest nieprawidłowy."</string>
+ <string name="mismatchPin">"Wprowadzone kody PIN nie są identyczne."</string>
+ <string name="invalidPin">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string>
+ <string name="needPuk">"Karta SIM jest zablokowana kodem PUK. Wprowadź kod PUK, aby odblokować kartę."</string>
+ <string name="needPuk2">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
+ <string name="ClipMmi">"Identyfikator rozmówcy przy połączeniach przychodzących"</string>
+ <string name="ClirMmi">"Identyfikator rozmówcy przy połączeniach wychodzących"</string>
+ <string name="CfMmi">"Przekierowania połączeń"</string>
+ <string name="CwMmi">"Połączenia oczekujące"</string>
+ <string name="BaMmi">"Blokada dzwonienia"</string>
+ <string name="PwdMmi">"Zmiana hasła"</string>
+ <string name="PinMmi">"Zmiana kodu PIN"</string>
+ <string name="CnipMmi">"Numer telefonu, z którego wykonywane jest połączenie, widoczny"</string>
+ <string name="CnirMmi">"Numer telefonujący zastrzeżony"</string>
+ <string name="ThreeWCMmi">"Połączenie dla trzech abonentów"</string>
+ <string name="RuacMmi">"Odrzucanie niepożądanych, irytujących połączeń"</string>
+ <string name="CndMmi">"Dostarczanie numeru telefonującego"</string>
+ <string name="DndMmi">"Nie przeszkadzać"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Identyfikator rozmówcy ustawiony jest domyślnie na „zastrzeżony”. Następne połączenie: zastrzeżony"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Identyfikator rozmówcy ustawiony jest domyślnie na „zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Identyfikator rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: zastrzeżony"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Identyfikator rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
+ <string name="serviceNotProvisioned">"Usługa nie jest świadczona."</string>
+ <string name="CLIRPermanent">"Nie można zmienić ustawienia identyfikatora rozmówcy."</string>
+ <string name="RestrictedChangedTitle">"Zmieniono ograniczenie dostępu"</string>
+ <string name="RestrictedOnData">"Usługa transmisji danych jest zablokowana."</string>
+ <string name="RestrictedOnEmergency">"Usługa połączeń alarmowych jest zablokowana."</string>
+ <string name="RestrictedOnNormal">"Usługa głosowa/SMS jest zablokowana."</string>
+ <string name="RestrictedOnAll">"Wszystkie usługi głosowe/SMS są zablokowane."</string>
+ <string name="serviceClassVoice">"Głos"</string>
+ <string name="serviceClassData">"Dane"</string>
+ <string name="serviceClassFAX">"FAKS"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Dane asynchroniczne"</string>
+ <string name="serviceClassDataSync">"Synchronizacja"</string>
+ <string name="serviceClassPacket">"Pakiet"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Wskaźnik roamingu włączony"</string>
+ <string name="roamingText1">"Wskaźnik roamingu wyłączony"</string>
+ <string name="roamingText2">"Migający wskaźnik roamingu"</string>
+ <string name="roamingText3">"W innej okolicy"</string>
+ <string name="roamingText4">"Poza biurem"</string>
+ <string name="roamingText5">"Roaming – preferowany system"</string>
+ <string name="roamingText6">"Roaming – dostępny system"</string>
+ <string name="roamingText7">"Roaming – partner stowarzyszony"</string>
+ <string name="roamingText8">"Roaming – partner Premium"</string>
+ <string name="roamingText9">"Roaming – pełna funkcjonalność usługi"</string>
+ <string name="roamingText10">"Roaming – częściowa funkcjonalność usługi"</string>
+ <string name="roamingText11">"Baner roamingu włączony"</string>
+ <string name="roamingText12">"Baner roamingu wyłączony"</string>
+ <string name="roamingTextSearching">"Wyszukiwanie usługi"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="fcComplete">"Wykonano kod funkcji."</string>
+ <string name="fcError">"Problem z połączeniem lub nieprawidłowy kod funkcji."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Strona sieci Web zawiera błąd."</string>
+ <string name="httpErrorLookup">"Nie można odszukać adresu URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schemat uwierzytelniania strony nie jest obsługiwany."</string>
+ <string name="httpErrorAuth">"Nieudane uwierzytelnianie."</string>
+ <string name="httpErrorProxyAuth">"Autoryzacja przez serwer proxy zakończyła się niepowodzeniem."</string>
+ <string name="httpErrorConnect">"Nieudane połączenie z serwerem."</string>
+ <string name="httpErrorIO">"Nie udało się połączyć z serwerem. Spróbuj ponownie później."</string>
+ <string name="httpErrorTimeout">"Zbyt długi czas oczekiwania na połączenie z serwerem."</string>
+ <string name="httpErrorRedirectLoop">"Strona zawiera zbyt wiele przekierowań do serwerów."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokół nie jest obsługiwany"</string>
+ <string name="httpErrorFailedSslHandshake">"Nie można ustanowić bezpiecznego połączenia."</string>
+ <string name="httpErrorBadUrl">"Nie można otworzyć strony, ponieważ adres URL jest nieprawidłowy."</string>
+ <string name="httpErrorFile">"Nie można uzyskać dostępu do pliku."</string>
+ <string name="httpErrorFileNotFound">"Nie znaleziono żądanego pliku."</string>
+ <string name="httpErrorTooManyRequests">"Zbyt wiele żądań jest przetwarzanych. Spróbuj ponownie później."</string>
+ <string name="contentServiceSync">"Synchronizacja"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronizuj"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Pamięć telefonu jest pełna! Usuń niektóre pliki, aby zwolnić miejsce."</string>
+ <string name="me">"Ja"</string>
+ <string name="power_dialog">"Opcje telefonu"</string>
+ <string name="silent_mode">"Tryb cichy"</string>
+ <string name="turn_on_radio">"Włącz połączenia bezprzewodowe"</string>
+ <string name="turn_off_radio">"Wyłącz połączenia bezprzewodowe"</string>
+ <string name="screen_lock">"Blokada ekranu"</string>
+ <string name="power_off">"Wyłącz"</string>
+ <string name="shutdown_progress">"Wyłączanie..."</string>
+ <string name="shutdown_confirm">"Telefon zostanie wyłączony"</string>
+ <string name="no_recent_tasks">"Brak ostatnio używanych aplikacji."</string>
+ <string name="global_actions">"Opcje telefonu"</string>
+ <string name="global_action_lock">"Blokada ekranu"</string>
+ <string name="global_action_power_off">"Wyłącz"</string>
+ <string name="global_action_toggle_silent_mode">"Tryb cichy"</string>
+ <string name="global_action_silent_mode_on_status">"Dźwięk jest wyłączony"</string>
+ <string name="global_action_silent_mode_off_status">"Dźwięk jest włączony"</string>
+ <string name="global_actions_toggle_airplane_mode">"Tryb samolotowy"</string>
+ <string name="global_actions_airplane_mode_on_status">"Tryb samolotowy jest włączony"</string>
+ <string name="global_actions_airplane_mode_off_status">"Tryb samolotowy jest wyłączony"</string>
+ <string name="safeMode">"Tryb awaryjny"</string>
+ <string name="android_system_label">"System Android"</string>
+ <string name="permgrouplab_costMoney">"Usługi płatne"</string>
+ <string name="permgroupdesc_costMoney">"Pozwól aplikacjom na wykonywanie płatnych operacji."</string>
+ <string name="permgrouplab_messages">"Twoje wiadomości"</string>
+ <string name="permgroupdesc_messages">"Czytanie i zapisywanie wiadomości SMS, e-mail i innych"</string>
+ <string name="permgrouplab_personalInfo">"Informacje osobiste"</string>
+ <string name="permgroupdesc_personalInfo">"Bezpośredni dostęp do kontaktów i kalendarza zapisanych w telefonie."</string>
+ <string name="permgrouplab_location">"Twoja lokalizacja"</string>
+ <string name="permgroupdesc_location">"Monitorowanie fizycznej lokalizacji"</string>
+ <string name="permgrouplab_network">"Połączenia sieciowe"</string>
+ <string name="permgroupdesc_network">"Pozwól aplikacjom na dostęp do różnych funkcji sieci."</string>
+ <string name="permgrouplab_accounts">"Twoje konta Google"</string>
+ <string name="permgroupdesc_accounts">"Uzyskaj dostęp do dostępnych kont Google."</string>
+ <string name="permgrouplab_hardwareControls">"Sterowanie sprzętowe"</string>
+ <string name="permgroupdesc_hardwareControls">"Bezpośredni dostęp do elementów sprzętowych telefonu."</string>
+ <string name="permgrouplab_phoneCalls">"Połączenia telefoniczne"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorowanie, nagrywanie i przetwarzanie połączeń telefonicznych."</string>
+ <string name="permgrouplab_systemTools">"Narzędzia systemowe"</string>
+ <string name="permgroupdesc_systemTools">"Dostęp i kontrola systemu niższego poziomu."</string>
+ <string name="permgrouplab_developmentTools">"Narzędzia programistyczne"</string>
+ <string name="permgroupdesc_developmentTools">"Funkcje potrzebne jedynie programistom"</string>
+ <string name="permgrouplab_storage">"Pamięć"</string>
+ <string name="permgroupdesc_storage">"Dostęp do karty SD."</string>
+ <string name="permlab_statusBar">"wyłączanie lub zmienianie paska stanu"</string>
+ <string name="permdesc_statusBar">"Pozwala aplikacjom na wyłączenie paska stanu lub dodawanie i usuwanie ikon systemowych."</string>
+ <string name="permlab_expandStatusBar">"rozwijanie/zwijanie paska stanu"</string>
+ <string name="permdesc_expandStatusBar">"Pozwala aplikacji na rozwijanie lub zwijanie paska stanu."</string>
+ <string name="permlab_processOutgoingCalls">"przechwytywanie połączeń wychodzących"</string>
+ <string name="permdesc_processOutgoingCalls">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Szkodliwe aplikacje mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
+ <string name="permlab_receiveSms">"odbieranie wiadomości SMS"</string>
+ <string name="permdesc_receiveSms">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości SMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
+ <string name="permlab_receiveMms">"odbieranie wiadomości MMS"</string>
+ <string name="permdesc_receiveMms">"Pozwala aplikacji na odbieranie i przetwarzanie wiadomości MMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez pokazywania ich użytkownikowi."</string>
+ <string name="permlab_sendSms">"wysyłanie wiadomości SMS"</string>
+ <string name="permdesc_sendSms">"Pozwól aplikacjom na wysyłanie wiadomości SMS. Szkodliwe aplikacje mogą generować koszty, wysyłając wiadomości bez wiedzy użytkownika."</string>
+ <string name="permlab_readSms">"czytanie wiadomości SMS lub MMS"</string>
+ <string name="permdesc_readSms">"Pozwala aplikacji na czytanie wiadomości SMS zapisanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą czytać poufne wiadomości."</string>
+ <string name="permlab_writeSms">"edytowanie wiadomości SMS lub MMS"</string>
+ <string name="permdesc_writeSms">"Pozwala aplikacji na zapisywanie wiadomości SMS przechowywanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą usunąć wiadomości."</string>
+ <string name="permlab_receiveWapPush">"odbieranie WAP"</string>
+ <string name="permdesc_receiveWapPush">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości WAP. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
+ <string name="permlab_getTasks">"pobieranie uruchomionych aplikacji"</string>
+ <string name="permdesc_getTasks">"Umożliwia aplikacji pobieranie informacji na temat obecnie i ostatnio uruchomionych zadań. Może pozwolić szkodliwym aplikacjom na uzyskanie prywatnych informacji na temat innych aplikacji."</string>
+ <string name="permlab_reorderTasks">"zmienianie porządku uruchomionych aplikacji"</string>
+ <string name="permdesc_reorderTasks">"Pozwala aplikacji na przenoszenie zadań z tła na pierwszy plan. Szkodliwe aplikacje mogą wymusić działanie pierwszoplanowe bez kontroli użytkownika."</string>
+ <string name="permlab_setDebugApp">"włączenie debugowania aplikacji"</string>
+ <string name="permdesc_setDebugApp">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Szkodliwe aplikacje mogą to wykorzystać do wyłączenia innych programów."</string>
+ <string name="permlab_changeConfiguration">"zmienianie ustawień interfejsu użytkownika"</string>
+ <string name="permdesc_changeConfiguration">"Pozwala aplikacji zmieniać bieżącą konfigurację, na przykład lokalny lub globalny rozmiar czcionki."</string>
+ <string name="permlab_restartPackages">"resetowanie innych aplikacji"</string>
+ <string name="permdesc_restartPackages">"Pozwala aplikacji na wymuszenie ponownego uruchomienia innych aplikacji."</string>
+ <string name="permlab_forceBack">"wymuszanie zamknięcia aplikacji"</string>
+ <string name="permdesc_forceBack">"Pozwala aplikacji na wymuszenie zamknięcia i cofnięcia dowolnej operacji działającej na pierwszym planie. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_dump">"pobieranie informacji o wewnętrznym stanie systemu"</string>
+ <string name="permdesc_dump">"Pozwala aplikacjom na pobieranie informacji o wewnętrznym stanie systemu. Szkodliwe aplikacje mogą pobrać szeroką gamę osobistych i zabezpieczonych informacji, które normalnie nie powinny im być nigdy potrzebne."</string>
+ <string name="permlab_shutdown">"częściowe wyłączenie"</string>
+ <string name="permdesc_shutdown">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
+ <string name="permlab_stopAppSwitches">"zapobieganie przełączaniu aplikacji"</string>
+ <string name="permdesc_stopAppSwitches">"Zapobiega przełączaniu aplikacji na inną przez użytkownika."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
+ <string name="permdesc_runSetActivityWatcher">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu, w jaki w systemie uruchamiane są różne działania. Szkodliwe aplikacje mogą całkowicie przejąć system. Te uprawnienia potrzebne są tylko programistom, nigdy w przypadku normalnego wykorzystywania telefonu."</string>
+ <string name="permlab_broadcastPackageRemoved">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Pozwala aplikacji na wysyłanie powiadomienia, że pakiet aplikacji został usunięty. Szkodliwe aplikacje mogą z niego skorzystać w celu wyłączania innych działających aplikacji."</string>
+ <string name="permlab_broadcastSmsReceived">"wysyłanie transmisji otrzymanych w wiadomości SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Szkodliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
+ <string name="permlab_broadcastWapPush">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Pozwala aplikacji na nadanie powiadomienia o otrzymaniu wiadomości WAP PUSH. Szkodliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
+ <string name="permlab_setProcessLimit">"ograniczanie liczby uruchomionych procesów"</string>
+ <string name="permdesc_setProcessLimit">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_setAlwaysFinish">"zamykanie wszystkich aplikacji działających w tle"</string>
+ <string name="permdesc_setAlwaysFinish">"Pozwala aplikacji na kontrolowanie, czy czynności są zawsze kończone, kiedy zaczynają działać w tle. Nigdy nie jest potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_batteryStats">"zmienianie statystyk dotyczących baterii"</string>
+ <string name="permdesc_batteryStats">"Pozwala na zmianę zebranych statystyk dotyczących baterii. Nie do wykorzystania przez normalne aplikacje."</string>
+ <string name="permlab_backup">"kontrolowanie tworzenia i przywracania kopii zapasowych systemu"</string>
+ <string name="permdesc_backup">"Umożliwia aplikacji kontrolowanie mechanizmu tworzenia i przywracania kopii zapasowych systemu. Nie jest przeznaczone do użytku dla zwykłych aplikacji."</string>
+ <string name="permlab_internalSystemWindow">"wyświetlanie nieuwierzytelnionych okien"</string>
+ <string name="permdesc_internalSystemWindow">"Pozwala na tworzenie okien, które przeznaczone są do wykorzystania przez wewnętrzny interfejs użytkownika systemu. Nie do wykorzystania przez normalne aplikacje."</string>
+ <string name="permlab_systemAlertWindow">"wyświetlanie ostrzeżeń systemowych"</string>
+ <string name="permdesc_systemAlertWindow">"Pozwala aplikacji na pokazywanie okien alarmów systemowych. Szkodliwe aplikacje mogą przejąć kontrolę nad całym ekranem telefonu."</string>
+ <string name="permlab_setAnimationScale">"zmienianie ogólnej prędkości animacji"</string>
+ <string name="permdesc_setAnimationScale">"Pozwala aplikacji na zmianę ogólnej prędkości animacji (szybsze lub wolniejsze animacje) w dowolnym momencie."</string>
+ <string name="permlab_manageAppTokens">"zarządzanie tokenami aplikacji"</string>
+ <string name="permdesc_manageAppTokens">"Pozwala aplikacjom na tworzenie własnych tokenów i zarządzanie nimi z pominięciem zwykłego porządku warstw. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_injectEvents">"naciskanie klawiszy oraz przycisków sterujących"</string>
+ <string name="permdesc_injectEvents">"Pozwala aplikacjom na dostarczanie własnych zdarzeń wprowadzania danych (naciśnięcie klawisza itp.) do innych aplikacji. Szkodliwe aplikacje mogą to wykorzystać do przejęcia kontroli nad telefonem."</string>
+ <string name="permlab_readInputState">"zapamiętywanie wpisywanych znaków oraz wykonywanych czynności"</string>
+ <string name="permdesc_readInputState">"Pozwala aplikacjom na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_bindInputMethod">"tworzenie powiązania z metodą wejściową"</string>
+ <string name="permdesc_bindInputMethod">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu metody wejściowej. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
+ <string name="permlab_setOrientation">"zmienianie orientacji ekranu"</string>
+ <string name="permdesc_setOrientation">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string>
+ <string name="permlab_signalPersistentProcesses">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
+ <string name="permdesc_signalPersistentProcesses">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string>
+ <string name="permlab_persistentActivity">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
+ <string name="permdesc_persistentActivity">"Dzięki temu uprawnieniu część elementów aplikacji może być trwała, przez co system nie może ich wykorzystać do innych aplikacji."</string>
+ <string name="permlab_deletePackages">"usuwanie aplikacji"</string>
+ <string name="permdesc_deletePackages">"Pozwala aplikacjom na usuwanie pakietów systemu Android. Szkodliwe aplikacje mogą wykorzystać to do usuwania ważnych aplikacji."</string>
+ <string name="permlab_clearAppUserData">"usuwanie danych innych aplikacji"</string>
+ <string name="permdesc_clearAppUserData">"Pozwala aplikacji na czyszczenie danych użytkowników."</string>
+ <string name="permlab_deleteCacheFiles">"usuwanie pamięci podręcznej innych aplikacji"</string>
+ <string name="permdesc_deleteCacheFiles">"Pozwala aplikacji na usuwanie plików z pamięci podręcznej."</string>
+ <string name="permlab_getPackageSize">"mierzenie rozmiaru pamięci aplikacji"</string>
+ <string name="permdesc_getPackageSize">"Pozwala aplikacji na pobieranie własnego kodu, danych oraz rozmiarów pamięci podręcznej"</string>
+ <string name="permlab_installPackages">"bezpośrednie instalowanie aplikacji"</string>
+ <string name="permdesc_installPackages">"Pozwala aplikacji na instalowanie nowych lub zaktualizowanych pakietów systemu Android. Szkodliwe aplikacje mogą to wykorzystać, aby dodać nowe aplikacje z arbitralnie nadanymi rozległymi uprawnieniami."</string>
+ <string name="permlab_clearAppCache">"usuwanie wszystkich danych aplikacji z pamięci podręcznej"</string>
+ <string name="permdesc_clearAppCache">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string>
+ <string name="permlab_readLogs">"czytanie plików dziennika systemu"</string>
+ <string name="permdesc_readLogs">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string>
+ <string name="permlab_diagnostic">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
+ <string name="permdesc_diagnostic">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string>
+ <string name="permlab_changeComponentState">"włączanie lub wyłączanie składników aplikacji"</string>
+ <string name="permdesc_changeComponentState">"Pozwala aplikacji na włączenie lub wyłączenie składnika innej aplikacji. Szkodliwe aplikacje mogą wykorzystać to uprawnienie do wyłączenia ważnych funkcji telefonu. Przy włączaniu uprawnienia należy zachować ostrożność, ponieważ istnieje możliwość wprowadzenia składników aplikacji w stan nieużywalności, niespójności lub niestabilności."</string>
+ <string name="permlab_setPreferredApplications">"ustawianie preferowanych aplikacji"</string>
+ <string name="permdesc_setPreferredApplications">"Umożliwia aplikacji zmianę preferowanych programów użytkownika. Może to pozwolić szkodliwym aplikacjom na niezauważalną podmianę uruchamianych programów, aby zbierać prywatne dane użytkownika."</string>
+ <string name="permlab_writeSettings">"modyfikowanie ogólnych ustawień systemu"</string>
+ <string name="permdesc_writeSettings">"Pozwala aplikacji na zmianę danych ustawień systemowych. Szkodliwe aplikacje mogą uszkodzić konfigurację systemu."</string>
+ <string name="permlab_writeSecureSettings">"modyfikowanie ustawień systemu dotyczących zabezpieczeń"</string>
+ <string name="permdesc_writeSecureSettings">"Pozwala aplikacji na modyfikowanie danych ustawień zabezpieczeń systemu. To uprawnienie nie jest wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_writeGservices">"zmienianie mapy usług Google"</string>
+ <string name="permdesc_writeGservices">"Pozwala aplikacji na modyfikowanie mapy usług Google. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_receiveBootCompleted">"automatyczne uruchamianie podczas uruchamiania urządzenia"</string>
+ <string name="permdesc_receiveBootCompleted">"Pozwala aplikacji na samoczynne uruchamianie zaraz po zakończeniu uruchamiania systemu. Może to spowodować, że telefon będzie się dłużej uruchamiał oraz może ogólnie spowolnić działanie urządzenia, ponieważ aplikacja będzie cały czas uruchomiona."</string>
+ <string name="permlab_broadcastSticky">"wysyłanie transmisji trwałej"</string>
+ <string name="permdesc_broadcastSticky">"Pozwala aplikacji na wysyłanie transmisji trwałych, które pozostają aktywne po zakończeniu połączenia. Szkodliwe aplikacje mogą spowolnić lub zdestabilizować telefon, przez wymuszenie zbyt dużego zużycia pamięci."</string>
+ <string name="permlab_readContacts">"czytanie danych kontaktów"</string>
+ <string name="permdesc_readContacts">"Pozwala aplikacji na czytanie wszystkich danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wysyłać dane użytkownika do innych ludzi."</string>
+ <string name="permlab_writeContacts">"zapisywanie danych kontaktowych"</string>
+ <string name="permdesc_writeContacts">"Pozwala aplikacji na zmianę danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane kontaktowe."</string>
+ <string name="permlab_writeOwnerData">"zapisywanie danych właściciela"</string>
+ <string name="permdesc_writeOwnerData">"Pozwala aplikacji na zmianę danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wymazać lub zmienić dane właściciela."</string>
+ <string name="permlab_readOwnerData">"czytanie danych właściciela"</string>
+ <string name="permdesc_readOwnerData">"Pozwala aplikacji na czytanie danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do odczytania danych właściciela."</string>
+ <string name="permlab_readCalendar">"czytanie danych kalendarza"</string>
+ <string name="permdesc_readCalendar">"Pozwala aplikacji na odczytywanie wszystkich wydarzeń z kalendarza, zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do rozsyłania wydarzeń z kalendarza do innych ludzi."</string>
+ <string name="permlab_writeCalendar">"zapisywanie danych kalendarza"</string>
+ <string name="permdesc_writeCalendar">"Pozwala aplikacji na zmianę wydarzeń z kalendarza zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane w kalendarzu."</string>
+ <string name="permlab_accessMockLocation">"udawanie źródeł położenia dla testów"</string>
+ <string name="permdesc_accessMockLocation">"Tworzenie pozorowanych źródeł ustalania położenia dla testów. Szkodliwe aplikacje mogą to wykorzystać, aby zastąpić prawdziwe położenie i/lub stan zwracany przez prawdziwe źródła, takie jak GPS lub dostawcy usługi sieciowej."</string>
+ <string name="permlab_accessLocationExtraCommands">"dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji. Szkodliwe aplikacje mogą go wykorzystać, aby wpływać na działanie urządzenia GPS lub innych źródeł ustalania lokalizacji."</string>
+ <string name="permlab_installLocationProvider">"uprawnienia do instalowania dostawcy danych o lokalizacji"</string>
+ <string name="permdesc_installLocationProvider">"Utwórz sztuczne źródła danych o lokalizacji na potrzeby testowania. Złośliwe aplikacje mogą korzystać z tej opcji w celu zastępowania danych o lokalizacji i/lub stanie zwracanych przez prawdziwe źródła danych o lokalizacji, takie jak odbiornik GPS lub dostawcy sieciowi, bądź monitorowania i zgłaszania lokalizacji do źródeł zewnętrznych."</string>
+ <string name="permlab_accessFineLocation">"dokładna lokalizacja (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Uzyskiwanie dostępu do dokładnych źródeł ustalania położenia w telefonie, takich jak system GPS, tam, gdzie są one dostępne. Szkodliwe aplikacje mogą to wykorzystać do określenia położenia użytkownika oraz mogą zużywać więcej energii baterii."</string>
+ <string name="permlab_accessCoarseLocation">"przybliżone ustalanie lokalizacji (oparte o sieć)"</string>
+ <string name="permdesc_accessCoarseLocation">"Dostęp do źródeł, takich jak bazy danych sieci komórkowych, jeśli są dostępne, które pozwalają określić przybliżoną lokalizację telefonu. Szkodliwe aplikacje mogą go wykorzystać do określenia, gdzie w przybliżeniu znajduje się użytkownik."</string>
+ <string name="permlab_accessSurfaceFlinger">"dostęp do usługi SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"czytanie bufora ramki"</string>
+ <string name="permdesc_readFrameBuffer">"Pozwala aplikacji na wykorzystanie odczytanej zawartości bufora ramki."</string>
+ <string name="permlab_modifyAudioSettings">"zmienianie ustawień audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Pozwala aplikacjom na zmianę globalnych ustawień audio, takich jak głośność i routing."</string>
+ <string name="permlab_recordAudio">"nagrywanie dźwięku"</string>
+ <string name="permdesc_recordAudio">"Pozwala aplikacji na dostęp do ścieżki nagrywania dźwięku."</string>
+ <string name="permlab_camera">"robienie zdjęć"</string>
+ <string name="permdesc_camera">"Pozwala aplikacji na wykonywanie zdjęć za pomocą aparatu. Dzięki temu może ona pobierać zdjęcia z aparatu w dowolnym momencie."</string>
+ <string name="permlab_brick">"wyłączenie telefonu na stałe"</string>
+ <string name="permdesc_brick">"Pozwala aplikacji na wyłączenie całego telefonu na stałe. Jest to bardzo niebezpieczne."</string>
+ <string name="permlab_reboot">"wymuszanie ponownego uruchomienia telefonu"</string>
+ <string name="permdesc_reboot">"Pozwala aplikacji na wymuszenie ponownego uruchomienia telefonu."</string>
+ <string name="permlab_mount_unmount_filesystems">"podłączanie i odłączanie systemów plików"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Pozwala aplikacjom na podłączanie i odłączanie systemów plików w pamięciach przenośnych."</string>
+ <string name="permlab_mount_format_filesystems">"formatowanie pamięci zewnętrznej"</string>
+ <string name="permdesc_mount_format_filesystems">"Zezwala aplikacji na formatowanie wymiennych nośników."</string>
+ <string name="permlab_vibrate">"kontrolowanie wibracji"</string>
+ <string name="permdesc_vibrate">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
+ <string name="permlab_flashlight">"kontrolowanie latarki"</string>
+ <string name="permdesc_flashlight">"Pozwala aplikacji kontrolować latarkę."</string>
+ <string name="permlab_hardware_test">"testowanie sprzętu"</string>
+ <string name="permdesc_hardware_test">"Pozwala aplikacji na kontrolowanie różnych urządzeń peryferyjnych w celu testowania sprzętu."</string>
+ <string name="permlab_callPhone">"bezpośrednie wybieranie numerów telefonów"</string>
+ <string name="permdesc_callPhone">"Pozwala aplikacjom na dzwonienie pod numery telefonów bez interwencji użytkownika. Szkodliwe aplikacje mogą powodować występowanie niespodziewanych połączeń na rachunku telefonicznym. Należy zauważyć, że aplikacje nie mogą dzwonić na numery alarmowe."</string>
+ <string name="permlab_callPrivileged">"bezpośrednie wybieranie dowolnych numerów telefonu"</string>
+ <string name="permdesc_callPrivileged">"Pozwala aplikacji dzwonić na dowolny numer telefonu, włącznie z numerami alarmowymi, bez interwencji użytkownika. Szkodliwe aplikacje mogą wykonywać niepotrzebne i nielegalne połączenia z usługami alarmowymi."</string>
+ <string name="permlab_locationUpdates">"kontrolowanie powiadomień o aktualizacjach lokalizacji"</string>
+ <string name="permdesc_locationUpdates">"Pozwala włączyć/wyłączyć powiadomienia o aktualizacjach lokalizacji przez sieć bezprzewodową. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_checkinProperties">"dostęp do właściwości usługi rezerwacji"</string>
+ <string name="permdesc_checkinProperties">"Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_bindGadget">"wybieranie widżetów"</string>
+ <string name="permdesc_bindGadget">"Zezwala aplikacjom na wskazywanie systemowi, które widżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji."</string>
+ <string name="permlab_modifyPhoneState">"zmiana stanu telefonu"</string>
+ <string name="permdesc_modifyPhoneState">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
+ <string name="permlab_readPhoneState">"czytanie stanu telefonu"</string>
+ <string name="permdesc_readPhoneState">"Pozwala aplikacji na dostęp do funkcji telefonu w urządzeniu. Aplikacja z takim uprawnieniem może określić numer tego telefonu, czy jest nawiązane połączenie, numer, z którym jest ono nawiązane, itp."</string>
+ <string name="permlab_wakeLock">"zapobieganie przejściu telefonu w stan uśpienia"</string>
+ <string name="permdesc_wakeLock">"Pozwala aplikacji na zapobieganie przejściu telefonu w stan uśpienia."</string>
+ <string name="permlab_devicePower">"włączanie lub wyłączanie telefonu"</string>
+ <string name="permdesc_devicePower">"Pozwala aplikacji włączać i wyłączać telefon."</string>
+ <string name="permlab_factoryTest">"uruchamianie w trybie testu fabrycznego"</string>
+ <string name="permdesc_factoryTest">"Uruchom jako niskopoziomowy test producenta, pozwalając na całkowity dostęp do elementów sprzętowych telefonu. Dostępne tylko jeśli telefon działa w trybie testu producenta."</string>
+ <string name="permlab_setWallpaper">"ustawianie tapety"</string>
+ <string name="permdesc_setWallpaper">"Pozwala aplikacji na ustawianie tapety systemu."</string>
+ <string name="permlab_setWallpaperHints">"ustawianie wskazówek dotyczących rozmiaru tapety"</string>
+ <string name="permdesc_setWallpaperHints">"Pozwala aplikacji na ustawianie wskazówek dotyczących rozmiaru tapety."</string>
+ <string name="permlab_masterClear">"resetowanie systemu do ustawień fabrycznych"</string>
+ <string name="permdesc_masterClear">"Pozwala aplikacji na całkowite zresetowanie systemu do ustawień fabrycznych, z wymazaniem wszystkich danych, konfiguracji oraz zainstalowanych aplikacji."</string>
+ <string name="permlab_setTimeZone">"ustawianie strefy czasowej"</string>
+ <string name="permdesc_setTimeZone">"Pozwala aplikacji na zmianę strefy czasowej w telefonie."</string>
+ <string name="permlab_getAccounts">"wykrywanie znanych kont"</string>
+ <string name="permdesc_getAccounts">"Pozwala aplikacji na pobranie listy kont zapisanych w telefonie."</string>
+ <string name="permlab_accessNetworkState">"wyświetlanie stanu sieci"</string>
+ <string name="permdesc_accessNetworkState">"Pozwala aplikacji na wyświetlanie stanu wszystkich sieci."</string>
+ <string name="permlab_createNetworkSockets">"pełen dostęp do internetu"</string>
+ <string name="permdesc_createNetworkSockets">"Pozwala aplikacji na tworzenie gniazd sieciowych."</string>
+ <string name="permlab_writeApnSettings">"zapisywanie ustawień nazwy punktu dostępowego (APN, Access Point Name)"</string>
+ <string name="permdesc_writeApnSettings">"Pozwala aplikacji na zmianę ustawień APN, takich jak serwer proxy oraz port dowolnego APN."</string>
+ <string name="permlab_changeNetworkState">"zmienianie połączeń sieci"</string>
+ <string name="permdesc_changeNetworkState">"Pozwala aplikacji na zmianę stanu połączeń sieciowych."</string>
+ <string name="permlab_changeBackgroundDataSetting">"zmienianie ustawienia używania danych w tle"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Zezwala aplikacji na zmianę ustawień użycia danych w tle."</string>
+ <string name="permlab_accessWifiState">"wyświetlanie stanu Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Pozwala aplikacji na wyświetlanie informacji o stanie Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"zmiana stanu Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Pozwala aplikacji na łączenie i rozłączanie z punktami dostępowymi Wi-Fi oraz na dokonywanie zmian skonfigurowanych sieci Wi-Fi."</string>
+ <string name="permlab_changeWifiMulticastState">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Umożliwia aplikacji odbieranie pakietów nieskierowanych bezpośrednio do Twojego urządzenia. Może to być przydatne przy wykrywaniu usług oferowanych w okolicy. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
+ <string name="permlab_bluetoothAdmin">"administrowanie Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Pozwala aplikacji na konfigurowanie lokalnego telefonu Bluetooth, wyszukiwanie urządzeń zdalnych i łączenie się z nimi."</string>
+ <string name="permlab_bluetooth">"tworzenie połączeń Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Pozwala aplikacji na wyświetlanie konfiguracji lokalnego telefonu Bluetooth oraz na tworzenie i akceptowanie połączeń ze sparowanymi urządzeniami."</string>
+ <string name="permlab_disableKeyguard">"wyłączanie blokady klawiatury"</string>
+ <string name="permdesc_disableKeyguard">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Typowym przykładem takiego działania jest wyłączanie blokady klawiatury, gdy pojawia się połączenie przychodzące, a następnie ponowne jej włączanie po zakończeniu połączenia."</string>
+ <string name="permlab_readSyncSettings">"czytanie ustawień synchronizowania"</string>
+ <string name="permdesc_readSyncSettings">"Pozwala aplikacji na czytanie ustawień synchronizacji, takich jak informacje, czy synchronizacja kontaktów jest włączona."</string>
+ <string name="permlab_writeSyncSettings">"zapisywanie ustawień synchronizowania"</string>
+ <string name="permdesc_writeSyncSettings">"Pozwala aplikacji na zmianę ustawień synchronizowania, takich jak ustalenie, czy synchronizacja dla kontaktów ma być włączona."</string>
+ <string name="permlab_readSyncStats">"czytanie statystyk dotyczących synchronizowania"</string>
+ <string name="permdesc_readSyncStats">"Pozwala aplikacji na czytanie statystyk synchronizowania, np. historii przeprowadzonych synchronizacji."</string>
+ <string name="permlab_subscribedFeedsRead">"czytanie subskrybowanych źródeł"</string>
+ <string name="permdesc_subscribedFeedsRead">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
+ <string name="permlab_subscribedFeedsWrite">"zapisywanie subskrybowanych źródeł"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
+ <string name="permlab_readDictionary">"odczytywanie słownika zdefiniowanego przez użytkownika"</string>
+ <string name="permdesc_readDictionary">"Zezwala aplikacji na odczytywanie wszelkich prywatnych słów, nazw i wyrażeń zapisanych przez użytkownika w swoim słowniku."</string>
+ <string name="permlab_writeDictionary">"zapisywanie w słowniku zdefiniowanym przez użytkownika"</string>
+ <string name="permdesc_writeDictionary">"Zezwala aplikacjom na zapisywanie nowych słów w słowniku użytkownika."</string>
+ <string name="permlab_sdcardWrite">"modyfikowanie/usuwanie zawartości karty SD"</string>
+ <string name="permdesc_sdcardWrite">"Umożliwia aplikacji zapis na karcie SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Dom"</item>
- <item msgid="869923650527136615">"Komórka"</item>
- <item msgid="7897544654242874543">"Praca"</item>
- <item msgid="1103601433382158155">"Faks w pracy"</item>
- <item msgid="1735177144948329370">"Faks domowy"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Inny"</item>
- <item msgid="9192514806975898961">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Komórka"</item>
+ <item>"Praca"</item>
+ <item>"Faks w pracy"</item>
+ <item>"Faks domowy"</item>
+ <item>"Pager"</item>
+ <item>"Inny"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Dom"</item>
- <item msgid="7084237356602625604">"Praca"</item>
- <item msgid="1112044410659011023">"Inne"</item>
- <item msgid="2374913952870110618">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Komórka"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Dom"</item>
- <item msgid="5629153956045109251">"Praca"</item>
- <item msgid="4966604264500343469">"Inny"</item>
- <item msgid="4932682847595299369">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inny"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Dom"</item>
- <item msgid="1359644565647383708">"Praca"</item>
- <item msgid="7868549401053615677">"Inne"</item>
- <item msgid="3145118944639869809">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Praca"</item>
- <item msgid="4378074129049520373">"Inne"</item>
- <item msgid="3455047468583965104">"Niestandardowy"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Wprowadź kod PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Błędny kod PIN!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numer alarmowy"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Brak usługi)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran zablokowany."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Naciśnij Menu, aby odblokować."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Narysuj wzór, aby odblokować"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Połączenie alarmowe"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Poprawnie!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Niestety, spróbuj ponownie"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Naładowany."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Podłącz ładowarkę."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Brak karty SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Brak karty SIM w telefonie."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Włóż kartę SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Sieć zablokowana"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Karta SIM jest zablokowana kodem PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Zapoznaj się z instrukcją obsługi lub skontaktuj się z działem obsługi klienta."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM jest zablokowana."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokowywanie karty SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> sekund."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomniałeś wzoru?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Zbyt wiele prób narysowania wzoru!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Aby odblokować, zaloguj się za pomocą konta Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nazwa użytkownika (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Hasło"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Zaloguj"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Błędna nazwa użytkownika lub hasło."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wyczyść"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Ładowanie..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Podłącz ładowarkę"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Bateria się rozładowuje:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"pozostało mniej niż <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Dlaczego?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Nieudany test fabryczny"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Uruchom ponownie"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wybierz opcję OK, aby kontynuować, lub opcję Anuluj, aby pozostać na tej stronie."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"odczyt historii i zakładek przeglądarki"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umożliwia aplikacji odczyt wszystkich adresów URL odwiedzonych przez przeglądarkę, a także wszystkich zakładek przeglądarki."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"zapis historii i zakładek przeglądarki"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Umożliwia aplikacji modyfikowanie historii lub zakładek przeglądarki zapisanych w telefonie. Złośliwe aplikacje mogą używać tej opcji do usuwania lub modyfikowania danych przeglądarki."</string>
- <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nigdy"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Brak uprawnień do otwierania tej strony."</string>
- <string name="text_copied" msgid="4985729524670131385">"Tekst został skopiowany do schowka."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Więcej"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spacja"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"usuń"</string>
- <string name="search_go" msgid="8298016669822141719">"Szukaj"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
+ <string name="keyguard_password_enter_pin_code">"Wprowadź kod PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Błędny kod PIN!"</string>
+ <string name="keyguard_label_text">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numer alarmowy"</string>
+ <string name="lockscreen_carrier_default">"(Brak usługi)"</string>
+ <string name="lockscreen_screen_locked">"Ekran zablokowany."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Naciśnij Menu, aby odblokować."</string>
+ <string name="lockscreen_pattern_instructions">"Narysuj wzór, aby odblokować"</string>
+ <string name="lockscreen_emergency_call">"Połączenie alarmowe"</string>
+ <string name="lockscreen_pattern_correct">"Poprawnie!"</string>
+ <string name="lockscreen_pattern_wrong">"Niestety, spróbuj ponownie"</string>
+ <string name="lockscreen_plugged_in">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Podłącz ładowarkę."</string>
+ <string name="lockscreen_missing_sim_message_short">"Brak karty SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Brak karty SIM w telefonie."</string>
+ <string name="lockscreen_missing_sim_instructions">"Włóż kartę SIM."</string>
+ <string name="lockscreen_network_locked_message">"Sieć zablokowana"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Karta SIM jest zablokowana kodem PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Zapoznaj się z instrukcją obsługi lub skontaktuj się z działem obsługi klienta."</string>
+ <string name="lockscreen_sim_locked_message">"Karta SIM jest zablokowana."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Odblokowywanie karty SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Zapomniałeś wzoru?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Zbyt wiele prób narysowania wzoru!"</string>
+ <string name="lockscreen_glogin_instructions">"Aby odblokować, zaloguj się za pomocą konta Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nazwa użytkownika (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Hasło"</string>
+ <string name="lockscreen_glogin_submit_button">"Zaloguj"</string>
+ <string name="lockscreen_glogin_invalid_input">"Błędna nazwa użytkownika lub hasło."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Brak powiadomień"</string>
+ <string name="status_bar_ongoing_events_title">"Bieżące"</string>
+ <string name="status_bar_latest_events_title">"Powiadomienia"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Ładowanie..."</string>
+ <string name="battery_low_title">"Podłącz ładowarkę"</string>
+ <string name="battery_low_subtitle">"Bateria się rozładowuje:"</string>
+ <string name="battery_low_percent_format">"pozostało mniej niż <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Dlaczego?"</string>
+ <string name="factorytest_failed">"Nieudany test fabryczny"</string>
+ <string name="factorytest_not_system">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
+ <string name="factorytest_no_action">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Uruchom ponownie"</string>
+ <string name="js_dialog_title">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wybierz opcję OK, aby kontynuować, lub opcję Anuluj, aby pozostać na tej stronie."</string>
+ <string name="save_password_label">"Potwierdź"</string>
+ <string name="permlab_readHistoryBookmarks">"odczyt historii i zakładek przeglądarki"</string>
+ <string name="permdesc_readHistoryBookmarks">"Umożliwia aplikacji odczyt wszystkich adresów URL odwiedzonych przez przeglądarkę, a także wszystkich zakładek przeglądarki."</string>
+ <string name="permlab_writeHistoryBookmarks">"zapis historii i zakładek przeglądarki"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Umożliwia aplikacji modyfikowanie historii lub zakładek przeglądarki zapisanych w telefonie. Złośliwe aplikacje mogą używać tej opcji do usuwania lub modyfikowania danych przeglądarki."</string>
+ <string name="save_password_message">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
+ <string name="save_password_notnow">"Nie teraz"</string>
+ <string name="save_password_remember">"Zapamiętaj"</string>
+ <string name="save_password_never">"Nigdy"</string>
+ <string name="open_permission_deny">"Brak uprawnień do otwierania tej strony."</string>
+ <string name="text_copied">"Tekst został skopiowany do schowka."</string>
+ <string name="more_item_label">"Więcej"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"spacja"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"usuń"</string>
+ <string name="search_go">"Szukaj"</string>
+ <string name="oneMonthDurationPast">"1 miesiąc temu"</string>
+ <string name="beforeOneMonthDurationPast">"Ponad 1 miesiąc temu"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"sekundę temu"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekund temu"</item>
+ <item quantity="one">"sekundę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sekund temu"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minutę temu"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minut temu"</item>
+ <item quantity="one">"1 minutę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minut temu"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"godzinę temu"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> godzin temu"</item>
+ <item quantity="one">"godzinę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> godzin temu"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"wczoraj"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
+ <item quantity="one">"wczoraj"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za sekundę"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
+ <item quantity="one">"za sekundę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za minutę"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> minut"</item>
+ <item quantity="one">"za minutę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> minut"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za godzinę"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
+ <item quantity="one">"za godzinę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"jutro"</item>
- <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
+ <item quantity="one">"jutro"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"sekundę temu"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
+ <item quantity="one">"sekundę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"minutę temu"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
+ <item quantity="one">"minutę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"godzinę temu"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
+ <item quantity="one">"godzinę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"wczoraj"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
+ <item quantity="one">"wczoraj"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za sekundę"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ <item quantity="one">"za sekundę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za minutę"</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"za minutę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za godzinę"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
+ <item quantity="one">"za godzinę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"jutro"</item>
- <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
+ <item quantity="one">"jutro"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"dnia %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"o %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"w %s"</string>
- <string name="day" msgid="8144195776058119424">"dzień"</string>
- <string name="days" msgid="4774547661021344602">"dni"</string>
- <string name="hour" msgid="2126771916426189481">"godzina"</string>
- <string name="hours" msgid="894424005266852993">"godzin"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minut"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"S"</string>
- <string name="week" msgid="5617961537173061583">"tydzień"</string>
- <string name="weeks" msgid="6509623834583944518">"tygodni"</string>
- <string name="year" msgid="4001118221013892076">"rok"</string>
- <string name="years" msgid="6881577717993213522">"lat"</string>
- <string name="every_weekday" msgid="8777593878457748503">"W każdy dzień roboczy (pon–pt)"</string>
- <string name="daily" msgid="5738949095624133403">"Codziennie"</string>
- <string name="weekly" msgid="983428358394268344">"Co tydzień w <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Miesięcznie"</string>
- <string name="yearly" msgid="1519577999407493836">"Co roku"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Nie można odtworzyć filmu wideo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Przepraszamy, ten film wideo nie nadaje się do przesyłania strumieniowego do tego urządzenia."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Niestety, nie można odtworzyć tego filmu wideo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"południe"</string>
- <string name="Noon" msgid="3342127745230013127">"Południe"</string>
- <string name="midnight" msgid="7166259508850457595">"północ"</string>
- <string name="Midnight" msgid="5630806906897892201">"Północ"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string>
- <string name="selectText" msgid="3889149123626888637">"Zaznacz tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zatrzymaj wybieranie tekstu"</string>
- <string name="cut" msgid="3092569408438626261">"Wytnij"</string>
- <string name="cutAll" msgid="2436383270024931639">"Wytnij wszystko"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopiuj wszystko"</string>
- <string name="paste" msgid="5629880836805036433">"Wklej"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopiuj adres URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Wprowadzanie tekstu"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Dodaj „%s” do słownika"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Edytuj tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Mało miejsca"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Maleje ilość dostępnej pamięci telefonu."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Anuluj"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Uwaga"</string>
- <string name="capital_on" msgid="1544682755514494298">"Włącz"</string>
- <string name="capital_off" msgid="6815870386972805832">"Wyłącz"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Zakończ czynność korzystając z"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Używaj domyślnie dla tej czynności."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wyczyść domyślne w: Ustawienia strony głównej > Aplikacje > Zarządzaj aplikacjami."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Wybierz czynność"</string>
- <string name="noApplications" msgid="1691104391758345586">"Żadna z aplikacji nie może wykonać tej czynności."</string>
- <string name="aerr_title" msgid="653922989522758100">"Przepraszamy!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> został niespodziewanie zatrzymany. Spróbuj ponownie."</string>
- <string name="anr_title" msgid="3100070910664756057">"Przepraszamy!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."</string>
- <string name="force_close" msgid="3653416315450806396">"Wymuś zamknięcie"</string>
- <string name="report" msgid="4060218260984795706">"Zgłoś"</string>
- <string name="wait" msgid="7147118217226317732">"Czekaj"</string>
- <string name="debug" msgid="9103374629678531849">"Debuguj"</string>
- <string name="sendText" msgid="5132506121645618310">"Jak wysłać tekst?"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Głośność dzwonka"</string>
- <string name="volume_music" msgid="5421651157138628171">"Głośność multimediów"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Odtwarzanie przez Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Głośność podczas połączenia"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Głośność Bluetooth w czasie połączenia"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Głośność alarmu"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Głośność powiadomienia"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Głośność"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Cichy"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Nieznany dzwonek"</string>
+ <string name="preposition_for_date">"dnia %s"</string>
+ <string name="preposition_for_time">"o %s"</string>
+ <string name="preposition_for_year">"w %s"</string>
+ <string name="day">"dzień"</string>
+ <string name="days">"dni"</string>
+ <string name="hour">"godzina"</string>
+ <string name="hours">"godzin"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minut"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"S"</string>
+ <string name="week">"tydzień"</string>
+ <string name="weeks">"tygodni"</string>
+ <string name="year">"rok"</string>
+ <string name="years">"lat"</string>
+ <string name="every_weekday">"W każdy dzień roboczy (pon–pt)"</string>
+ <string name="daily">"Codziennie"</string>
+ <string name="weekly">"Co tydzień w <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Miesięcznie"</string>
+ <string name="yearly">"Co roku"</string>
+ <string name="VideoView_error_title">"Nie można odtworzyć filmu wideo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Przepraszamy, ten film wideo nie nadaje się do przesyłania strumieniowego do tego urządzenia."</string>
+ <string name="VideoView_error_text_unknown">"Niestety, nie można odtworzyć tego filmu wideo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"południe"</string>
+ <string name="Noon">"Południe"</string>
+ <string name="midnight">"północ"</string>
+ <string name="Midnight">"Północ"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Zaznacz wszystko"</string>
+ <string name="selectText">"Zaznacz tekst"</string>
+ <string name="stopSelectingText">"Zatrzymaj wybieranie tekstu"</string>
+ <string name="cut">"Wytnij"</string>
+ <string name="cutAll">"Wytnij wszystko"</string>
+ <string name="copy">"Kopiuj"</string>
+ <string name="copyAll">"Kopiuj wszystko"</string>
+ <string name="paste">"Wklej"</string>
+ <string name="copyUrl">"Kopiuj adres URL"</string>
+ <string name="inputMethod">"Wprowadzanie tekstu"</string>
+ <string name="addToDictionary">"Dodaj „%s” do słownika"</string>
+ <string name="editTextMenuTitle">"Edytuj tekst"</string>
+ <string name="low_internal_storage_view_title">"Mało miejsca"</string>
+ <string name="low_internal_storage_view_text">"Maleje ilość dostępnej pamięci telefonu."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Anuluj"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Anuluj"</string>
+ <string name="dialog_alert_title">"Uwaga"</string>
+ <string name="capital_on">"Włącz"</string>
+ <string name="capital_off">"Wyłącz"</string>
+ <string name="whichApplication">"Zakończ czynność korzystając z"</string>
+ <string name="alwaysUse">"Używaj domyślnie dla tej czynności."</string>
+ <string name="clearDefaultHintMsg">"Wyczyść domyślne w: Ustawienia strony głównej > Aplikacje > Zarządzaj aplikacjami."</string>
+ <string name="chooseActivity">"Wybierz czynność"</string>
+ <string name="noApplications">"Żadna z aplikacji nie może wykonać tej czynności."</string>
+ <string name="aerr_title">"Przepraszamy!"</string>
+ <string name="aerr_application">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
+ <string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> został niespodziewanie zatrzymany. Spróbuj ponownie."</string>
+ <string name="anr_title">"Przepraszamy!"</string>
+ <string name="anr_activity_application">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_activity_process">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_application_process">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."</string>
+ <string name="force_close">"Wymuś zamknięcie"</string>
+ <string name="report">"Zgłoś"</string>
+ <string name="wait">"Czekaj"</string>
+ <string name="debug">"Debuguj"</string>
+ <string name="sendText">"Jak wysłać tekst?"</string>
+ <string name="volume_ringtone">"Głośność dzwonka"</string>
+ <string name="volume_music">"Głośność multimediów"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Odtwarzanie przez Bluetooth"</string>
+ <string name="volume_call">"Głośność podczas połączenia"</string>
+ <string name="volume_bluetooth_call">"Głośność Bluetooth w czasie połączenia"</string>
+ <string name="volume_alarm">"Głośność alarmu"</string>
+ <string name="volume_notification">"Głośność powiadomienia"</string>
+ <string name="volume_unknown">"Głośność"</string>
+ <string name="ringtone_default">"Dzwonek domyślny"</string>
+ <string name="ringtone_default_with_actual">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Cichy"</string>
+ <string name="ringtone_picker_title">"Dzwonki"</string>
+ <string name="ringtone_unknown">"Nieznany dzwonek"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Sieć Wi-Fi jest dostępna"</item>
- <item quantity="other" msgid="4192424489168397386">"Dostępne sieci Wi-Fi"</item>
+ <item quantity="one">"Sieć Wi-Fi jest dostępna"</item>
+ <item quantity="other">"Dostępne sieci Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Otwórz dostępne sieci Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Otwórz dostępne sieci Wi-Fi"</item>
+ <item quantity="one">"Otwórz dostępne sieci Wi-Fi"</item>
+ <item quantity="other">"Otwórz dostępne sieci Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Nieznana aplikacja"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Wysyłana jest duża liczba wiadomości SMS. Wybierz „OK”, aby kontynuować, lub „Anuluj”, aby zatrzymać wysyłanie."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Anuluj"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ustaw"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Domyślne"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ukryj"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Pokaż wszystko"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Ładowanie..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Połączenie przez USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Telefon został podłączony do komputera przez port USB. Wybierz polecenie „Podłącz”, jeśli chcesz skopiować pliki między komputerem a kartą SD w telefonie."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Podłącz"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nie podłączaj"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Wystąpił problem z wykorzystaniem karty SD dla pamięci USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Połączenie przez USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Wybierz, aby skopiować pliki do/z komputera"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Wyłącz nośnik USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Wybierz, aby wyłączyć nośnik USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Wyłącz nośnik USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Przed wyłączeniem nośnika USB upewnij się, że odłączono go od hosta USB. Wybierz „Wyłącz”, aby wyłączyć nośnik USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Wyłącz"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Anuluj"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Napotkano problem przy wyłączaniu nośnika USB. Sprawdź, czy host USB został odłączony i spróbuj ponownie."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatuj kartę SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Czy na pewno sformatować kartę SD? Wszystkie dane na karcie zostaną utracone."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatuj"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Komputer jest połączony z telefonem."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Sposób wprowadzania tekstu"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Przygotowywanie karty SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Sprawdzanie w poszukiwaniu błędów."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Pusta karta SD"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Karta SD jest pusta lub zawiera nieobsługiwany system plików."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Uszkodzona karta SD"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Karta SD jest uszkodzona. Konieczne może być ponowne sformatowanie."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Karta SD została nieoczekiwanie wyjęta"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Odłącz kartę SD przed jej wyjęciem, aby uniknąć utraty danych."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Można bezpiecznie usunąć kartę SD"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Możesz bezpiecznie wyjąć kartę SD."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Usunięta karta SD"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Karta SD została wyjęta. Włóż nową kartę."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nie znaleziono pasujących działań"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aktualizowanie statystyk użycia komponentu"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Zezwala na modyfikacje zebranych statystyk użycia komponentu. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Błąd podczas wyodrębniania widżetu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Przejdź"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Szukaj"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Wyślij"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Dalej"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Gotowe"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Wykonaj"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Połącz"\n"z numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Utwórz kontakt"\n"dla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"zaznaczone"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"niezaznaczone"</string>
+ <string name="select_character">"Wstaw znak"</string>
+ <string name="sms_control_default_app_name">"Nieznana aplikacja"</string>
+ <string name="sms_control_title">"Wysyłanie wiadomości SMS"</string>
+ <string name="sms_control_message">"Wysyłana jest duża liczba wiadomości SMS. Wybierz „OK”, aby kontynuować, lub „Anuluj”, aby zatrzymać wysyłanie."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Anuluj"</string>
+ <string name="date_time_set">"Ustaw"</string>
+ <string name="default_permission_group">"Domyślne"</string>
+ <string name="no_permissions">"Nie są wymagane żadne uprawnienia"</string>
+ <string name="perms_hide"><b>"Ukryj"</b></string>
+ <string name="perms_show_all"><b>"Pokaż wszystko"</b></string>
+ <string name="googlewebcontenthelper_loading">"Ładowanie..."</string>
+ <string name="usb_storage_title">"Połączenie przez USB"</string>
+ <string name="usb_storage_message">"Telefon został podłączony do komputera przez port USB. Wybierz polecenie „Podłącz”, jeśli chcesz skopiować pliki między komputerem a kartą SD w telefonie."</string>
+ <string name="usb_storage_button_mount">"Podłącz"</string>
+ <string name="usb_storage_button_unmount">"Nie podłączaj"</string>
+ <string name="usb_storage_error_message">"Wystąpił problem z wykorzystaniem karty SD dla pamięci USB."</string>
+ <string name="usb_storage_notification_title">"Połączenie przez USB"</string>
+ <string name="usb_storage_notification_message">"Wybierz, aby skopiować pliki do/z komputera"</string>
+ <string name="usb_storage_stop_notification_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_notification_message">"Wybierz, aby wyłączyć nośnik USB."</string>
+ <string name="usb_storage_stop_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_message">"Przed wyłączeniem nośnika USB upewnij się, że odłączono go od hosta USB. Wybierz „Wyłącz”, aby wyłączyć nośnik USB."</string>
+ <string name="usb_storage_stop_button_mount">"Wyłącz"</string>
+ <string name="usb_storage_stop_button_unmount">"Anuluj"</string>
+ <string name="usb_storage_stop_error_message">"Napotkano problem przy wyłączaniu nośnika USB. Sprawdź, czy host USB został odłączony i spróbuj ponownie."</string>
+ <string name="extmedia_format_title">"Formatuj kartę SD"</string>
+ <string name="extmedia_format_message">"Czy na pewno sformatować kartę SD? Wszystkie dane na karcie zostaną utracone."</string>
+ <string name="extmedia_format_button_format">"Formatuj"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Sposób wprowadzania tekstu"</string>
+ <string name="fast_scroll_alphabet">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandydaci"</u></string>
+ <string name="ext_media_checking_notification_title">"Przygotowywanie karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Sprawdzanie w poszukiwaniu błędów."</string>
+ <string name="ext_media_nofs_notification_title">"Pusta karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD jest pusta lub zawiera nieobsługiwany system plików."</string>
+ <string name="ext_media_unmountable_notification_title">"Uszkodzona karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD jest uszkodzona. Konieczne może być ponowne sformatowanie."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD została nieoczekiwanie wyjęta"</string>
+ <string name="ext_media_badremoval_notification_message">"Odłącz kartę SD przed jej wyjęciem, aby uniknąć utraty danych."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Można bezpiecznie usunąć kartę SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Możesz bezpiecznie wyjąć kartę SD."</string>
+ <string name="ext_media_nomedia_notification_title">"Usunięta karta SD"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD została wyjęta. Włóż nową kartę."</string>
+ <string name="activity_list_empty">"Nie znaleziono pasujących działań"</string>
+ <string name="permlab_pkgUsageStats">"aktualizowanie statystyk użycia komponentu"</string>
+ <string name="permdesc_pkgUsageStats">"Zezwala na modyfikacje zebranych statystyk użycia komponentu. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
+ <string name="gadget_host_error_inflating">"Błąd podczas wyodrębniania widżetu"</string>
+ <string name="ime_action_go">"Przejdź"</string>
+ <string name="ime_action_search">"Szukaj"</string>
+ <string name="ime_action_send">"Wyślij"</string>
+ <string name="ime_action_next">"Dalej"</string>
+ <string name="ime_action_done">"Gotowe"</string>
+ <string name="ime_action_default">"Wykonaj"</string>
+ <string name="dial_number_using">"Połącz"\n"z numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Utwórz kontakt"\n"dla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"zaznaczone"</string>
+ <string name="accessibility_compound_button_unselected">"niezaznaczone"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a6ab576..5b75aad 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<sem título>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconhecido)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de ligação ou código MMI inválido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"O serviço foi activado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"O serviço foi activado para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"O serviço foi desactivado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"O registo foi bem sucedido."</string>
- <string name="serviceErased" msgid="1288584695297200972">"A eliminação foi bem sucedida."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Palavra-passe incorrecta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI concluído."</string>
- <string name="badPin" msgid="5085454289896032547">"O PIN antigo que introduziu não está correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"O PUK que introduziu não está correcto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Os PINs que introduziu não coincidem."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Introduza um PIN entre 4 e 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID do Autor da Chamada"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efectuada"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamadas"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Barramento de chamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Alteração de palavra-passe"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Alteração de PIN"</string>
+ <string name="untitled">"<sem título>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nenhum número de telefone)"</string>
+ <string name="unknownName">"(Desconhecido)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correio de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de ligação ou código MMI inválido."</string>
+ <string name="serviceEnabled">"O serviço foi activado."</string>
+ <string name="serviceEnabledFor">"O serviço foi activado para:"</string>
+ <string name="serviceDisabled">"O serviço foi desactivado."</string>
+ <string name="serviceRegistered">"O registo foi bem sucedido."</string>
+ <string name="serviceErased">"A eliminação foi bem sucedida."</string>
+ <string name="passwordIncorrect">"Palavra-passe incorrecta."</string>
+ <string name="mmiComplete">"MMI concluído."</string>
+ <string name="badPin">"O PIN antigo que introduziu não está correcto."</string>
+ <string name="badPuk">"O PUK que introduziu não está correcto."</string>
+ <string name="mismatchPin">"Os PINs que introduziu não coincidem."</string>
+ <string name="invalidPin">"Introduza um PIN entre 4 e 8 números."</string>
+ <string name="needPuk">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
+ <string name="ClipMmi">"ID do Autor da Chamada"</string>
+ <string name="ClirMmi">"ID do autor da chamada efectuada"</string>
+ <string name="CfMmi">"Encaminhamento de chamadas"</string>
+ <string name="CwMmi">"Chamada em espera"</string>
+ <string name="BaMmi">"Barramento de chamadas"</string>
+ <string name="PwdMmi">"Alteração de palavra-passe"</string>
+ <string name="PinMmi">"Alteração de PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID do autor da chamada é predefinido como não restrito. Chamada seguinte: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Serviço não fornecido."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Não é possível mudar o ID do autor da chamada."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito modificado"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"O serviço de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos os serviços de voz/SMS estão bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dados"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Assíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronização"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacote"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn">"ID do autor da chamada é predefinido como não restrito. Chamada seguinte: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
+ <string name="serviceNotProvisioned">"Serviço não fornecido."</string>
+ <string name="CLIRPermanent">"Não é possível mudar o ID do autor da chamada."</string>
+ <string name="RestrictedChangedTitle">"Acesso restrito modificado"</string>
+ <string name="RestrictedOnData">"O serviço de dados está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"O serviço de emergência está bloqueado."</string>
+ <string name="RestrictedOnNormal">"O serviço de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos os serviços de voz/SMS estão bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Dados"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Assíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronização"</string>
+ <string name="serviceClassPacket">"Pacote"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"A página Web contém um erro."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Não foi possível localizar o URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"O esquema de autenticação do site não é suportado."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"A autenticação falhou."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"A autenticação através do servidor proxy falhou."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Não foi possível estabelecer a ligação ao servidor."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"O servidor falhou ao comunicar. Tente novamente mais tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Esgotou o tempo limite da ligação ao servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"A página contém demasiados redireccionamentos do servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"O protocolo não é suportado."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Não foi possível estabelecer uma ligação segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Não foi possível abrir a página porque o URL é inválido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Não foi possível aceder ao ficheiro."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Não foi possível localizar o ficheiro pedido."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Existem demasiados pedidos em processamento. Tente novamente mais tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronização"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronização"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"O armazenamento do telefone está cheio! Elimine alguns ficheiros para libertar espaço."</string>
- <string name="me" msgid="6545696007631404292">"Eu"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opções do telefone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar sem fios"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar sem fios"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueio de ecrã"</string>
- <string name="power_off" msgid="4266614107412865048">"Desligar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"O seu telefone irá encerrar."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nenhuma aplicação recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opções do telefone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som desactivado"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está activado"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está activado"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desactivado"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que implicam pagamento"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite às aplicações efectuar acções que implicam pagamento."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"As suas mensagens"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leia e escreva a sua SMS, o seu e-mail e outras mensagens."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Os seus dados pessoais"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acesso directo aos seus contactos e calendário armazenados no telefone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"A sua localização"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorizar a sua localização física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicação de rede"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite o acesso de aplicações a várias funcionalidades de rede."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"As suas Contas Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Aceda às Contas Google disponíveis."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlos de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda directamente ao hardware no telefone."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorize, grave e processe chamadas telefónicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acesso e controlo de nível inferior do sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ferramentas de desenvolvimento"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funcionalidades apenas necessárias para programadores de aplicações."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"A página Web contém um erro."</string>
+ <string name="httpErrorLookup">"Não foi possível localizar o URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"O esquema de autenticação do site não é suportado."</string>
+ <string name="httpErrorAuth">"A autenticação falhou."</string>
+ <string name="httpErrorProxyAuth">"A·autenticação·através·do·servidor·proxy·falhou."</string>
+ <string name="httpErrorConnect">"Não foi possível estabelecer a ligação ao servidor."</string>
+ <string name="httpErrorIO">"O servidor falhou ao comunicar. Tente novamente mais tarde."</string>
+ <string name="httpErrorTimeout">"Esgotou o tempo limite da ligação ao servidor."</string>
+ <string name="httpErrorRedirectLoop">"A página contém demasiados redireccionamentos do servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"O protocolo não é suportado."</string>
+ <string name="httpErrorFailedSslHandshake">"Não foi possível estabelecer uma ligação segura."</string>
+ <string name="httpErrorBadUrl">"Não foi possível abrir a página porque o URL é inválido."</string>
+ <string name="httpErrorFile">"Não foi possível aceder ao ficheiro."</string>
+ <string name="httpErrorFileNotFound">"Não foi possível localizar o ficheiro pedido."</string>
+ <string name="httpErrorTooManyRequests">"Existem demasiados pedidos em processamento. Tente novamente mais tarde."</string>
+ <string name="contentServiceSync">"Sincronização"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronização"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"O armazenamento do telefone está cheio! Elimine alguns ficheiros para libertar espaço."</string>
+ <string name="me">"Eu"</string>
+ <string name="power_dialog">"Opções do telefone"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Activar sem fios"</string>
+ <string name="turn_off_radio">"Desactivar sem fios"</string>
+ <string name="screen_lock">"Bloqueio de ecrã"</string>
+ <string name="power_off">"Desligar"</string>
+ <string name="shutdown_progress">"A encerrar..."</string>
+ <string name="shutdown_confirm">"O seu telefone irá encerrar."</string>
+ <string name="no_recent_tasks">"Nenhuma aplicação recente."</string>
+ <string name="global_actions">"Opções do telefone"</string>
+ <string name="global_action_lock">"Bloqueio de ecrã"</string>
+ <string name="global_action_power_off">"Desligar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"Som desactivado"</string>
+ <string name="global_action_silent_mode_off_status">"O som está activado"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo de avião"</string>
+ <string name="global_actions_airplane_mode_on_status">"O modo de voo está activado"</string>
+ <string name="global_actions_airplane_mode_off_status">"O modo de voo está desactivado"</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Serviços que implicam pagamento"</string>
+ <string name="permgroupdesc_costMoney">"Permite às aplicações efectuar acções que implicam pagamento."</string>
+ <string name="permgrouplab_messages">"As suas mensagens"</string>
+ <string name="permgroupdesc_messages">"Leia e escreva a sua SMS, o seu e-mail e outras mensagens."</string>
+ <string name="permgrouplab_personalInfo">"Os seus dados pessoais"</string>
+ <string name="permgroupdesc_personalInfo">"Acesso directo aos seus contactos e calendário armazenados no telefone."</string>
+ <string name="permgrouplab_location">"A sua localização"</string>
+ <string name="permgroupdesc_location">"Monitorizar a sua localização física"</string>
+ <string name="permgrouplab_network">"Comunicação de rede"</string>
+ <string name="permgroupdesc_network">"Permite o acesso de aplicações a várias funcionalidades de rede."</string>
+ <string name="permgrouplab_accounts">"As suas Contas Google"</string>
+ <string name="permgroupdesc_accounts">"Aceda às Contas Google disponíveis."</string>
+ <string name="permgrouplab_hardwareControls">"Controlos de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Aceda directamente ao hardware no telefone."</string>
+ <string name="permgrouplab_phoneCalls">"Chamadas"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorize, grave e processe chamadas telefónicas."</string>
+ <string name="permgrouplab_systemTools">"Ferramentas do sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acesso e controlo de nível inferior do sistema."</string>
+ <string name="permgrouplab_developmentTools">"Ferramentas de desenvolvimento"</string>
+ <string name="permgroupdesc_developmentTools">"Funcionalidades apenas necessárias para programadores de aplicações."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite à aplicação desactivar a barra de estado ou adicionar e remover ícones do sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/fechar barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite à aplicação expandir ou fechar a barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar chamadas efectuadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite à aplicação processar chamadas efectuadas e mudar o número a marcar. Algumas aplicações maliciosas podem monitorizar, redireccionar ou impedir chamadas efectuadas."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"receber SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite à aplicação receber e processar mensagens SMS. Algumas aplicações maliciosas podem monitorizar as suas mensagens e eliminá-las sem mostrá-las a si."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"receber MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite à aplicação receber e processar mensagens MMS. Algumas aplicações maliciosas podem monitorizar as mensagens ou eliminá-las sem mostrá-las ao utilizador."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensagens SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite à aplicação enviar mensagens SMS. Algumas aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ler SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite à aplicação ler mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem ler as suas mensagens confidenciais."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS ou MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite a aplicações escrever mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem eliminar as suas mensagens."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"receber WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite à aplicação receber e processar mensagens WAP. Algumas aplicações maliciosas podem monitorizar ou eliminá-las sem mostrá-las ao utilizador."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"obter aplicações em execução"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite à aplicação obter informações sobre tarefas actualmente em execução e recentemente executadas. Pode permitir que aplicações maliciosas descubram informações privadas sobre outras aplicações."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reordenar aplicações em execução"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite a uma aplicação mover tarefas do primeiro e do segundo planos. Algumas aplicações maliciosas podem impor-se no primeiro plano sem o controlo do utilizador."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"activar depuração da aplicação"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite a uma aplicação activar a depuração para outra aplicação. Algumas aplicações maliciosas podem utilizar este item para eliminar outras aplicações."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite a uma aplicação mudar a configuração actual como, por exemplo, a região ou o tamanho global do tipo de letra."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar outras aplicações"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite a uma aplicação efectuar o reinício forçado de outras aplicações."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forçar fecho da aplicação"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite a uma aplicação forçar qualquer actividade em primeiro plano a fechar e retroceder. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"obter estado interno do sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite à aplicação obter o estado interno do sistema. Algumas aplicações maliciosas podem obter uma ampla variedade de dados privados e seguros de que, normalmente, nunca devem necessitar."</string>
+ <string name="permlab_statusBar">"desactivar ou modificar barra de estado"</string>
+ <string name="permdesc_statusBar">"Permite à aplicação desactivar a barra de estado ou adicionar e remover ícones do sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/fechar barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Permite à aplicação expandir ou fechar a barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar chamadas efectuadas"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite à aplicação processar chamadas efectuadas e mudar o número a marcar. Algumas aplicações maliciosas podem monitorizar, redireccionar ou impedir chamadas efectuadas."</string>
+ <string name="permlab_receiveSms">"receber SMS"</string>
+ <string name="permdesc_receiveSms">"Permite à aplicação receber e processar mensagens SMS. Algumas aplicações maliciosas podem monitorizar as suas mensagens e eliminá-las sem mostrá-las a si."</string>
+ <string name="permlab_receiveMms">"receber MMS"</string>
+ <string name="permdesc_receiveMms">"Permite à aplicação receber e processar mensagens MMS. Algumas aplicações maliciosas podem monitorizar as mensagens ou eliminá-las sem mostrá-las ao utilizador."</string>
+ <string name="permlab_sendSms">"enviar mensagens SMS"</string>
+ <string name="permdesc_sendSms">"Permite à aplicação enviar mensagens SMS. Algumas aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
+ <string name="permlab_readSms">"ler SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permite à aplicação ler mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem ler as suas mensagens confidenciais."</string>
+ <string name="permlab_writeSms">"editar SMS ou MMS"</string>
+ <string name="permdesc_writeSms">"Permite a aplicações escrever mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem eliminar as suas mensagens."</string>
+ <string name="permlab_receiveWapPush">"receber WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite à aplicação receber e processar mensagens WAP. Algumas aplicações maliciosas podem monitorizar ou eliminá-las sem mostrá-las ao utilizador."</string>
+ <string name="permlab_getTasks">"obter aplicações em execução"</string>
+ <string name="permdesc_getTasks">"Permite à aplicação obter informações sobre tarefas actualmente em execução e recentemente executadas. Pode permitir que aplicações maliciosas descubram informações privadas sobre outras aplicações."</string>
+ <string name="permlab_reorderTasks">"reordenar aplicações em execução"</string>
+ <string name="permdesc_reorderTasks">"Permite a uma aplicação mover tarefas do primeiro e do segundo planos. Algumas aplicações maliciosas podem impor-se no primeiro plano sem o controlo do utilizador."</string>
+ <string name="permlab_setDebugApp">"activar depuração da aplicação"</string>
+ <string name="permdesc_setDebugApp">"Permite a uma aplicação activar a depuração para outra aplicação. Algumas aplicações maliciosas podem utilizar este item para eliminar outras aplicações."</string>
+ <string name="permlab_changeConfiguration">"mudar definições da IU"</string>
+ <string name="permdesc_changeConfiguration">"Permite a uma aplicação mudar a configuração actual como, por exemplo, a região ou o tamanho global do tipo de letra."</string>
+ <string name="permlab_restartPackages">"reiniciar outras aplicações"</string>
+ <string name="permdesc_restartPackages">"Permite a uma aplicação efectuar o reinício forçado de outras aplicações."</string>
+ <string name="permlab_forceBack">"forçar fecho da aplicação"</string>
+ <string name="permdesc_forceBack">"Permite a uma aplicação forçar qualquer actividade em primeiro plano a fechar e retroceder. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_dump">"obter estado interno do sistema"</string>
+ <string name="permdesc_dump">"Permite à aplicação obter o estado interno do sistema. Algumas aplicações maliciosas podem obter uma ampla variedade de dados privados e seguros de que, normalmente, nunca devem necessitar."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorizar a controlar a iniciação de todas as aplicações"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite a uma aplicação monitorizar e controlar a forma como o sistema inicia actividades. Algumas aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização apenas é necessária para desenvolvimento, nunca para a utilização normal do telefone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusão de pacote removido"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite a uma aplicação difundir uma notificação de que foi removido um pacote de aplicações. Algumas aplicações maliciosas podem utilizar este item para eliminar qualquer outra aplicação em execução."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar difusão recebida por SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagem SMS. Algumas aplicações maliciosas podem utilizar este item para falsificar mensagens SMS a receber."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar difusão recebida através de PUSH WAP"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagens PUSH WAP. Algumas aplicações maliciosas podem utilizar este item para falsificar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"número limite de processos em execução"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite a um aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"fazer com que todas as aplicações de fundo fechem"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite a uma aplicação controlar se as actividades são sempre terminadas assim que passam para o fundo. Nunca é necessário para aplicações normais."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estatísticas da bateria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas recolhidas sobre a bateria. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorizar a controlar a iniciação de todas as aplicações"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite a uma aplicação monitorizar e controlar a forma como o sistema inicia actividades. Algumas aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização apenas é necessária para desenvolvimento, nunca para a utilização normal do telefone."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar difusão de pacote removido"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite a uma aplicação difundir uma notificação de que foi removido um pacote de aplicações. Algumas aplicações maliciosas podem utilizar este item para eliminar qualquer outra aplicação em execução."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar difusão recebida por SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagem SMS. Algumas aplicações maliciosas podem utilizar este item para falsificar mensagens SMS a receber."</string>
+ <string name="permlab_broadcastWapPush">"enviar difusão recebida através de PUSH WAP"</string>
+ <string name="permdesc_broadcastWapPush">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagens PUSH WAP. Algumas aplicações maliciosas podem utilizar este item para falsificar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"número limite de processos em execução"</string>
+ <string name="permdesc_setProcessLimit">"Permite a um aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
+ <string name="permlab_setAlwaysFinish">"fazer com que todas as aplicações de fundo fechem"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite a uma aplicação controlar se as actividades são sempre terminadas assim que passam para o fundo. Nunca é necessário para aplicações normais."</string>
+ <string name="permlab_batteryStats">"modificar estatísticas da bateria"</string>
+ <string name="permdesc_batteryStats">"Permite a modificação das estatísticas recolhidas sobre a bateria. Não se destina a utilização por aplicações normais."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"apresentar janelas não autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas a utilização pela interface de utilizador interna do sistema. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"apresentar alertas ao nível do sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite a um aplicação mostrar janelas de alerta do sistema. Algumas aplicações maliciosas podem ocupar todo o ecrã do telefone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade global da animação"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite a uma aplicação mudar a velocidade global da animação (animações mais rápidas ou mais lentas) em qualquer altura."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gerir tokens de aplicações"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite a aplicações criar e gerir os seus próprios tokens, ignorando a ordenação normal dos mesmos pelo eixo dos Z. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"premir teclas e botões de controlo"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite a uma aplicação fornecer os seus próprios eventos de entrada (toques em teclas, etc.) a outras aplicações. Algumas aplicações maliciosas podem utilizar este item para controlar o telefone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"gravar o que utilizador escreve e as acções que efectua"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite às aplicações verificar as teclas que o utilizador prime, mesmo ao interagir com outras aplicações (como, por exemplo, ao introduzir uma palavra-passe). Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite ao titular vincular a interface de nível superior a um método de entrada de som. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais Linux para aplicações"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"fazer com que a aplicação seja sempre executada"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite a uma aplicação tornar persistentes partes da mesma, para que o sistema não possa utilizá-la para outras aplicações."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicações"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite a uma aplicação eliminar pacotes do Android. Algumas aplicações maliciosas podem utilizar este item para eliminar aplicações importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar dados de outras aplicações"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite a uma aplicação limpar dados do proprietário."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar caches de outras aplicações"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite a uma aplicação eliminar ficheiros em cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento da aplicação"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos os dados da aplicações"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ler ficheiros de registo do sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"activar ou desactivar componentes da aplicação"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite a uma aplicação mudar a opção de activar ou não um componente de outra aplicação. Algumas aplicações maliciosas podem utilizar este item para desactivar funcionalidades importantes do telefone. É necessário ter cuidado com a autorização, uma vez que é possível tornar alguns componentes de aplicações num estado inutilizável, inconsistente ou instável."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"definir aplicações preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite a uma aplicação modificar as suas aplicações preferidas. Isto pode permitir que algumas aplicações maliciosas mudem, de forma silenciosa, as aplicações executadas, falsificando as aplicações existentes para recolher os seus dados privados."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar definições globais do sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite a uma aplicação modificar os dados das definições do sistema. Algumas aplicações maliciosas podem danificar as configurações do sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar definições seguras do sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite a uma aplicação modificar os dados de definições seguras dos sistemas. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar o mapa de serviços do Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite a uma aplicação modificar o mapa de serviços do Google. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automaticamente no arranque"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode demorar o início do telefone e permitir à aplicação abrandar todo o funcionamento do telefone, uma vez que está em constante execução."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar difusão fixa"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite a uma aplicação enviar difusões fixas, que permanecem após o fim da difusão. Algumas aplicações maliciosas podem tornar o telefone lento ou instável, fazendo com que utilize demasiada memória."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ler dados de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite a uma aplicação ler todos os dados de contactos (endereços) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os seus dados a outras pessoas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escrever dados de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite a uma aplicação modificar os dados de contacto (endereço) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar estes dados para apagar ou modificar os dados dos seus contactos."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escrever dados do proprietário"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar dados do proprietário."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ler dados do proprietário"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para ler dados do proprietário do telefone."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ler dados do calendário"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite a uma aplicação ler todos os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os eventos do seu calendário a outras pessoas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escrever dados do calendário"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite a uma aplicação modificar os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar os dados do seu calendário."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fontes de localização fictícias para teste"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crie fontes de localização fictícias para fins de teste. Algumas aplicações maliciosas podem utilizar este item para substituir a localização e/ou o estado devolvido por fontes de localização reais, tais como fornecedores de GPS ou de Rede."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"aceder a comandos adicionais do fornecedor de localização"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Aceda a comandos adicionais do fornecedor de localização. Algumas aplicações maliciosas podem utilizar este item para interferir com o funcionamento do GPS ou de outras fontes de localização."</string>
+ <string name="permlab_internalSystemWindow">"apresentar janelas não autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite a criação de janelas destinadas a utilização pela interface de utilizador interna do sistema. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_systemAlertWindow">"apresentar alertas ao nível do sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite a um aplicação mostrar janelas de alerta do sistema. Algumas aplicações maliciosas podem ocupar todo o ecrã do telefone."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidade global da animação"</string>
+ <string name="permdesc_setAnimationScale">"Permite a uma aplicação mudar a velocidade global da animação (animações mais rápidas ou mais lentas) em qualquer altura."</string>
+ <string name="permlab_manageAppTokens">"gerir tokens de aplicações"</string>
+ <string name="permdesc_manageAppTokens">"Permite a aplicações criar e gerir os seus próprios tokens, ignorando a ordenação normal dos mesmos pelo eixo dos Z. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_injectEvents">"premir teclas e botões de controlo"</string>
+ <string name="permdesc_injectEvents">"Permite a uma aplicação fornecer os seus próprios eventos de entrada (toques em teclas, etc.) a outras aplicações. Algumas aplicações maliciosas podem utilizar este item para controlar o telefone."</string>
+ <string name="permlab_readInputState">"gravar o que utilizador escreve e as acções que efectua"</string>
+ <string name="permdesc_readInputState">"Permite às aplicações verificar as teclas que o utilizador prime, mesmo ao interagir com outras aplicações (como, por exemplo, ao introduzir uma palavra-passe). Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_bindInputMethod">"vincular a um método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite ao titular vincular a interface de nível superior a um método de entrada de som. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_setOrientation">"mudar orientação do ecrã"</string>
+ <string name="permdesc_setOrientation">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar sinais Linux para aplicações"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
+ <string name="permlab_persistentActivity">"fazer com que a aplicação seja sempre executada"</string>
+ <string name="permdesc_persistentActivity">"Permite a uma aplicação tornar persistentes partes da mesma, para que o sistema não possa utilizá-la para outras aplicações."</string>
+ <string name="permlab_deletePackages">"eliminar aplicações"</string>
+ <string name="permdesc_deletePackages">"Permite a uma aplicação eliminar pacotes do Android. Algumas aplicações maliciosas podem utilizar este item para eliminar aplicações importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar dados de outras aplicações"</string>
+ <string name="permdesc_clearAppUserData">"Permite a uma aplicação limpar dados do proprietário."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar caches de outras aplicações"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite a uma aplicação eliminar ficheiros em cache."</string>
+ <string name="permlab_getPackageSize">"medir espaço de armazenamento da aplicação"</string>
+ <string name="permdesc_getPackageSize">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string>
+ <string name="permlab_installPackages">"instalar aplicações directamente"</string>
+ <string name="permdesc_installPackages">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos os dados da aplicações"</string>
+ <string name="permdesc_clearAppCache">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
+ <string name="permlab_readLogs">"ler ficheiros de registo do sistema"</string>
+ <string name="permdesc_readLogs">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string>
+ <string name="permlab_diagnostic">"ler/escrever em recursos propriedade de diag"</string>
+ <string name="permdesc_diagnostic">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
+ <string name="permlab_changeComponentState">"activar ou desactivar componentes da aplicação"</string>
+ <string name="permdesc_changeComponentState">"Permite a uma aplicação mudar a opção de activar ou não um componente de outra aplicação. Algumas aplicações maliciosas podem utilizar este item para desactivar funcionalidades importantes do telefone. É necessário ter cuidado com a autorização, uma vez que é possível tornar alguns componentes de aplicações num estado inutilizável, inconsistente ou instável."</string>
+ <string name="permlab_setPreferredApplications">"definir aplicações preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Permite a uma aplicação modificar as suas aplicações preferidas. Isto pode permitir que algumas aplicações maliciosas mudem, de forma silenciosa, as aplicações executadas, falsificando as aplicações existentes para recolher os seus dados privados."</string>
+ <string name="permlab_writeSettings">"modificar definições globais do sistema"</string>
+ <string name="permdesc_writeSettings">"Permite a uma aplicação modificar os dados das definições do sistema. Algumas aplicações maliciosas podem danificar as configurações do sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar definições seguras do sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Permite a uma aplicação modificar os dados de definições seguras dos sistemas. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_writeGservices">"modificar o mapa de serviços do Google"</string>
+ <string name="permdesc_writeGservices">"Permite a uma aplicação modificar o mapa de serviços do Google. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automaticamente no arranque"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode demorar o início do telefone e permitir à aplicação abrandar todo o funcionamento do telefone, uma vez que está em constante execução."</string>
+ <string name="permlab_broadcastSticky">"enviar difusão fixa"</string>
+ <string name="permdesc_broadcastSticky">"Permite a uma aplicação enviar difusões fixas, que permanecem após o fim da difusão. Algumas aplicações maliciosas podem tornar o telefone lento ou instável, fazendo com que utilize demasiada memória."</string>
+ <string name="permlab_readContacts">"ler dados de contacto"</string>
+ <string name="permdesc_readContacts">"Permite a uma aplicação ler todos os dados de contactos (endereços) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os seus dados a outras pessoas."</string>
+ <string name="permlab_writeContacts">"escrever dados de contacto"</string>
+ <string name="permdesc_writeContacts">"Permite a uma aplicação modificar os dados de contacto (endereço) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar estes dados para apagar ou modificar os dados dos seus contactos."</string>
+ <string name="permlab_writeOwnerData">"escrever dados do proprietário"</string>
+ <string name="permdesc_writeOwnerData">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar dados do proprietário."</string>
+ <string name="permlab_readOwnerData">"ler dados do proprietário"</string>
+ <string name="permdesc_readOwnerData">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para ler dados do proprietário do telefone."</string>
+ <string name="permlab_readCalendar">"ler dados do calendário"</string>
+ <string name="permdesc_readCalendar">"Permite a uma aplicação ler todos os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os eventos do seu calendário a outras pessoas."</string>
+ <string name="permlab_writeCalendar">"escrever dados do calendário"</string>
+ <string name="permdesc_writeCalendar">"Permite a uma aplicação modificar os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar os dados do seu calendário."</string>
+ <string name="permlab_accessMockLocation">"fontes de localização fictícias para teste"</string>
+ <string name="permdesc_accessMockLocation">"Crie fontes de localização fictícias para fins de teste. Algumas aplicações maliciosas podem utilizar este item para substituir a localização e/ou o estado devolvido por fontes de localização reais, tais como fornecedores de GPS ou de Rede."</string>
+ <string name="permlab_accessLocationExtraCommands">"aceder a comandos adicionais do fornecedor de localização"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Aceda a comandos adicionais do fornecedor de localização. Algumas aplicações maliciosas podem utilizar este item para interferir com o funcionamento do GPS ou de outras fontes de localização."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"localização exacta (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Aceder a fontes de localização específicas, tais como o Sistema de Posicionamento Global (GPS), no telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar a localização do utilizador e podem consumir energia adicional da bateria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"localização aproximada (baseada na rede)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Aceda a fontes de localização aproximadas, tais como a base de dados da rede celular, para determinar uma localização aproximada do telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar aproximadamente onde o utilizador se encontra."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"aceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite às aplicações utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler memória intermédia de fotogramas"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite à aplicação ler o conteúdo da memória intermédia de fotogramas."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas definições de áudio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite à aplicação modificar as definições de áudio globais, tais como o volume e o encaminhamento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite à aplicação aceder ao caminho de gravação de áudio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tirar fotografias"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite à aplicação tirar fotografias com a câmara. Isto permite que a aplicação recolha imagens captadas pela câmara em qualquer momento."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desactivar telefone de forma permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite à aplicação desactivar permanentemente todo o telefone. Esta acção é muito perigosa."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forçar reinício do telefone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite à aplicação forçar o reinício do telefone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e desmontar sistemas de ficheiros"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite à aplicação montar e desmontar sistemas de ficheiros para armazenamento removível."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatar armazenamento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite a uma aplicação formatar o armazenamento removível."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar vibrador"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite à aplicação controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite à aplicação controlar a lanterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone directamente"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar directamente quaisquer números de telefone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar notificações de actualização de localização"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"aceder a propriedades de verificação"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite acesso de leitura/escrita a propriedades carregadas pelo serviço de verificação. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"escolher miniaplicações"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite à aplicação informar o sistema acerca das miniaplicações que podem ser utilizadas com cada aplicação. Com esta autorização, algumas aplicações podem conceder acesso a dados pessoais a outras aplicações. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado do telefone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite à aplicação controlar as funcionalidades do telefone do dispositivo. Uma aplicação com esta autorização pode alternar entre redes, ligar e desligar o rádio do telefone, etc., sem nunca notificar o utilizador."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir que o telefone entre em inactividade"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite a uma aplicação impedir o telefone de entrar em inactividade."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite a uma aplicação ligar ou desligar o telefone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"executar em modo de teste de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Executar como um teste de nível inferior do fabricante, permitindo o acesso total ao hardware do telefone. Apenas disponível quando um telefone está em execução em modo de teste do fabricante."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"definir imagem de fundo"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite à aplicação definir a imagem de fundo do sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir sugestões de tamanho da imagem de fundo"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permitir que a aplicação defina as sugestões de tamanho da imagem de fundo do sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"repor definições de fábrica do sistemas"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite a uma aplicação repor totalmente as definições de fábrica do sistema, apagando todos os dados, configurações e aplicações instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"definir fuso horário"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite a uma aplicação mudar o fuso horário do telefone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descobrir contas reconhecidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite a uma aplicação obter a lista de contas reconhecidas pelo telefone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado da rede"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite a uma aplicação ver o estado de todas as redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acesso total à Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite a uma aplicação criar sockets de rede."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escrever definições de Nome do ponto de acesso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite a uma aplicaçaõ modificar as definições de APN, tais como Proxy e Porta de qualquer APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"mudar conectividade de rede"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite a uma aplicação mudar o estado da conectividade de rede."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"mudar definição de utilização de dados de segundo plano"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite a uma aplicação mudar a definição de utilização de dados de segundo plano."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver estado de Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"localização exacta (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Aceder a fontes de localização específicas, tais como o Sistema de Posicionamento Global (GPS), no telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar a localização do utilizador e podem consumir energia adicional da bateria."</string>
+ <string name="permlab_accessCoarseLocation">"localização aproximada (baseada na rede)"</string>
+ <string name="permdesc_accessCoarseLocation">"Aceda a fontes de localização aproximadas, tais como a base de dados da rede celular, para determinar uma localização aproximada do telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar aproximadamente onde o utilizador se encontra."</string>
+ <string name="permlab_accessSurfaceFlinger">"aceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite às aplicações utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
+ <string name="permlab_readFrameBuffer">"ler memória intermédia de fotogramas"</string>
+ <string name="permdesc_readFrameBuffer">"Permite·à·aplicação·ler·o·conteúdo·da·memória·intermédia·de·fotogramas."</string>
+ <string name="permlab_modifyAudioSettings">"mudar as suas definições de áudio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite à aplicação modificar as definições de áudio globais, tais como o volume e o encaminhamento."</string>
+ <string name="permlab_recordAudio">"gravar áudio"</string>
+ <string name="permdesc_recordAudio">"Permite à aplicação aceder ao caminho de gravação de áudio."</string>
+ <string name="permlab_camera">"tirar fotografias"</string>
+ <string name="permdesc_camera">"Permite à aplicação tirar fotografias com a câmara. Isto permite que a aplicação recolha imagens captadas pela câmara em qualquer momento."</string>
+ <string name="permlab_brick">"desactivar telefone de forma permanente"</string>
+ <string name="permdesc_brick">"Permite à aplicação desactivar permanentemente todo o telefone. Esta acção é muito perigosa."</string>
+ <string name="permlab_reboot">"forçar reinício do telefone"</string>
+ <string name="permdesc_reboot">"Permite à aplicação forçar o reinício do telefone."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar e desmontar sistemas de ficheiros"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite à aplicação montar e desmontar sistemas de ficheiros para armazenamento removível."</string>
+ <string name="permlab_mount_format_filesystems">"formatar armazenamento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite a uma aplicação formatar o armazenamento removível."</string>
+ <string name="permlab_vibrate">"controlar vibrador"</string>
+ <string name="permdesc_vibrate">"Permite à aplicação controlar o vibrador."</string>
+ <string name="permlab_flashlight">"controlar lanterna"</string>
+ <string name="permdesc_flashlight">"Permite à aplicação controlar a lanterna."</string>
+ <string name="permlab_hardware_test">"testar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
+ <string name="permlab_callPhone">"marcar números de telefone directamente"</string>
+ <string name="permdesc_callPhone">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string>
+ <string name="permlab_callPrivileged">"marcar directamente quaisquer números de telefone"</string>
+ <string name="permdesc_callPrivileged">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string>
+ <string name="permlab_locationUpdates">"controlar notificações de actualização de localização"</string>
+ <string name="permdesc_locationUpdates">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_checkinProperties">"aceder a propriedades de verificação"</string>
+ <string name="permdesc_checkinProperties">"Permite acesso de leitura/escrita a propriedades carregadas pelo serviço de verificação. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_bindGadget">"escolher miniaplicações"</string>
+ <string name="permdesc_bindGadget">"Permite à aplicação informar o sistema acerca das miniaplicações que podem ser utilizadas com cada aplicação. Com esta autorização, algumas aplicações podem conceder acesso a dados pessoais a outras aplicações. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado do telefone"</string>
+ <string name="permdesc_modifyPhoneState">"Permite à aplicação controlar as funcionalidades do telefone do dispositivo. Uma aplicação com esta autorização pode alternar entre redes, ligar e desligar o rádio do telefone, etc., sem nunca notificar o utilizador."</string>
+ <string name="permlab_readPhoneState">"ler estado do telefone"</string>
+ <string name="permdesc_readPhoneState">"Permite à aplicação aceder às funcionalidades do dispositivo. Uma aplicação com esta autorização pode determinar o número deste telefone, se existe uma chamada activa, o número a que a essa chamada está ligada, entre outras."</string>
+ <string name="permlab_wakeLock">"impedir que o telefone entre em inactividade"</string>
+ <string name="permdesc_wakeLock">"Permite a uma aplicação impedir o telefone de entrar em inactividade."</string>
+ <string name="permlab_devicePower">"ligar ou desligar o telefone"</string>
+ <string name="permdesc_devicePower">"Permite a uma aplicação ligar ou desligar o telefone."</string>
+ <string name="permlab_factoryTest">"executar em modo de teste de fábrica"</string>
+ <string name="permdesc_factoryTest">"Executar como um teste de nível inferior do fabricante, permitindo o acesso total ao hardware do telefone. Apenas disponível quando um telefone está em execução em modo de teste do fabricante."</string>
+ <string name="permlab_setWallpaper">"definir imagem de fundo"</string>
+ <string name="permdesc_setWallpaper">"Permite à aplicação definir a imagem de fundo do sistema."</string>
+ <string name="permlab_setWallpaperHints">"definir sugestões de tamanho da imagem de fundo"</string>
+ <string name="permdesc_setWallpaperHints">"Permitir que a aplicação defina as sugestões de tamanho da imagem de fundo do sistema."</string>
+ <string name="permlab_masterClear">"repor definições de fábrica do sistemas"</string>
+ <string name="permdesc_masterClear">"Permite a uma aplicação repor totalmente as definições de fábrica do sistema, apagando todos os dados, configurações e aplicações instaladas."</string>
+ <string name="permlab_setTimeZone">"definir fuso horário"</string>
+ <string name="permdesc_setTimeZone">"Permite a uma aplicação mudar o fuso horário do telefone."</string>
+ <string name="permlab_getAccounts">"descobrir contas reconhecidas"</string>
+ <string name="permdesc_getAccounts">"Permite a uma aplicação obter a lista de contas reconhecidas pelo telefone."</string>
+ <string name="permlab_accessNetworkState">"ver estado da rede"</string>
+ <string name="permdesc_accessNetworkState">"Permite a uma aplicação ver o estado de todas as redes."</string>
+ <string name="permlab_createNetworkSockets">"acesso total à Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite a uma aplicação criar sockets de rede."</string>
+ <string name="permlab_writeApnSettings">"escrever definições de Nome do ponto de acesso"</string>
+ <string name="permdesc_writeApnSettings">"Permite a uma aplicaçaõ modificar as definições de APN, tais como Proxy e Porta de qualquer APN."</string>
+ <string name="permlab_changeNetworkState">"mudar conectividade de rede"</string>
+ <string name="permdesc_changeNetworkState">"Permite a uma aplicação mudar o estado da conectividade de rede."</string>
+ <string name="permlab_changeBackgroundDataSetting">"mudar definição de utilização de dados de segundo plano"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite a uma aplicação mudar a definição de utilização de dados de segundo plano."</string>
+ <string name="permlab_accessWifiState">"ver estado de Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"mudar estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite a uma aplicação configurar o telefone Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"criar ligações Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite a uma aplicação ver a configuração do telefone Bluetooth local, bem como efectuar e aceitar ligações com dispositivos emparelhados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar bloqueio de teclas"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite a uma aplicação desactivar o bloqueio de teclas e qualquer segurança por palavra-passe associada. Um exemplo legítimo é a desactivação do bloqueio de teclas pelo telefone ao receber uma chamada, reactivando, em seguida, o bloqueio de teclas ao terminar a chamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler definições de sincronização"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite a uma aplicação ler as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"definições de sincronização de escrita"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite a uma aplicação modificar as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ler estatísticas de sincronização"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite a uma aplicação ler as estatísticas de sincronização, por exemplo, o histórico de sincronizações ocorridas."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds subscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite a uma aplicação obter detalhes acerca dos feeds actualmente sincronizados."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escrever feeds subscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite a uma aplicação modificar os seus feeds actualmente sincronizados. Isto pode permitir a uma aplicação maliciosa alterar os seus feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ler dicionário definido pelo utilizador"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite a uma aplicação ler quaisquer palavras, nomes e expressões privadas que o utilizador possa ter armazenado no dicionário do utilizador."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escrever no dicionário definido pelo utilizador"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite a uma aplicação escrever novas palavras no dicionário do utilizador."</string>
+ <string name="permlab_bluetoothAdmin">"administração de bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite a uma aplicação configurar o telefone Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"criar ligações Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite a uma aplicação ver a configuração do telefone Bluetooth local, bem como efectuar e aceitar ligações com dispositivos emparelhados."</string>
+ <string name="permlab_disableKeyguard">"desactivar bloqueio de teclas"</string>
+ <string name="permdesc_disableKeyguard">"Permite a uma aplicação desactivar o bloqueio de teclas e qualquer segurança por palavra-passe associada. Um exemplo legítimo é a desactivação do bloqueio de teclas pelo telefone ao receber uma chamada, reactivando, em seguida, o bloqueio de teclas ao terminar a chamada."</string>
+ <string name="permlab_readSyncSettings">"ler definições de sincronização"</string>
+ <string name="permdesc_readSyncSettings">"Permite a uma aplicação ler as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
+ <string name="permlab_writeSyncSettings">"definições de sincronização de escrita"</string>
+ <string name="permdesc_writeSyncSettings">"Permite a uma aplicação modificar as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
+ <string name="permlab_readSyncStats">"ler estatísticas de sincronização"</string>
+ <string name="permdesc_readSyncStats">"Permite a uma aplicação ler as estatísticas de sincronização, por exemplo, o histórico de sincronizações ocorridas."</string>
+ <string name="permlab_subscribedFeedsRead">"ler feeds subscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite a uma aplicação obter detalhes acerca dos feeds actualmente sincronizados."</string>
+ <string name="permlab_subscribedFeedsWrite">"escrever feeds subscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite a uma aplicação modificar os seus feeds actualmente sincronizados. Isto pode permitir a uma aplicação maliciosa alterar os seus feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"ler dicionário definido pelo utilizador"</string>
+ <string name="permdesc_readDictionary">"Permite a uma aplicação ler quaisquer palavras, nomes e expressões privadas que o utilizador possa ter armazenado no dicionário do utilizador."</string>
+ <string name="permlab_writeDictionary">"escrever no dicionário definido pelo utilizador"</string>
+ <string name="permdesc_writeDictionary">"Permite a uma aplicação escrever novas palavras no dicionário do utilizador."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Residência"</item>
- <item msgid="869923650527136615">"Móvel"</item>
- <item msgid="7897544654242874543">"Emprego"</item>
- <item msgid="1103601433382158155">"Fax do emprego"</item>
- <item msgid="1735177144948329370">"Fax da residência"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Outro"</item>
- <item msgid="9192514806975898961">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Móvel"</item>
+ <item>"Emprego"</item>
+ <item>"Fax do emprego"</item>
+ <item>"Fax da residência"</item>
+ <item>"Pager"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Residência"</item>
- <item msgid="7084237356602625604">"Emprego"</item>
- <item msgid="1112044410659011023">"Outro"</item>
- <item msgid="2374913952870110618">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Móvel"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Residência"</item>
- <item msgid="5629153956045109251">"Emprego"</item>
- <item msgid="4966604264500343469">"Outro"</item>
- <item msgid="4932682847595299369">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Residência"</item>
- <item msgid="1359644565647383708">"Emprego"</item>
- <item msgid="7868549401053615677">"Outro"</item>
- <item msgid="3145118944639869809">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Emprego"</item>
- <item msgid="4378074129049520373">"Outro"</item>
- <item msgid="3455047468583965104">"Personalizado"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduzir código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Código PIN incorrecto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, prima Menu e, em seguida, 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Nenhum serviço)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecrã bloqueado."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Prima Menu para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenhar padrão para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chamada de emergência"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Lamentamos, tente novamente"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"A carregar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Introduzir código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Código PIN incorrecto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, prima Menu e, em seguida, 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergência"</string>
+ <string name="lockscreen_carrier_default">"(Nenhum serviço)"</string>
+ <string name="lockscreen_screen_locked">"Ecrã bloqueado."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Prima Menu para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Desenhar padrão para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Chamada de emergência"</string>
+ <string name="lockscreen_pattern_correct">"Correcto!"</string>
+ <string name="lockscreen_pattern_wrong">"Lamentamos, tente novamente"</string>
+ <string name="lockscreen_plugged_in">"A carregar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ligue o carregador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nenhum cartão SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Nenhum cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Introduza um cartão SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado por PUK"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulte o Manual de utilizador ou contacte a Assistência a clientes."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"A desbloquear cartão SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu-se do padrão?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Demasiadas tentativas de efectuar o padrão!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, inicie sessão com a sua Conta Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome de utilizador (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Palavra-passe"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Iniciar sessão"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de utilizador ou palavra-passe inválidos."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Ligue o carregador."</string>
+ <string name="lockscreen_missing_sim_message_short">"Nenhum cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Nenhum cartão SIM no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Introduza um cartão SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rede bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"O cartão SIM está bloqueado por PUK"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulte o Manual de utilizador ou contacte a Assistência a clientes."</string>
+ <string name="lockscreen_sim_locked_message">"O cartão SIM está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"A desbloquear cartão SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Esqueceu-se do padrão?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Demasiadas tentativas de efectuar o padrão!"</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, inicie sessão com a sua Conta Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nome de utilizador (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Palavra-passe"</string>
+ <string name="lockscreen_glogin_submit_button">"Iniciar sessão"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nome de utilizador ou palavra-passe inválidos."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"A carregar..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Ligue o carregador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está a ficar fraca:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"resta menos de <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="status_bar_no_notifications_title">"Sem notificações"</string>
+ <string name="status_bar_ongoing_events_title">"Em curso"</string>
+ <string name="status_bar_latest_events_title">"Notificações"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"A carregar..."</string>
+ <string name="battery_low_title">"Ligue o carregador"</string>
+ <string name="battery_low_subtitle">"A bateria está a ficar fraca:"</string>
+ <string name="battery_low_percent_format">"resta menos de <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"O teste de fábrica falhou"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"A acção FACTORY_TEST apenas é suportada para pacotes instalados em /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Não foi localizado qualquer pacote que forneça a acção FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleccione OK para continuar ou Cancelar para permanecer na página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"O teste de fábrica falhou"</string>
+ <string name="factorytest_not_system">"A acção FACTORY_TEST apenas é suportada para pacotes instalados em /system/app."</string>
+ <string name="factorytest_no_action">"Não foi localizado qualquer pacote que forneça a acção FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleccione OK para continuar ou Cancelar para permanecer na página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Não tem autorização para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado para a área de transferência."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mais"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espaço"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"introduzir"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"eliminar"</string>
- <string name="search_go" msgid="8298016669822141719">"Pesquisar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
+ <string name="save_password_message">"Quer que o browser memorize esta palavra-passe?"</string>
+ <string name="save_password_notnow">"Agora não"</string>
+ <string name="save_password_remember">"Lembrar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"Não tem autorização para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado para a área de transferência."</string>
+ <string name="more_item_label">"Mais"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espaço"</string>
+ <string name="menu_enter_shortcut_label">"introduzir"</string>
+ <string name="menu_delete_shortcut_label">"eliminar"</string>
+ <string name="search_go">"Pesquisar"</string>
+ <string name="oneMonthDurationPast">"Há 1 mês"</string>
+ <string name="beforeOneMonthDurationPast">"Há·mais·de·1·mês"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Há 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"Há 1 segundo"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Há 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"Há 1 minuto"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Há 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Há 1 hora"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"daqui a 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"daqui a 1 segundo"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"daqui a 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"daqui a 1 minuto"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"daqui a 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"daqui a 1 hora"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Há 1 seg"</item>
- <item quantity="other" msgid="3699169366650930415">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
+ <item quantity="one">"Há 1 seg"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"há 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"há 1 min"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Há 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Há 1 hora"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"daqui a 1 seg"</item>
- <item quantity="other" msgid="5495880108825805108">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
+ <item quantity="one">"daqui a 1 seg"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"daqui a 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"daqui a 1 min"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"daqui a 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"daqui a 1 hora"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"a %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"às %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"em %s"</string>
- <string name="day" msgid="8144195776058119424">"dia"</string>
- <string name="days" msgid="4774547661021344602">"dias"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"minutos"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"seg"</string>
- <string name="seconds" msgid="3161515347216589235">"seg"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"ano"</string>
- <string name="years" msgid="6881577717993213522">"anos"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos os dias úteis (Seg-Sex)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente à/ao <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensalmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Impossível reproduzir vídeo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Lamentamos, este vídeo não é válido para transmissão em sequência neste dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Lamentamos, não é possível reproduzir este vídeo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"meio-dia"</string>
- <string name="Noon" msgid="3342127745230013127">"Meio-dia"</string>
- <string name="midnight" msgid="7166259508850457595">"meia-noite"</string>
- <string name="Midnight" msgid="5630806906897892201">"Meia-noite"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar selecção de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar tudo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar tudo"</string>
- <string name="paste" msgid="5629880836805036433">"Colar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Adicionar \"%s\" ao dicionário"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pouco espaço livre"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"O espaço de armazenamento do telefone está a ficar reduzido."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
- <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desactivar"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Concluir acção utilizando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar predefinição em Definições iniciais > Aplicações > Gerir aplicações."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar uma acção"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nenhuma aplicação pode efectuar esta acção."</string>
- <string name="aerr_title" msgid="653922989522758100">"Lamentamos."</string>
- <string name="aerr_application" msgid="4683614104336409186">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
- <string name="aerr_process" msgid="1551785535966089511">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou de forma inesperada. Tente novamente."</string>
- <string name="anr_title" msgid="3100070910664756057">"Lamentamos!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (na aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_process" msgid="1246866008169975783">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder."</string>
- <string name="force_close" msgid="3653416315450806396">"Forçar fecho"</string>
+ <string name="preposition_for_date">"a %s"</string>
+ <string name="preposition_for_time">"às %s"</string>
+ <string name="preposition_for_year">"em %s"</string>
+ <string name="day">"dia"</string>
+ <string name="days">"dias"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"minutos"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"seg"</string>
+ <string name="seconds">"seg"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"ano"</string>
+ <string name="years">"anos"</string>
+ <string name="every_weekday">"Todos os dias úteis (Seg-Sex)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente à/ao <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensalmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"Impossível reproduzir vídeo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Lamentamos, este vídeo não é válido para transmissão em sequência neste dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Lamentamos, não é possível reproduzir este vídeo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"meio-dia"</string>
+ <string name="Noon">"Meio-dia"</string>
+ <string name="midnight">"meia-noite"</string>
+ <string name="Midnight">"Meia-noite"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar tudo"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Parar selecção de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar tudo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar tudo"</string>
+ <string name="paste">"Colar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Adicionar \"%s\" ao dicionário"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Pouco espaço livre"</string>
+ <string name="low_internal_storage_view_text">"O espaço de armazenamento do telefone está a ficar reduzido."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atenção"</string>
+ <string name="capital_on">"Activado"</string>
+ <string name="capital_off">"Desactivar"</string>
+ <string name="whichApplication">"Concluir acção utilizando"</string>
+ <string name="alwaysUse">"Utilizar por predefinição para esta acção."</string>
+ <string name="clearDefaultHintMsg">"Limpar predefinição em Definições iniciais > Aplicações > Gerir aplicações."</string>
+ <string name="chooseActivity">"Seleccionar uma acção"</string>
+ <string name="noApplications">"Nenhuma aplicação pode efectuar esta acção."</string>
+ <string name="aerr_title">"Lamentamos."</string>
+ <string name="aerr_application">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
+ <string name="aerr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou de forma inesperada. Tente novamente."</string>
+ <string name="anr_title">"Lamentamos!"</string>
+ <string name="anr_activity_application">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (na aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_activity_process">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_application_process">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder."</string>
+ <string name="force_close">"Forçar fecho"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Esperar"</string>
- <string name="debug" msgid="9103374629678531849">"Depuração"</string>
- <string name="sendText" msgid="5132506121645618310">"Seleccionar uma acção para texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"A reproduzir através de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume da chamada recebida"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada recebida em Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume de notificações"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
+ <string name="wait">"Esperar"</string>
+ <string name="debug">"Depuração"</string>
+ <string name="sendText">"Seleccionar uma acção para texto"</string>
+ <string name="volume_ringtone">"Volume da campainha"</string>
+ <string name="volume_music">"Volume de multimédia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"A reproduzir através de Bluetooth"</string>
+ <string name="volume_call">"Volume da chamada recebida"</string>
+ <string name="volume_bluetooth_call">"Volume de chamada recebida em Bluetooth"</string>
+ <string name="volume_alarm">"Volume do alarme"</string>
+ <string name="volume_notification">"Volume de notificações"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Toque predefinido"</string>
+ <string name="ringtone_default_with_actual">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Toques"</string>
+ <string name="ringtone_unknown">"Toque desconhecido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi disponível"</item>
+ <item quantity="other">"Redes Wi-Fi disponíveis"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
- <item quantity="other" msgid="7915895323644292768">"Abrir redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi aberta disponível"</item>
+ <item quantity="other">"Abrir redes Wi-Fi disponíveis"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicação desconhecida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Está a ser enviado um grande número de mensagens SMS. Seleccione \"OK\" para continuar ou \"Cancelar\" para parar o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predefinido"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar tudo"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"A carregar..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Ligado através de USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Ligou o telefone ao computador através de USB. Seleccione \"Montar\" se pretender copiar ficheiros entre o computador e o cartão SD do telefone."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Não montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Existe um problema ao utilizar o cartão SD para armazenamento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Ligado através de USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleccione para copiar ficheiro para/do seu computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar armazenamento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Opte por desactivar o armazenamento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desactivar armazenamento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar o armazenamento USB, certifique-se de que o desmontou no anfitrião USB. Seleccione \"Desactivar\" para desactivar o armazenamento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desactivar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Detectámos um problema ao desactivar o armazenamento USB. Verifique para se certificar de que desmontou o anfitrião USB e, em seguida, tente novamente."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatar cartão SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Tem a certeza de que pretende formatar o cartão SD? Perder-se-ão todos os dados no cartão."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatar"</string>
+ <string name="select_character">"Introduzir carácter"</string>
+ <string name="sms_control_default_app_name">"Aplicação desconhecida"</string>
+ <string name="sms_control_title">"A enviar mensagens SMS"</string>
+ <string name="sms_control_message">"Está a ser enviado um grande número de mensagens SMS. Seleccione \"OK\" para continuar ou \"Cancelar\" para parar o envio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Definir"</string>
+ <string name="default_permission_group">"Predefinido"</string>
+ <string name="no_permissions">"Não são necessárias permissões"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar tudo"</b></string>
+ <string name="googlewebcontenthelper_loading">"A carregar..."</string>
+ <string name="usb_storage_title">"Ligado através de USB"</string>
+ <string name="usb_storage_message">"Ligou o telefone ao computador através de USB. Seleccione \"Montar\" se pretender copiar ficheiros entre o computador e o cartão SD do telefone."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"Não montar"</string>
+ <string name="usb_storage_error_message">"Existe um problema ao utilizar o cartão SD para armazenamento USB."</string>
+ <string name="usb_storage_notification_title">"Ligado através de USB"</string>
+ <string name="usb_storage_notification_message">"Seleccione para copiar ficheiro para/do seu computador."</string>
+ <string name="usb_storage_stop_notification_title">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Opte por desactivar o armazenamento USB."</string>
+ <string name="usb_storage_stop_title">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar o armazenamento USB, certifique-se de que o desmontou no anfitrião USB. Seleccione \"Desactivar\" para desactivar o armazenamento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desactivar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Detectámos um problema ao desactivar o armazenamento USB. Verifique para se certificar de que desmontou o anfitrião USB e, em seguida, tente novamente."</string>
+ <string name="extmedia_format_title">"Formatar cartão SD"</string>
+ <string name="extmedia_format_message">"Tem a certeza de que pretende formatar o cartão SD? Perder-se-ão todos os dados no cartão."</string>
+ <string name="extmedia_format_button_format">"Formatar"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"A preparar cartão SD"</string>
+ <string name="select_input_method">"Seleccionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"A preparar cartão SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Cartão SD vazio"</string>
+ <string name="ext_media_nofs_notification_title">"Cartão SD vazio"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Cartão SD danificado"</string>
+ <string name="ext_media_unmountable_notification_title">"Cartão SD danificado"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Cartão SD removido de forma inesperada"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmonte o cartão SD antes de retirá-lo para evitar a perda de dados."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"É seguro retirar o cartão SD"</string>
+ <string name="ext_media_badremoval_notification_title">"Cartão SD removido de forma inesperada"</string>
+ <string name="ext_media_badremoval_notification_message">"Desmonte o cartão SD antes de retirá-lo para evitar a perda de dados."</string>
+ <string name="ext_media_safe_unmount_notification_title">"É seguro retirar o cartão SD"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Cartão SD removido"</string>
+ <string name="ext_media_nomedia_notification_title">"Cartão SD removido"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Nenhuma actividade correspondente encontrada"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar estatísticas de utilização de componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite a modificação de estatísticas de utilização de componentes recolhidas. Não se destina a utilização por aplicações normais."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocar duas vezes para controlar o zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erro ao inchar miniaplicação"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Pesquisar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Seguinte"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Criar contacto"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Nenhuma actividade correspondente encontrada"</string>
+ <string name="permlab_pkgUsageStats">"actualizar estatísticas de utilização de componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite a modificação de estatísticas de utilização de componentes recolhidas. Não se destina a utilização por aplicações normais."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tocar duas vezes para controlar o zoom"</string>
+ <string name="gadget_host_error_inflating">"Erro ao inchar miniaplicação"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Pesquisar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Seguinte"</string>
+ <string name="ime_action_done">"Concluído"</string>
+ <string name="ime_action_default">"Executar"</string>
+ <string name="dial_number_using">"Marcar número"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Criar contacto"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a241e36..4f84872 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Kb"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"Kb"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<sem título>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconhecido)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de conexão ou código MMI inválido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"O serviço foi ativado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"O serviço foi ativado para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"O serviço foi desativado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registro bem-sucedido."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Exclusão bem-sucedida."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Senha incorreta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI concluído."</string>
- <string name="badPin" msgid="5085454289896032547">"O PIN antigo digitado não está correto."</string>
- <string name="badPuk" msgid="5702522162746042460">"O PUK digitado não está correto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Os PINs digitados não correspondem."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Digite um PIN com 4 a 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o cartão SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID do chamador de entrada"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID do chamador de saída"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamada"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Bloqueio de chamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Alteração da senha"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Alteração do PIN"</string>
+ <string name="untitled">"<sem título>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nenhum número de telefone)"</string>
+ <string name="unknownName">"(Desconhecido)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correio de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de conexão ou código MMI inválido."</string>
+ <string name="serviceEnabled">"O serviço foi ativado."</string>
+ <string name="serviceEnabledFor">"O serviço foi ativado para:"</string>
+ <string name="serviceDisabled">"O serviço foi desativado."</string>
+ <string name="serviceRegistered">"Registro bem-sucedido."</string>
+ <string name="serviceErased">"Exclusão bem-sucedida."</string>
+ <string name="passwordIncorrect">"Senha incorreta."</string>
+ <string name="mmiComplete">"MMI concluído."</string>
+ <string name="badPin">"O PIN antigo digitado não está correto."</string>
+ <string name="badPuk">"O PUK digitado não está correto."</string>
+ <string name="mismatchPin">"Os PINs digitados não correspondem."</string>
+ <string name="invalidPin">"Digite um PIN com 4 a 8 números."</string>
+ <string name="needPuk">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2">"Digite o PUK2 para desbloquear o cartão SIM."</string>
+ <string name="ClipMmi">"ID do chamador de entrada"</string>
+ <string name="ClirMmi">"ID do chamador de saída"</string>
+ <string name="CfMmi">"Encaminhamento de chamada"</string>
+ <string name="CwMmi">"Chamada em espera"</string>
+ <string name="BaMmi">"Bloqueio de chamadas"</string>
+ <string name="PwdMmi">"Alteração da senha"</string>
+ <string name="PinMmi">"Alteração do PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"A configuração do ID do chamador não pode ser alterada."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"O serviço de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos os serviços de voz/SMS estão bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dados"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Assíncrono"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronizar"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacote"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
+ <string name="serviceNotProvisioned">"O serviço não foi habilitado."</string>
+ <string name="CLIRPermanent">"A configuração do ID do chamador não pode ser alterada."</string>
+ <string name="RestrictedChangedTitle">"Acesso restrito alterado"</string>
+ <string name="RestrictedOnData">"O serviço de dados está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"O serviço de emergência está bloqueado."</string>
+ <string name="RestrictedOnNormal">"O serviço de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos os serviços de voz/SMS estão bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Dados"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Assíncrono"</string>
+ <string name="serviceClassDataSync">"Sincronizar"</string>
+ <string name="serviceClassPacket">"Pacote"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"A página da web contém um erro."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Não foi possível encontrar o URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"O esquema de autenticação do site não é suportado."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Falha na autenticação."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Falha na autenticação por meio do servidor proxy."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Falha na conexão com o servidor."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Falha de comunicação do servidor. Tente novamente mais tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"O tempo limite de conexão com o servidor esgotou."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"A página contém muitos redirecionamentos do servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"O protocolo não é suportado."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Não foi possível estabelecer uma conexão segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Não foi possível abrir a página porque o URL é inválido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Não foi possível acessar o arquivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"O arquivo solicitado não foi encontrado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Há muitas solicitações sendo processadas. Tente novamente mais tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizar"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizar"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"O armazenamento do telefone está cheio! Exclua alguns arquivos para liberar espaço."</string>
- <string name="me" msgid="6545696007631404292">"Eu"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opções do telefone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Ativar sem fio"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desativar a rede sem fio"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloquear tela"</string>
- <string name="power_off" msgid="4266614107412865048">"Desligar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Encerrando…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"O seu telefone será desligado."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nenhum aplicativo recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opções do telefone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo de avião ATIVADO"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo de avião DESATIVADO"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite que os aplicativos façam coisas que possam gerar gastos."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lê e grava o seu SMS, e-mail e outras mensagens."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Suas informações pessoais"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acessa diretamente os seus contatos e agenda armazenados no telefone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Seu local"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitora o seu local físico."</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicação da rede"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite que os aplicativos acessem diversos recursos de rede."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Suas Contas do Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acessar as Contas do Google disponíveis."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acessa o hardware diretamente no aparelho."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas telefônicas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitora, registra e processa chamadas telefônicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acesso de nível inferior e controle do sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ferramentas de desenvolvimento"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Recursos necessários apenas para desenvolvedores de aplicativo."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"A página da web contém um erro."</string>
+ <string name="httpErrorLookup">"Não foi possível encontrar o URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"O esquema de autenticação do site não é suportado."</string>
+ <string name="httpErrorAuth">"Falha na autenticação."</string>
+ <string name="httpErrorProxyAuth">"Falha na autenticação por meio do servidor proxy."</string>
+ <string name="httpErrorConnect">"Falha na conexão com o servidor."</string>
+ <string name="httpErrorIO">"Falha de comunicação do servidor. Tente novamente mais tarde."</string>
+ <string name="httpErrorTimeout">"O tempo limite de conexão com o servidor esgotou."</string>
+ <string name="httpErrorRedirectLoop">"A página contém muitos redirecionamentos do servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"O protocolo não é suportado."</string>
+ <string name="httpErrorFailedSslHandshake">"Não foi possível estabelecer uma conexão segura."</string>
+ <string name="httpErrorBadUrl">"Não foi possível abrir a página porque o URL é inválido."</string>
+ <string name="httpErrorFile">"Não foi possível acessar o arquivo."</string>
+ <string name="httpErrorFileNotFound">"O arquivo solicitado não foi encontrado."</string>
+ <string name="httpErrorTooManyRequests">"Há muitas solicitações sendo processadas. Tente novamente mais tarde."</string>
+ <string name="contentServiceSync">"Sincronizar"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronizar"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"O armazenamento do telefone está cheio! Exclua alguns arquivos para liberar espaço."</string>
+ <string name="me">"Eu"</string>
+ <string name="power_dialog">"Opções do telefone"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Ativar sem fio"</string>
+ <string name="turn_off_radio">"Desativar a rede sem fio"</string>
+ <string name="screen_lock">"Bloquear tela"</string>
+ <string name="power_off">"Desligar"</string>
+ <string name="shutdown_progress">"Encerrando…"</string>
+ <string name="shutdown_confirm">"O seu telefone será desligado."</string>
+ <string name="no_recent_tasks">"Nenhum aplicativo recente."</string>
+ <string name="global_actions">"Opções do telefone"</string>
+ <string name="global_action_lock">"Bloquear tela"</string>
+ <string name="global_action_power_off">"Desligar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"Som DESATIVADO"</string>
+ <string name="global_action_silent_mode_off_status">"O som está ATIVADO"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo de avião"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modo de avião ATIVADO"</string>
+ <string name="global_actions_airplane_mode_off_status">"Modo de avião DESATIVADO"</string>
+ <string name="safeMode">"Modo de segurança"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Serviços que geram gastos"</string>
+ <string name="permgroupdesc_costMoney">"Permite que os aplicativos façam coisas que possam gerar gastos."</string>
+ <string name="permgrouplab_messages">"Suas mensagens"</string>
+ <string name="permgroupdesc_messages">"Lê e grava o seu SMS, e-mail e outras mensagens."</string>
+ <string name="permgrouplab_personalInfo">"Suas informações pessoais"</string>
+ <string name="permgroupdesc_personalInfo">"Acessa diretamente os seus contatos e agenda armazenados no telefone."</string>
+ <string name="permgrouplab_location">"Seu local"</string>
+ <string name="permgroupdesc_location">"Monitora o seu local físico."</string>
+ <string name="permgrouplab_network">"Comunicação da rede"</string>
+ <string name="permgroupdesc_network">"Permite que os aplicativos acessem diversos recursos de rede."</string>
+ <string name="permgrouplab_accounts">"Suas Contas do Google"</string>
+ <string name="permgroupdesc_accounts">"Acessar as Contas do Google disponíveis."</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acessa o hardware diretamente no aparelho."</string>
+ <string name="permgrouplab_phoneCalls">"Chamadas telefônicas"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitora, registra e processa chamadas telefônicas."</string>
+ <string name="permgrouplab_systemTools">"Ferramentas do sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acesso de nível inferior e controle do sistema."</string>
+ <string name="permgrouplab_developmentTools">"Ferramentas de desenvolvimento"</string>
+ <string name="permgroupdesc_developmentTools">"Recursos necessários apenas para desenvolvedores de aplicativo."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite que o aplicativo desative a barra de status ou adicione e remova ícones do sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/recolher barra de status"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite que o aplicativo expanda ou recolha a barra de status."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar chamadas enviadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite que o aplicativo processe chamadas enviadas e altere o número a ser discado. Aplicativos maliciosos podem monitorar, redirecionar ou impedir a realização de chamadas."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"receber SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite que o aplicativo receba e processe mensagens SMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"receber MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite que o aplicativo receba e processe mensagens MMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensagens SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite que o aplicativo envie mensagens SMS. Aplicativos maliciosos podem gerar gastos enviando mensagens sem a sua confirmação."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ler SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite que o aplicativo leia mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem ler as suas mensagens confidenciais."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS ou MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite que o aplicativo grave mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem excluir suas mensagens."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"receber WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite que o aplicativo receba e processe mensagens WAP. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicativos em execução"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que o aplicativo recupere as informações sobre tarefas em execução no momento ou recentemente. Pode permitir que aplicativos maliciosos descubram informações particulares sobre outros aplicativos."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicativos em execução"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que um aplicativo mova as tarefas para o primeiro e para o segundo planos. Aplicativos maliciosos podem se forçar à frente sem o seu controle."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"ativar depuração do aplicativo"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que um aplicativo ative a depuração de outro aplicativo. Aplicativos maliciosos podem usar isso para encerrar outros aplicativos."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite que um aplicativo altere a configuração atual, como o local ou o tamanho geral da fonte."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar outros aplicativos"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite que um aplicativo reinicie forçosamente outros aplicativos."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forçar fechamento do aplicativo"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite que um aplicativo force o fechamento de qualquer atividade que esteja em primeiro plano. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar o estado interno do sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite que um aplicativo recupere o estado interno do sistema. Aplicativos maliciosos podem recuperar uma grande variedade de informações privadas e de segurança que normalmente não precisariam."</string>
+ <string name="permlab_statusBar">"desativar ou modificar a barra de status"</string>
+ <string name="permdesc_statusBar">"Permite que o aplicativo desative a barra de status ou adicione e remova ícones do sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/recolher barra de status"</string>
+ <string name="permdesc_expandStatusBar">"Permite que o aplicativo expanda ou recolha a barra de status."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar chamadas enviadas"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite que o aplicativo processe chamadas enviadas e altere o número a ser discado. Aplicativos maliciosos podem monitorar, redirecionar ou impedir a realização de chamadas."</string>
+ <string name="permlab_receiveSms">"receber SMS"</string>
+ <string name="permdesc_receiveSms">"Permite que o aplicativo receba e processe mensagens SMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_receiveMms">"receber MMS"</string>
+ <string name="permdesc_receiveMms">"Permite que o aplicativo receba e processe mensagens MMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_sendSms">"enviar mensagens SMS"</string>
+ <string name="permdesc_sendSms">"Permite que o aplicativo envie mensagens SMS. Aplicativos maliciosos podem gerar gastos enviando mensagens sem a sua confirmação."</string>
+ <string name="permlab_readSms">"ler SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permite que o aplicativo leia mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem ler as suas mensagens confidenciais."</string>
+ <string name="permlab_writeSms">"editar SMS ou MMS"</string>
+ <string name="permdesc_writeSms">"Permite que o aplicativo grave mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem excluir suas mensagens."</string>
+ <string name="permlab_receiveWapPush">"receber WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite que o aplicativo receba e processe mensagens WAP. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_getTasks">"recuperar aplicativos em execução"</string>
+ <string name="permdesc_getTasks">"Permite que o aplicativo recupere as informações sobre tarefas em execução no momento ou recentemente. Pode permitir que aplicativos maliciosos descubram informações particulares sobre outros aplicativos."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicativos em execução"</string>
+ <string name="permdesc_reorderTasks">"Permite que um aplicativo mova as tarefas para o primeiro e para o segundo planos. Aplicativos maliciosos podem se forçar à frente sem o seu controle."</string>
+ <string name="permlab_setDebugApp">"ativar depuração do aplicativo"</string>
+ <string name="permdesc_setDebugApp">"Permite que um aplicativo ative a depuração de outro aplicativo. Aplicativos maliciosos podem usar isso para encerrar outros aplicativos."</string>
+ <string name="permlab_changeConfiguration">"alterar as suas configurações de UI"</string>
+ <string name="permdesc_changeConfiguration">"Permite que um aplicativo altere a configuração atual, como a localidade ou tamanho geral da fonte."</string>
+ <string name="permlab_restartPackages">"reiniciar outros aplicativos"</string>
+ <string name="permdesc_restartPackages">"Permite que um aplicativo reinicie forçosamente outros aplicativos."</string>
+ <string name="permlab_forceBack">"forçar fechamento do aplicativo"</string>
+ <string name="permdesc_forceBack">"Permite que um aplicativo force o fechamento de qualquer atividade que esteja em primeiro plano. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_dump">"recuperar o estado interno do sistema"</string>
+ <string name="permdesc_dump">"Permite que um aplicativo recupere o estado interno do sistema. Aplicativos maliciosos podem recuperar uma grande variedade de informações privadas e de segurança que normalmente não precisariam."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorar e controlar toda inicialização de aplicativo"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite que um aplicativo monitore e controle a maneira como o sistema inicia as atividades. Aplicativos maliciosos podem comprometer todo o sistema. Essa permissão é necessária apenas para desenvolvimento, nunca para uso normal do telefone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar transmissão removida do pacote"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite que um aplicativo transmita uma notificação informando que um pacote de aplicativo foi removido. Aplicativos maliciosos podem usar isso para encerrar qualquer outro aplicativo em execução."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar transmissão SMS recebida"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite que um aplicativo transmita uma notificação de que uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagens SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar transmissão WAP-PUSH recebida"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite que um aplicativo transmita uma notificação de que uma mensagem WAP PUSH foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagem MMS ou substituir silenciosamente o conteúdo de qualquer página da web por variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar número de processos em execução"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite que um aplicativo controle o número máximo de processos que serão executados. Aplicativos normais não precisam disso em momento algum."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"fechar todos os aplicativos em segundo plano"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite que um aplicativo controle se as atividades são sempre concluídas assim que vão para o segundo plano. Aplicativos normais não precisam disso em momento algum."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estatísticas da bateria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas de bateria coletadas. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorar e controlar toda inicialização de aplicativo"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite que um aplicativo monitore e controle a maneira como o sistema inicia as atividades. Aplicativos maliciosos podem comprometer todo o sistema. Essa permissão é necessária apenas para desenvolvimento, nunca para uso normal do telefone."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar transmissão removida do pacote"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite que um aplicativo transmita uma notificação informando que um pacote de aplicativo foi removido. Aplicativos maliciosos podem usar isso para encerrar qualquer outro aplicativo em execução."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar transmissão SMS recebida"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite que um aplicativo transmita uma notificação de que uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagens SMS."</string>
+ <string name="permlab_broadcastWapPush">"enviar transmissão WAP-PUSH recebida"</string>
+ <string name="permdesc_broadcastWapPush">"Permite que um aplicativo transmita uma notificação de que uma mensagem WAP PUSH foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagem MMS ou substituir silenciosamente o conteúdo de qualquer página da web por variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"limitar número de processos em execução"</string>
+ <string name="permdesc_setProcessLimit">"Permite que um aplicativo controle o número máximo de processos que serão executados. Aplicativos normais não precisam disso em momento algum."</string>
+ <string name="permlab_setAlwaysFinish">"fechar todos os aplicativos em segundo plano"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite que um aplicativo controle se as atividades são sempre concluídas assim que vão para o segundo plano. Aplicativos normais não precisam disso em momento algum."</string>
+ <string name="permlab_batteryStats">"modificar estatísticas da bateria"</string>
+ <string name="permdesc_batteryStats">"Permite a modificação das estatísticas de bateria coletadas. Não deve ser usado por aplicativos normais."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"exibir janelas não autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas ao uso pela interface de usuário do sistema interno. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"exibir alertas de nível do sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite que um aplicativo mostre janelas de alerta do sistema. Aplicativos maliciosos podem assumir o controle de toda a tela do telefone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade de animação global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite que um aplicativo altere a velocidade de animação global (animação mais rápida ou mais lenta) a qualquer momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gerenciar tokens do aplicativo"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite que os aplicativos criem e gerenciem seus próprios tokens, ignorando a ordem Z normal. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"pressionar as teclas e os botões de controle"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite que um aplicativo use seus próprios eventos de entrada (pressionamentos de teclas etc.) em outros aplicativos. Aplicativos maliciosos podem usar isso para assumir o controle do telefone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrar o que você digita e as ações que realiza"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite que os aplicativos vejam as teclas que você pressiona, mesmo quando estiver interagindo com outro aplicativo (como ao digitar uma senha). Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite que o detentor se sujeite à interface de nível superior de um método de entrada. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais de Linux para os aplicativos"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"executar sempre o aplicativo"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite que um aplicativo torne partes de si mesmo persistentes, de modo que o sistema não possa usar essas partes para outros aplicativos."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"excluir aplicativos"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite que um aplicativo exclua pacotes do Android. Aplicativos maliciosos podem usar isso para excluir aplicativos importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"excluir dados de outros aplicativos"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite que um aplicativo limpe os dados do usuário."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"excluir os caches de outros aplicativos"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite que um aplicativo exclua os arquivos do cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento do aplicativo"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite que um aplicativo recupere seu código, seus dados e os tamanhos do cache."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar diretamente os aplicativos"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite que um aplicativo instale pacotes novos ou atualizados do Android. Aplicativos maliciosos podem usar isso para adicionar novos aplicativos com permissões arbitrariamente avançadas."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"excluir todos os dados de cache do aplicativo"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ler arquivos de registro do sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"ativar ou desativar os componentes do aplicativo"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite que um aplicativo altere se um componente de outro aplicativo está ativado ou não. Aplicativos maliciosos podem usar isso para desativar recursos de telefone importantes. É preciso ter cuidado com a permissão, pois é possível deixar os componentes do aplicativo em um estado inutilizável, inconsistente ou instável."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"definir os aplicativos preferidos"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite que um aplicativo modifique os seus aplicativos preferidos. Isso pode permitir que aplicativos maliciosos alterem silenciosamente os aplicativos em execução, falsificando os seus aplicativos existentes para coletar os seus dados particulares."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar configurações globais do sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite que um aplicativo modifique os dados de configuração do sistema. Aplicativos maliciosos podem corromper a configuração do seu sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar configurações do sistema de segurança"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite que um aplicativo modifique os dados de configuração de segurança dos sistemas. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar o mapa de serviços do Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite que um aplicativo modifique o mapa de serviços do Google. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automaticamente na inicialização"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que um aplicativo inicie assim que o sistema conclui a inicialização. Isso pode retardar a inicialização do telefone e permitir que o aplicativo deixe o telefone mais lento por estar sempre em execução."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar transmissão persistente"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite que um aplicativo envie uma transmissão persistente, que permanece após o término da transmissão. Aplicativos maliciosos podem tornar o telefone lento ou instável fazendo com que ele use muita memória."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ler dados do contato"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite que um aplicativo leia todos os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar os seus dados para outras pessoas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"gravar dados de contato"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite que um aplicativo modifique os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados de contato."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"gravar dados do proprietário"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite que um aplicativo modifique os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar dados do proprietário."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ler dados do proprietário"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite que um aplicativo leia os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para ler os dados de proprietário do telefone."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ler dados da agenda"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite que um aplicativo leia todos os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar eventos da sua agenda para outras pessoas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"gravar dados da agenda"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite que um aplicativo modifique os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados da agenda."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fontes de locais fictícios para teste"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Cria fontes de locais fictícios para teste. Aplicativos maliciosos podem usar isso para substituir o local e/ou o status retornado pelas fontes de locais reais como GPS ou provedores de rede."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acessar comandos extras do provedor de localização"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Acessa comandos extras do provedor de localização. Aplicativos maliciosos podem usar isso para interferir na operação do GPS ou de outras fontes de localização."</string>
+ <string name="permlab_internalSystemWindow">"exibir janelas não autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite a criação de janelas destinadas ao uso pela interface de usuário do sistema interno. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_systemAlertWindow">"exibir alertas de nível do sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite que um aplicativo mostre janelas de alerta do sistema. Aplicativos maliciosos podem assumir o controle de toda a tela do telefone."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidade de animação global"</string>
+ <string name="permdesc_setAnimationScale">"Permite que um aplicativo altere a velocidade de animação global (animação mais rápida ou mais lenta) a qualquer momento."</string>
+ <string name="permlab_manageAppTokens">"gerenciar tokens do aplicativo"</string>
+ <string name="permdesc_manageAppTokens">"Permite que os aplicativos criem e gerenciem seus próprios tokens, ignorando a ordem Z normal. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_injectEvents">"pressionar as teclas e os botões de controle"</string>
+ <string name="permdesc_injectEvents">"Permite que um aplicativo use seus próprios eventos de entrada (pressionamentos de teclas etc.) em outros aplicativos. Aplicativos maliciosos podem usar isso para assumir o controle do telefone."</string>
+ <string name="permlab_readInputState">"registrar o que você digita e as ações que realiza"</string>
+ <string name="permdesc_readInputState">"Permite que os aplicativos vejam as teclas que você pressiona, mesmo quando estiver interagindo com outro aplicativo (como ao digitar uma senha). Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_bindInputMethod">"vincular a um método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite que o detentor se sujeite à interface de nível superior de um método de entrada. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_setOrientation">"alterar orientação da tela"</string>
+ <string name="permdesc_setOrientation">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar sinais de Linux para os aplicativos"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string>
+ <string name="permlab_persistentActivity">"executar sempre o aplicativo"</string>
+ <string name="permdesc_persistentActivity">"Permite que um aplicativo torne partes de si mesmo persistentes, de modo que o sistema não possa usar essas partes para outros aplicativos."</string>
+ <string name="permlab_deletePackages">"excluir aplicativos"</string>
+ <string name="permdesc_deletePackages">"Permite que um aplicativo exclua pacotes do Android. Aplicativos maliciosos podem usar isso para excluir aplicativos importantes."</string>
+ <string name="permlab_clearAppUserData">"excluir dados de outros aplicativos"</string>
+ <string name="permdesc_clearAppUserData">"Permite que um aplicativo limpe os dados do usuário."</string>
+ <string name="permlab_deleteCacheFiles">"excluir os caches de outros aplicativos"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite que um aplicativo exclua os arquivos do cache."</string>
+ <string name="permlab_getPackageSize">"medir espaço de armazenamento do aplicativo"</string>
+ <string name="permdesc_getPackageSize">"Permite que um aplicativo recupere seu código, seus dados e os tamanhos do cache."</string>
+ <string name="permlab_installPackages">"instalar diretamente os aplicativos"</string>
+ <string name="permdesc_installPackages">"Permite que um aplicativo instale pacotes novos ou atualizados do Android. Aplicativos maliciosos podem usar isso para adicionar novos aplicativos com permissões arbitrariamente avançadas."</string>
+ <string name="permlab_clearAppCache">"excluir todos os dados de cache do aplicativo"</string>
+ <string name="permdesc_clearAppCache">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string>
+ <string name="permlab_readLogs">"ler arquivos de registro do sistema"</string>
+ <string name="permdesc_readLogs">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string>
+ <string name="permlab_diagnostic">"ler/gravar em recursos pertencentes ao diag"</string>
+ <string name="permdesc_diagnostic">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string>
+ <string name="permlab_changeComponentState">"ativar ou desativar os componentes do aplicativo"</string>
+ <string name="permdesc_changeComponentState">"Permite que um aplicativo altere se um componente de outro aplicativo está ativado ou não. Aplicativos maliciosos podem usar isso para desativar recursos de telefone importantes. É preciso ter cuidado com a permissão, pois é possível deixar os componentes do aplicativo em um estado inutilizável, inconsistente ou instável."</string>
+ <string name="permlab_setPreferredApplications">"definir os aplicativos preferidos"</string>
+ <string name="permdesc_setPreferredApplications">"Permite que um aplicativo modifique os seus aplicativos preferidos. Isso pode permitir que aplicativos maliciosos alterem silenciosamente os aplicativos em execução, falsificando os seus aplicativos existentes para coletar os seus dados particulares."</string>
+ <string name="permlab_writeSettings">"modificar configurações globais do sistema"</string>
+ <string name="permdesc_writeSettings">"Permite que um aplicativo modifique os dados de configuração do sistema. Aplicativos maliciosos podem corromper a configuração do seu sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar configurações do sistema de segurança"</string>
+ <string name="permdesc_writeSecureSettings">"Permite que um aplicativo modifique os dados de configuração de segurança dos sistemas. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_writeGservices">"modificar o mapa de serviços do Google"</string>
+ <string name="permdesc_writeGservices">"Permite que um aplicativo modifique o mapa de serviços do Google. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automaticamente na inicialização"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que um aplicativo inicie assim que o sistema conclui a inicialização. Isso pode retardar a inicialização do telefone e permitir que o aplicativo deixe o telefone mais lento por estar sempre em execução."</string>
+ <string name="permlab_broadcastSticky">"enviar transmissão persistente"</string>
+ <string name="permdesc_broadcastSticky">"Permite que um aplicativo envie uma transmissão persistente, que permanece após o término da transmissão. Aplicativos maliciosos podem tornar o telefone lento ou instável fazendo com que ele use muita memória."</string>
+ <string name="permlab_readContacts">"ler dados do contato"</string>
+ <string name="permdesc_readContacts">"Permite que um aplicativo leia todos os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar os seus dados para outras pessoas."</string>
+ <string name="permlab_writeContacts">"gravar dados de contato"</string>
+ <string name="permdesc_writeContacts">"Permite que um aplicativo modifique os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados de contato."</string>
+ <string name="permlab_writeOwnerData">"gravar dados do proprietário"</string>
+ <string name="permdesc_writeOwnerData">"Permite que um aplicativo modifique os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar dados do proprietário."</string>
+ <string name="permlab_readOwnerData">"ler dados do proprietário"</string>
+ <string name="permdesc_readOwnerData">"Permite que um aplicativo leia os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para ler os dados de proprietário do telefone."</string>
+ <string name="permlab_readCalendar">"ler dados da agenda"</string>
+ <string name="permdesc_readCalendar">"Permite que um aplicativo leia todos os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar eventos da sua agenda para outras pessoas."</string>
+ <string name="permlab_writeCalendar">"gravar dados da agenda"</string>
+ <string name="permdesc_writeCalendar">"Permite que um aplicativo modifique os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados da agenda."</string>
+ <string name="permlab_accessMockLocation">"fontes de locais fictícios para teste"</string>
+ <string name="permdesc_accessMockLocation">"Cria fontes de locais fictícios para teste. Aplicativos maliciosos podem usar isso para substituir o local e/ou o status retornado pelas fontes de locais reais como GPS ou provedores de rede."</string>
+ <string name="permlab_accessLocationExtraCommands">"acessar comandos extras do provedor de localização"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Acessa comandos extras do provedor de localização. Aplicativos maliciosos podem usar isso para interferir na operação do GPS ou de outras fontes de localização."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localização precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Acessa fontes de localização precisa como o GPS (Global Positioning System) no telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar onde você está e podem consumir energia adicional da bateria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"local aproximado (com base na rede)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Acessa fontes de localização aproximada como o banco de dados de rede celular para determinar a localização aproximada de um telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar aproximadamente onde você está."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acessar SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite que o aplicativo use recursos de nível inferior do SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler o buffer do frame"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite que o aplicativo a ser usado leia o conteúdo do buffer de frame."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas configurações de áudio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite que o aplicativo modifique as configurações globais de áudio como volume e roteamento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite que um aplicativo acesse o caminho de gravação do áudio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tirar fotos"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite que o aplicativo tire fotos com a câmera. Isso permite que o aplicativo colete imagens vistas pela câmera a qualquer momento."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desativar permanentemente o telefone"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite que o aplicativo desative o telefone inteiro permanentemente. Isso é muito perigoso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forçar reinicialização do telefone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite que o aplicativo force a reinicialização do telefone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e desmontar sistemas de arquivos"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite que o aplicativo monte e desmonte arquivos de sistema para armazenamento removível."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatar armazenamento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite que o aplicativo formate o armazenamento removível."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar o vibrador"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que o aplicativo controle o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que o aplicativo controle a lanterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que o aplicativo controle diversos periféricos para teste do hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"chamar diretamente os números de telefone"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite que o aplicativo ligue para números de telefones sem a sua intervenção. Aplicativos maliciosos podem causar chamadas inesperadas na conta do seu telefone. Observe que isso não permite que o aplicativo ligue para números de emergência."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"chamar diretamente quaisquer números de telefone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite que o aplicativo ligue para qualquer número de telefone, incluindo números de emergência, sem a sua intervenção. Aplicativos maliciosos podem fazer chamadas desnecessárias e ilegais para serviços de emergência."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar as notificações de atualização do local"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a ativação/desativação de notificações de atualização do local a partir do rádio. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acessar propriedades de verificação"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite o acesso de leitura/gravação às propriedades enviadas pelo serviço de verificação. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"escolher widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite que o aplicativo informe ao sistema quais widgets podem ser usados por quais aplicativos. Com essa permissão, os aplicativos podem conceder acesso aos dados pessoais a outros aplicativos. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado do telefone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar redes, ligar e desligar o rádio do telefone e outras ações parecidas sem notificá-lo."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite que um aplicativo impeça o telefone de entrar no modo de inatividade."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite que o aplicativo ative ou desative o telefone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"executar no modo de teste de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Executa como um teste do fabricante de nível inferior, permitindo o acesso completo ao hardware do telefone. Disponível apenas quando um telefone está em execução no modo de teste do fabricante."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"definir papel de parede"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite que o aplicativo defina o papel de parede do sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir dicas de tamanho do papel de parede"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permite que o aplicativo defina as dicas de tamanho do papel de parede do sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"redefinir o sistema para os padrões de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite que um aplicativo redefina completamente o sistema para as configurações de fábrica, apagando todos os dados, configuração e aplicativos instalados."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"definir fuso horário"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite que um aplicativo altere o fuso horário do telefone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descobrir contas conhecidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite que um aplicativo obtenha a lista de contas conhecidas pelo telefone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado da rede"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite que um aplicativo veja o estado de todas as redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acesso total da internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite que um aplicativo crie soquetes de rede."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"gravar as configurações do Nome do ponto de acesso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite que um aplicativo modifique as configurações de APN, como Proxy e Porta de qualquer APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"alterar conectividade da rede"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite que um aplicativo altere o estado da conectividade de rede."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"alterar configuração de uso dos dados de segundo plano"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite que um aplicativo altere a configuração de uso dos dados de segundo plano."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visualizar estado da rede Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite que um aplicativo veja as informações sobre o estado de Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar o estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que um aplicativo se conecte e desconecte dos pontos de acesso Wi-Fi e faça alterações nas redes Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"Localização precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Acessa fontes de localização precisa como o GPS (Global Positioning System) no telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar onde você está e podem consumir energia adicional da bateria."</string>
+ <string name="permlab_accessCoarseLocation">"local aproximado (com base na rede)"</string>
+ <string name="permdesc_accessCoarseLocation">"Acessa fontes de localização aproximada como o banco de dados de rede celular para determinar a localização aproximada de um telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar aproximadamente onde você está."</string>
+ <string name="permlab_accessSurfaceFlinger">"acessar SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite que o aplicativo use recursos de nível inferior do SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"ler o buffer do frame"</string>
+ <string name="permdesc_readFrameBuffer">"Permite que o aplicativo a ser usado leia o conteúdo do buffer de frame."</string>
+ <string name="permlab_modifyAudioSettings">"alterar as suas configurações de áudio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite que o aplicativo modifique as configurações globais de áudio como volume e roteamento."</string>
+ <string name="permlab_recordAudio">"gravar áudio"</string>
+ <string name="permdesc_recordAudio">"Permite que um aplicativo acesse o caminho de gravação do áudio."</string>
+ <string name="permlab_camera">"tirar fotos"</string>
+ <string name="permdesc_camera">"Permite que o aplicativo tire fotos com a câmera. Isso permite que o aplicativo colete imagens vistas pela câmera a qualquer momento."</string>
+ <string name="permlab_brick">"desativar permanentemente o telefone"</string>
+ <string name="permdesc_brick">"Permite que o aplicativo desative o telefone inteiro permanentemente. Isso é muito perigoso."</string>
+ <string name="permlab_reboot">"forçar reinicialização do telefone"</string>
+ <string name="permdesc_reboot">"Permite que o aplicativo force a reinicialização do telefone."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar e desmontar sistemas de arquivos"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite que o aplicativo monte e desmonte arquivos de sistema para armazenamento removível."</string>
+ <string name="permlab_mount_format_filesystems">"formatar armazenamento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite que o aplicativo formate o armazenamento removível."</string>
+ <string name="permlab_vibrate">"controlar o vibrador"</string>
+ <string name="permdesc_vibrate">"Permite que o aplicativo controle o vibrador."</string>
+ <string name="permlab_flashlight">"controlar lanterna"</string>
+ <string name="permdesc_flashlight">"Permite que o aplicativo controle a lanterna."</string>
+ <string name="permlab_hardware_test">"testar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite que o aplicativo controle diversos periféricos para teste do hardware."</string>
+ <string name="permlab_callPhone">"chamar diretamente os números de telefone"</string>
+ <string name="permdesc_callPhone">"Permite que o aplicativo ligue para números de telefones sem a sua intervenção. Aplicativos maliciosos podem causar chamadas inesperadas na conta do seu telefone. Observe que isso não permite que o aplicativo ligue para números de emergência."</string>
+ <string name="permlab_callPrivileged">"chamar diretamente quaisquer números de telefone"</string>
+ <string name="permdesc_callPrivileged">"Permite que o aplicativo ligue para qualquer número de telefone, incluindo números de emergência, sem a sua intervenção. Aplicativos maliciosos podem fazer chamadas desnecessárias e ilegais para serviços de emergência."</string>
+ <string name="permlab_locationUpdates">"controlar as notificações de atualização do local"</string>
+ <string name="permdesc_locationUpdates">"Permite a ativação/desativação de notificações de atualização do local a partir do rádio. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_checkinProperties">"acessar propriedades de verificação"</string>
+ <string name="permdesc_checkinProperties">"Permite o acesso de leitura/gravação às propriedades enviadas pelo serviço de verificação. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_bindGadget">"escolher widgets"</string>
+ <string name="permdesc_bindGadget">"Permite que o aplicativo informe ao sistema quais widgets podem ser usados por quais aplicativos. Com essa permissão, os aplicativos podem conceder acesso aos dados pessoais a outros aplicativos. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado do telefone"</string>
+ <string name="permdesc_modifyPhoneState">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar redes, ligar e desligar o rádio do telefone e outras ações parecidas sem notificá-lo."</string>
+ <string name="permlab_readPhoneState">"ler estado do telefone"</string>
+ <string name="permdesc_readPhoneState">"Permite que o aplicativo acesse os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode determinar o número desse telefone, se uma chamada está ativa, o número ao qual a chamada está conectada e outras informações parecidas."</string>
+ <string name="permlab_wakeLock">"impedir modo de inatividade do telefone"</string>
+ <string name="permdesc_wakeLock">"Permite que um aplicativo impeça o telefone de entrar no modo de inatividade."</string>
+ <string name="permlab_devicePower">"ligar ou desligar o telefone"</string>
+ <string name="permdesc_devicePower">"Permite que o aplicativo ative ou desative o telefone."</string>
+ <string name="permlab_factoryTest">"executar no modo de teste de fábrica"</string>
+ <string name="permdesc_factoryTest">"Executa como um teste do fabricante de nível inferior, permitindo o acesso completo ao hardware do telefone. Disponível apenas quando um telefone está em execução no modo de teste do fabricante."</string>
+ <string name="permlab_setWallpaper">"definir papel de parede"</string>
+ <string name="permdesc_setWallpaper">"Permite que o aplicativo defina o papel de parede do sistema."</string>
+ <string name="permlab_setWallpaperHints">"definir dicas de tamanho do papel de parede"</string>
+ <string name="permdesc_setWallpaperHints">"Permite que o aplicativo defina as dicas de tamanho do papel de parede do sistema."</string>
+ <string name="permlab_masterClear">"redefinir o sistema para os padrões de fábrica"</string>
+ <string name="permdesc_masterClear">"Permite que um aplicativo redefina completamente o sistema para as configurações de fábrica, apagando todos os dados, configuração e aplicativos instalados."</string>
+ <string name="permlab_setTimeZone">"definir fuso horário"</string>
+ <string name="permdesc_setTimeZone">"Permite que um aplicativo altere o fuso horário do telefone."</string>
+ <string name="permlab_getAccounts">"descobrir contas conhecidas"</string>
+ <string name="permdesc_getAccounts">"Permite que um aplicativo obtenha a lista de contas conhecidas pelo telefone."</string>
+ <string name="permlab_accessNetworkState">"ver estado da rede"</string>
+ <string name="permdesc_accessNetworkState">"Permite que um aplicativo veja o estado de todas as redes."</string>
+ <string name="permlab_createNetworkSockets">"acesso total da internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite que um aplicativo crie soquetes de rede."</string>
+ <string name="permlab_writeApnSettings">"gravar as configurações do Nome do ponto de acesso"</string>
+ <string name="permdesc_writeApnSettings">"Permite que um aplicativo modifique as configurações de APN, como Proxy e Porta de qualquer APN."</string>
+ <string name="permlab_changeNetworkState">"alterar conectividade da rede"</string>
+ <string name="permdesc_changeNetworkState">"Permite que um aplicativo altere o estado da conectividade de rede."</string>
+ <string name="permlab_changeBackgroundDataSetting">"alterar configuração de uso dos dados de segundo plano"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite que um aplicativo altere a configuração de uso dos dados de segundo plano."</string>
+ <string name="permlab_accessWifiState">"visualizar estado da rede Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite que um aplicativo veja as informações sobre o estado de Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"alterar o estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite que um aplicativo se conecte e desconecte dos pontos de acesso Wi-Fi e faça alterações nas redes Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que um aplicativo configure o telefone Bluetooth local, descubra e pareie com dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"criar conexões Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite que um aplicativo veja a configuração do telefone Bluetooth local e que possa fazer e aceitar conexões com dispositivos pareados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desativar o bloqueio de teclas"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que um aplicativo desative o bloqueio de teclas e qualquer segurança por senha associada. Um exemplo legítimo disso é a desativação do bloqueio de teclas pelo telefone ao receber uma chamada e a reativação do bloqueio quando a chamada é finalizada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite que um aplicativo leia as configurações de sincronização, como se a sincronização está ativada para Contatos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"gravar configurações de sincronização"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite que um aplicativo modifique as configurações de sincronização, como a ativação da sincronização para Contatos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ler estatísticas de sincronização"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite que um aplicativo leia as estatísticas de sincronização; por exemplo, o histórico de sincronizações ocorridas."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite que um aplicativo obtenha detalhes sobre os feeds sincronizados no momento."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"gravar feeds inscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite que um aplicativo modifique os seus feeds atualmente sincronizados. Isso pode permitir que um aplicativo malicioso altere os seus feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ler dicionário definido pelo usuário"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite que um aplicativo leia quaisquer palavras, nomes e frases particulares armazenados pelo usuário no dicionário do usuário."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"gravar no dicionário definido pelo usuário"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite que um aplicativo grave novas palavras no dicionário do usuário."</string>
+ <string name="permlab_bluetoothAdmin">"administração de Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite que um aplicativo configure o telefone Bluetooth local, descubra e pareie com dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"criar conexões Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite que um aplicativo veja a configuração do telefone Bluetooth local e que possa fazer e aceitar conexões com dispositivos pareados."</string>
+ <string name="permlab_disableKeyguard">"desativar o bloqueio de teclas"</string>
+ <string name="permdesc_disableKeyguard">"Permite que um aplicativo desative o bloqueio de teclas e qualquer segurança por senha associada. Um exemplo legítimo disso é a desativação do bloqueio de teclas pelo telefone ao receber uma chamada e a reativação do bloqueio quando a chamada é finalizada."</string>
+ <string name="permlab_readSyncSettings">"ler as configurações de sincronização"</string>
+ <string name="permdesc_readSyncSettings">"Permite que um aplicativo leia as configurações de sincronização, como se a sincronização está ativada para Contatos."</string>
+ <string name="permlab_writeSyncSettings">"gravar configurações de sincronização"</string>
+ <string name="permdesc_writeSyncSettings">"Permite que um aplicativo modifique as configurações de sincronização, como a ativação da sincronização para Contatos."</string>
+ <string name="permlab_readSyncStats">"ler estatísticas de sincronização"</string>
+ <string name="permdesc_readSyncStats">"Permite que um aplicativo leia as estatísticas de sincronização; por exemplo, o histórico de sincronizações ocorridas."</string>
+ <string name="permlab_subscribedFeedsRead">"ler feeds inscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite que um aplicativo obtenha detalhes sobre os feeds sincronizados no momento."</string>
+ <string name="permlab_subscribedFeedsWrite">"gravar feeds inscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite que um aplicativo modifique os seus feeds atualmente sincronizados. Isso pode permitir que um aplicativo malicioso altere os seus feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"ler dicionário definido pelo usuário"</string>
+ <string name="permdesc_readDictionary">"Permite que um aplicativo leia quaisquer palavras, nomes e frases particulares armazenados pelo usuário no dicionário do usuário."</string>
+ <string name="permlab_writeDictionary">"gravar no dicionário definido pelo usuário"</string>
+ <string name="permdesc_writeDictionary">"Permite que um aplicativo grave novas palavras no dicionário do usuário."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Página inicial"</item>
- <item msgid="869923650527136615">"Celular"</item>
- <item msgid="7897544654242874543">"Trabalho"</item>
- <item msgid="1103601433382158155">"Fax do trabalho"</item>
- <item msgid="1735177144948329370">"Fax doméstico"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Outros"</item>
- <item msgid="9192514806975898961">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Celular"</item>
+ <item>"Trabalho"</item>
+ <item>"Fax do trabalho"</item>
+ <item>"Fax doméstico"</item>
+ <item>"Pager"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Página inicial"</item>
- <item msgid="7084237356602625604">"Trabalho"</item>
- <item msgid="1112044410659011023">"Outros"</item>
- <item msgid="2374913952870110618">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Celular"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Página inicial"</item>
- <item msgid="5629153956045109251">"Trabalho"</item>
- <item msgid="4966604264500343469">"Outros"</item>
- <item msgid="4932682847595299369">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Página inicial"</item>
- <item msgid="1359644565647383708">"Trabalho"</item>
- <item msgid="7868549401053615677">"Outros"</item>
- <item msgid="3145118944639869809">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabalho"</item>
- <item msgid="4378074129049520373">"Outros"</item>
- <item msgid="3455047468583965104">"Personalizado"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Digite o código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Código PIN incorreto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sem serviço)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Tela bloqueada."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pressione Menu para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenhe o padrão para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chamada de emergência"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correto!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Tente novamente"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Carregando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Digite o código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Código PIN incorreto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergência"</string>
+ <string name="lockscreen_carrier_default">"(Sem serviço)"</string>
+ <string name="lockscreen_screen_locked">"Tela bloqueada."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Pressione Menu para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Desenhe o padrão para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Chamada de emergência"</string>
+ <string name="lockscreen_pattern_correct">"Correto!"</string>
+ <string name="lockscreen_pattern_wrong">"Tente novamente"</string>
+ <string name="lockscreen_plugged_in">"Carregando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecte o seu carregador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Sem cartão SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Não há um cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Insira um cartão SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado pelo PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulte o Guia do Usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Você desenhou incorretamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu o padrão?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Muitas tentativas de padrão!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, faça login com a sua Conta do Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome de usuário (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Senha"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Fazer login"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de usuário ou senha inválida."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Conecte o seu carregador."</string>
+ <string name="lockscreen_missing_sim_message_short">"Sem cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Não há um cartão SIM no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Insira um cartão SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rede bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"O cartão SIM está bloqueado pelo PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulte o Guia do Usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
+ <string name="lockscreen_sim_locked_message">"O cartão SIM está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando o cartão SIM…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Você desenhou incorretamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Esqueceu o padrão?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Muitas tentativas de padrão!"</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, faça login com a sua Conta do Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nome de usuário (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Senha"</string>
+ <string name="lockscreen_glogin_submit_button">"Fazer login"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nome de usuário ou senha inválida."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Carregando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecte o carregador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está ficando baixa:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes."</string>
+ <string name="status_bar_no_notifications_title">"Sem notificações"</string>
+ <string name="status_bar_ongoing_events_title">"Em andamento"</string>
+ <string name="status_bar_latest_events_title">"Notificações"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Carregando..."</string>
+ <string name="battery_low_title">"Conecte o carregador"</string>
+ <string name="battery_low_subtitle">"A bateria está ficando baixa:"</string>
+ <string name="battery_low_percent_format">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Falha no teste de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"A ação FACTORY_TEST é suportada apenas para pacotes instalados em /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nenhum pacote que forneça a ação FACTORY_TEST foi encontrado."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" mostra:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"Falha no teste de fábrica"</string>
+ <string name="factorytest_not_system">"A ação FACTORY_TEST é suportada apenas para pacotes instalados em /system/app."</string>
+ <string name="factorytest_no_action">"Nenhum pacote que forneça a ação FACTORY_TEST foi encontrado."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" mostra:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Você não tem permissão para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado para a área de transferência."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mais"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espaço"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"excluir"</string>
- <string name="search_go" msgid="8298016669822141719">"Pesquisar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
+ <string name="save_password_message">"Deseja que o navegador lembre desta senha?"</string>
+ <string name="save_password_notnow">"Agora não"</string>
+ <string name="save_password_remember">"Lembrar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"Você não tem permissão para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado para a área de transferência."</string>
+ <string name="more_item_label">"Mais"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espaço"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"excluir"</string>
+ <string name="search_go">"Pesquisar"</string>
+ <string name="oneMonthDurationPast">"1 mês atrás"</string>
+ <string name="beforeOneMonthDurationPast">"Antes de 1 mês atrás"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 segundo atrás"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
+ <item quantity="one">"1 segundo atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto atrás"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
+ <item quantity="one">"1 minuto atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 hora atrás"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
+ <item quantity="one">"1 hora atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"em 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"em 1 segundo"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"em 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"em 1 minuto"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"em 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"em 1 hora"</item>
+ <item quantity="other">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seg. atrás"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> segundos\n atrás"</item>
+ <item quantity="one">"1 seg. atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> segundos\n atrás"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuto atrás"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
+ <item quantity="one">"1 minuto atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 hora atrás"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
+ <item quantity="one">"1 hora atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"em 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"em 1 segundo"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"em 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"em 1 minuto"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"em 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"em 1 hora"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"em %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"às %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"em %s"</string>
- <string name="day" msgid="8144195776058119424">"dia"</string>
- <string name="days" msgid="4774547661021344602">"dias"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"seg."</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"ano"</string>
- <string name="years" msgid="6881577717993213522">"anos"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos os dias da semana (de segunda a sexta)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente na <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensalmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Não é possível reproduzir o vídeo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Este vídeo não é válido para transmissão com este dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Este vídeo não pode ser reproduzido."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"meio-dia"</string>
- <string name="Noon" msgid="3342127745230013127">"Meio-dia"</string>
- <string name="midnight" msgid="7166259508850457595">"meia-noite"</string>
- <string name="Midnight" msgid="5630806906897892201">"Meia-noite"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Selecionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar seleção de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Recortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Recortar tudo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar tudo"</string>
- <string name="paste" msgid="5629880836805036433">"Colar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Adicionar \"%s\" ao dicionário"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pouco espaço"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"O espaço de armazenamento do telefone está ficando baixo."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
- <string name="capital_on" msgid="1544682755514494298">"ATIVADO"</string>
- <string name="capital_off" msgid="6815870386972805832">"DESATIVADO"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Complete a ação usando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Use o como padrão para esta ação."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar o padrão em Configurações da página inicial > Aplicativos > Gerenciar aplicativos."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Selecionar uma ação"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nenhum aplicativo pode realizar esta ação."</string>
- <string name="aerr_title" msgid="653922989522758100">"Desculpe!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
- <string name="aerr_process" msgid="1551785535966089511">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou inesperadamente. Tente novamente."</string>
- <string name="anr_title" msgid="3100070910664756057">"Desculpe!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no aplicativo <xliff:g id="APPLICATION">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_process" msgid="1246866008169975783">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo."</string>
- <string name="force_close" msgid="3653416315450806396">"Forçar fechamento"</string>
+ <string name="preposition_for_date">"em %s"</string>
+ <string name="preposition_for_time">"às %s"</string>
+ <string name="preposition_for_year">"em %s"</string>
+ <string name="day">"dia"</string>
+ <string name="days">"dias"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"seg."</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"ano"</string>
+ <string name="years">"anos"</string>
+ <string name="every_weekday">"Todos os dias da semana (de segunda a sexta)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente na <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensalmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"Não é possível reproduzir o vídeo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Este vídeo não é válido para transmissão com este dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Este vídeo não pode ser reproduzido."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"meio-dia"</string>
+ <string name="Noon">"Meio-dia"</string>
+ <string name="midnight">"meia-noite"</string>
+ <string name="Midnight">"Meia-noite"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Selecionar tudo"</string>
+ <string name="selectText">"Selecionar texto"</string>
+ <string name="stopSelectingText">"Parar seleção de texto"</string>
+ <string name="cut">"Recortar"</string>
+ <string name="cutAll">"Recortar tudo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar tudo"</string>
+ <string name="paste">"Colar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Adicionar \"%s\" ao dicionário"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Pouco espaço"</string>
+ <string name="low_internal_storage_view_text">"O espaço de armazenamento do telefone está ficando baixo."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atenção"</string>
+ <string name="capital_on">"ATIVADO"</string>
+ <string name="capital_off">"DESATIVADO"</string>
+ <string name="whichApplication">"Complete a ação usando"</string>
+ <string name="alwaysUse">"Use o como padrão para esta ação."</string>
+ <string name="clearDefaultHintMsg">"Limpar o padrão em Configurações da página inicial > Aplicativos > Gerenciar aplicativos."</string>
+ <string name="chooseActivity">"Selecionar uma ação"</string>
+ <string name="noApplications">"Nenhum aplicativo pode realizar esta ação."</string>
+ <string name="aerr_title">"Desculpe!"</string>
+ <string name="aerr_application">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
+ <string name="aerr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou inesperadamente. Tente novamente."</string>
+ <string name="anr_title">"Desculpe!"</string>
+ <string name="anr_activity_application">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no aplicativo <xliff:g id="APPLICATION">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_activity_process">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_application_process">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo."</string>
+ <string name="force_close">"Forçar fechamento"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Aguardar"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecione uma ação para o texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduzindo por meio de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume na chamada"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume da notificação"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
+ <string name="wait">"Aguardar"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Selecione uma ação para o texto"</string>
+ <string name="volume_ringtone">"Volume da campainha"</string>
+ <string name="volume_music">"Volume da mídia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduzindo por meio de Bluetooth"</string>
+ <string name="volume_call">"Volume na chamada"</string>
+ <string name="volume_bluetooth_call">"Volume de chamada Bluetooth"</string>
+ <string name="volume_alarm">"Volume do alarme"</string>
+ <string name="volume_notification">"Volume da notificação"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Toque padrão"</string>
+ <string name="ringtone_default_with_actual">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Toques"</string>
+ <string name="ringtone_unknown">"Toque desconhecido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi disponível"</item>
+ <item quantity="other">"Redes Wi-Fi disponíveis"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
- <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abertas disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi aberta disponível"</item>
+ <item quantity="other">"Redes Wi-Fi abertas disponíveis"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicativo desconhecido"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Padrão"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todas"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Carregando..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Você conectou o telefone ao computador via USB. Selecione \"Montar\" se quiser copiar arquivos entre o computador e o cartão SD do seu telefone."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Não montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Há um problema com o uso do seu cartão SD para armazenamento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Conectado por USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Selecione para copiar arquivos para/do seu computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desativar o armazenamento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Selecione para desativar o armazenamento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desativar o armazenamento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desativar o armazenamento USB, desmonte o host USB. Selecione \"Desativar\" para desativar o armazenamento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desativar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Encontramos um problema ao desativar o armazenamento USB. Verifique se desmontou o host USB e tente novamente."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatar cartão SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Tem certeza de que deseja formatar o cartão SD? Todos os dados no seu cartão serão perdidos."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatar"</string>
+ <string name="select_character">"Inserir caractere"</string>
+ <string name="sms_control_default_app_name">"Aplicativo desconhecido"</string>
+ <string name="sms_control_title">"Enviando mensagens SMS"</string>
+ <string name="sms_control_message">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Definir"</string>
+ <string name="default_permission_group">"Padrão"</string>
+ <string name="no_permissions">"Nenhuma permissão necessária"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todas"</b></string>
+ <string name="googlewebcontenthelper_loading">"Carregando..."</string>
+ <string name="usb_storage_title">"Conectado por USB"</string>
+ <string name="usb_storage_message">"Você conectou o telefone ao computador via USB. Selecione \"Montar\" se quiser copiar arquivos entre o computador e o cartão SD do seu telefone."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"Não montar"</string>
+ <string name="usb_storage_error_message">"Há um problema com o uso do seu cartão SD para armazenamento USB."</string>
+ <string name="usb_storage_notification_title">"Conectado por USB"</string>
+ <string name="usb_storage_notification_message">"Selecione para copiar arquivos para/do seu computador."</string>
+ <string name="usb_storage_stop_notification_title">"Desativar o armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Selecione para desativar o armazenamento USB."</string>
+ <string name="usb_storage_stop_title">"Desativar o armazenamento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desativar o armazenamento USB, desmonte o host USB. Selecione \"Desativar\" para desativar o armazenamento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desativar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Encontramos um problema ao desativar o armazenamento USB. Verifique se desmontou o host USB e tente novamente."</string>
+ <string name="extmedia_format_title">"Formatar cartão SD"</string>
+ <string name="extmedia_format_message">"Tem certeza de que deseja formatar o cartão SD? Todos os dados no seu cartão serão perdidos."</string>
+ <string name="extmedia_format_button_format">"Formatar"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Selecionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparando o cartão SD"</string>
+ <string name="select_input_method">"Selecionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparando o cartão SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Cartão SD em branco"</string>
+ <string name="ext_media_nofs_notification_title">"Cartão SD em branco"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Cartão SD danificado"</string>
+ <string name="ext_media_unmountable_notification_title">"Cartão SD danificado"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Cartão SD removido inesperadamente."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmonte o cartão SD antes da remoção para evitar a perda de dados."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"O cartão SD já pode ser removido com segurança."</string>
+ <string name="ext_media_badremoval_notification_title">"Cartão SD removido inesperadamente."</string>
+ <string name="ext_media_badremoval_notification_message">"Desmonte o cartão SD antes da remoção para evitar a perda de dados."</string>
+ <string name="ext_media_safe_unmount_notification_title">"O cartão SD já pode ser removido com segurança."</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Cartão SD removido"</string>
+ <string name="ext_media_nomedia_notification_title">"Cartão SD removido"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Nenhum atividade correspondente foi encontrada"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"atualizar estatísticas de uso do componente"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite a modificação das estatísticas de uso do componente coletadas. Não deve ser usado por aplicativos normais."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erro ao aumentar o widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Pesquisar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Próximo"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Discar número"\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Criar contato "\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Nenhum atividade correspondente foi encontrada"</string>
+ <string name="permlab_pkgUsageStats">"atualizar estatísticas de uso do componente"</string>
+ <string name="permdesc_pkgUsageStats">"Permite a modificação das estatísticas de uso do componente coletadas. Não deve ser usado por aplicativos normais."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Toque duas vezes para ter controle do zoom"</string>
+ <string name="gadget_host_error_inflating">"Erro ao aumentar o widget"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Pesquisar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Próximo"</string>
+ <string name="ime_action_done">"Concluído"</string>
+ <string name="ime_action_default">"Executar"</string>
+ <string name="dial_number_using">"Discar número"\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Criar contato "\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8613540..22120f6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"Б"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"КБ"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"МБ"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"ГБ"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TБ"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"ПБ"</string>
+ <string name="byteShort">"Б"</string>
+ <string name="kilobyteShort">"КБ"</string>
+ <string name="megabyteShort">"МБ"</string>
+ <string name="gigabyteShort">"ГБ"</string>
+ <string name="terabyteShort">"TБ"</string>
+ <string name="petabyteShort">"ПБ"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<без названия>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Нет номера телефона)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Неизвестно)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Голосовая почта"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Неполадки подключения или неверный код MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Служба включена."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Служба подключена для:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Служба отключена."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Регистрация пройдена успешно."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Удаление выполнено успешно."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Неверный пароль."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Запрос MMI завершен."</string>
- <string name="badPin" msgid="5085454289896032547">"Введен неверный старый PUK."</string>
- <string name="badPuk" msgid="5702522162746042460">"Введен неверный PUK."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Введенные PIN-коды не совпадают."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Введите PIN-код (от 4 до 8 цифр)."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM-карта заблокирована с помощью кода PUK. Для разблокировки введите код PUK."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Для разблокировки SIM-карты введите PUK2."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Идентификация вызывающего абонента"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Идентификация звонящего абонента"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Переадресация вызова"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Параллельный вызов"</string>
- <string name="BaMmi" msgid="455193067926770581">"Запрет вызовов"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Смена пароля"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Смена PIN"</string>
+ <string name="untitled">"<без названия>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Нет номера телефона)"</string>
+ <string name="unknownName">"(Неизвестно)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Голосовая почта"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Неполадки подключения или неверный код MMI."</string>
+ <string name="serviceEnabled">"Служба включена."</string>
+ <string name="serviceEnabledFor">"Служба подключена для:"</string>
+ <string name="serviceDisabled">"Служба отключена."</string>
+ <string name="serviceRegistered">"Регистрация пройдена успешно."</string>
+ <string name="serviceErased">"Удаление выполнено успешно."</string>
+ <string name="passwordIncorrect">"Неверный пароль."</string>
+ <string name="mmiComplete">"Запрос MMI завершен."</string>
+ <string name="badPin">"Введен неверный старый PUK."</string>
+ <string name="badPuk">"Введен неверный PUK."</string>
+ <string name="mismatchPin">"Введенные PIN-коды не совпадают."</string>
+ <string name="invalidPin">"Введите PIN-код (от 4 до 8 цифр)."</string>
+ <string name="needPuk">"SIM-карта заблокирована с помощью кода PUK. Для разблокировки введите код PUK."</string>
+ <string name="needPuk2">"Для разблокировки SIM-карты введите PUK2."</string>
+ <string name="ClipMmi">"Идентификация вызывающего абонента"</string>
+ <string name="ClirMmi">"Идентификация звонящего абонента"</string>
+ <string name="CfMmi">"Переадресация вызова"</string>
+ <string name="CwMmi">"Параллельный вызов"</string>
+ <string name="BaMmi">"Запрет вызовов"</string>
+ <string name="PwdMmi">"Смена пароля"</string>
+ <string name="PinMmi">"Смена PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Идентификация абонента по умолчанию запрещена. След. вызов: запрещена"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Идентификация абонента по умолчанию запрещена. След. вызов: разрешена"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Идентификация абонента по умолчанию не запрещена. След. вызов: запрещена"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Идентификация абонента по умолчанию не запрещена. След. вызов: разрешена"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Услуга не предоставляется."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Невозможно изменить настройку идентификации абонента."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ограничения доступа изменены"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Служба данных заблокирована."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Служба экстренной помощи заблокирована."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Служба передачи SMS/голосовых сообщений заблокирована."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Все службы передачи SMS/голосовых сообщений заблокированы."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Голосовая связь"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Данные"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"ФАКС"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Асинхр."</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Синхр."</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Пакет"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Идентификация абонента по умолчанию запрещена. След. вызов: запрещена"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Идентификация абонента по умолчанию запрещена. След. вызов: разрешена"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Идентификация абонента по умолчанию не запрещена. След. вызов: запрещена"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Идентификация абонента по умолчанию не запрещена. След. вызов: разрешена"</string>
+ <string name="serviceNotProvisioned">"Услуга не предоставляется."</string>
+ <string name="CLIRPermanent">"Невозможно изменить настройку идентификации абонента."</string>
+ <string name="RestrictedChangedTitle">"Ограничения доступа изменены"</string>
+ <string name="RestrictedOnData">"Служба данных заблокирована."</string>
+ <string name="RestrictedOnEmergency">"Служба экстренной помощи заблокирована."</string>
+ <string name="RestrictedOnNormal">"Служба передачи SMS/голосовых сообщений заблокирована."</string>
+ <string name="RestrictedOnAll">"Все службы передачи SMS/голосовых сообщений заблокированы."</string>
+ <string name="serviceClassVoice">"Голосовая связь"</string>
+ <string name="serviceClassData">"Данные"</string>
+ <string name="serviceClassFAX">"ФАКС"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Асинхр."</string>
+ <string name="serviceClassDataSync">"Синхр."</string>
+ <string name="serviceClassPacket">"Пакет"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадресовано"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не переадресовано"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не переадресовано"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадресовано"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не переадресовано"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не переадресовано"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"ОК"</string>
- <string name="httpError" msgid="2567300624552921790">"Ошибка на веб-странице."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Не удалось найти URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Схема аутентификации сайта не поддерживается."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Не удалось провести аутентификацию."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Не удалось выполнить аутентификацию через прокси-сервер."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Не удалось подключиться к серверу."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Сервер не отвечает. Повторите попытку позднее."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Время ожидания соединения с сервером истекло."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Страница содержит слишком много перенаправлений сервера."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Этот протокол не поддерживается."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Не удалось установить безопасное соединение."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Не удалось открыть страницу. Указан недопустимый URL."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Не удается получить доступ к файлу."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Не удалось найти указанные файлы."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Обрабатывается слишком много запросов. Повторите попытку позднее."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Синхр."</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Память телефона заполнена! Удалите файлы, чтобы освободить место."</string>
- <string name="me" msgid="6545696007631404292">"Я"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Параметры телефона"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Тихий режим"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Включить беспроводную связь"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Отключить беспроводное соединение"</string>
- <string name="screen_lock" msgid="799094655496098153">"Блокировка экрана"</string>
- <string name="power_off" msgid="4266614107412865048">"Выключить связь"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Телефон будет отключен."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Нет последних приложений."</string>
- <string name="global_actions" msgid="2406416831541615258">"Параметры телефона"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Тихий режим"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Звук ВЫКЛ"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Звук ВКЛЮЧЕН"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим полета ВКЛЮЧЕН"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим полета ВЫКЛЮЧЕН"</string>
- <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платные услуги"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Разрешать приложениям использовать платные услуги."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Сообщения"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Считывать и записывать SMS, электронные письма и другие сообщения."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Личная информация"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Прямой доступ к контактам и событиям календаря, сохраненным в памяти телефона."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Ваше местоположение"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Отслеживание физического местоположения"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Сетевой обмен данными"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Позволяет приложениям получать доступ к различным сетевым функциям."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Ваши аккаунты Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Входить в доступные аккаунты Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Элементы управления аппаратным обеспечением"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Прямой доступ к аппаратному обеспечению телефона."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Телефонные вызовы"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Отслеживать, записывать и обрабатывать телефонные звонки."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Системные инструменты"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Доступ нижнего уровня и управление системой."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Инструменты разработки"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Функции, необходимые только разработчикам приложений."</string>
+ <string name="httpErrorOk">"ОК"</string>
+ <string name="httpError">"Ошибка на веб-странице."</string>
+ <string name="httpErrorLookup">"Не удалось найти URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Схема аутентификации сайта не поддерживается."</string>
+ <string name="httpErrorAuth">"Не удалось провести аутентификацию."</string>
+ <string name="httpErrorProxyAuth">"Не удалось выполнить аутентификацию через прокси-сервер."</string>
+ <string name="httpErrorConnect">"Не удалось подключиться к серверу."</string>
+ <string name="httpErrorIO">"Сервер не отвечает. Повторите попытку позднее."</string>
+ <string name="httpErrorTimeout">"Время ожидания соединения с сервером истекло."</string>
+ <string name="httpErrorRedirectLoop">"Страница содержит слишком много перенаправлений сервера."</string>
+ <string name="httpErrorUnsupportedScheme">"Этот протокол не поддерживается."</string>
+ <string name="httpErrorFailedSslHandshake">"Не удалось установить безопасное соединение."</string>
+ <string name="httpErrorBadUrl">"Не удалось открыть страницу. Указан недопустимый URL."</string>
+ <string name="httpErrorFile">"Не удается получить доступ к файлу."</string>
+ <string name="httpErrorFileNotFound">"Не удалось найти указанные файлы."</string>
+ <string name="httpErrorTooManyRequests">"Обрабатывается слишком много запросов. Повторите попытку позднее."</string>
+ <string name="contentServiceSync">"Синхр."</string>
+ <string name="contentServiceSyncNotificationTitle">"Синхр."</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Память телефона заполнена! Удалите файлы, чтобы освободить место."</string>
+ <string name="me">"Я"</string>
+ <string name="power_dialog">"Параметры телефона"</string>
+ <string name="silent_mode">"Беззвучный режим"</string>
+ <string name="turn_on_radio">"Включить беспроводную связь"</string>
+ <string name="turn_off_radio">"Отключить беспроводное соединение"</string>
+ <string name="screen_lock">"Блокировка экрана"</string>
+ <string name="power_off">"Выключить связь"</string>
+ <string name="shutdown_progress">"Выключение..."</string>
+ <string name="shutdown_confirm">"Телефон будет отключен."</string>
+ <string name="no_recent_tasks">"Нет последних приложений."</string>
+ <string name="global_actions">"Параметры телефона"</string>
+ <string name="global_action_lock">"Блокировка экрана"</string>
+ <string name="global_action_power_off">"Отключить питание"</string>
+ <string name="global_action_toggle_silent_mode">"Беззвучный режим"</string>
+ <string name="global_action_silent_mode_on_status">"Звук ВЫКЛ"</string>
+ <string name="global_action_silent_mode_off_status">"Звук ВКЛЮЧЕН"</string>
+ <string name="global_actions_toggle_airplane_mode">"Режим полета"</string>
+ <string name="global_actions_airplane_mode_on_status">"Режим полета ВКЛЮЧЕН"</string>
+ <string name="global_actions_airplane_mode_off_status">"Режим полета ВЫКЛЮЧЕН"</string>
+ <string name="safeMode">"Безопасный режим"</string>
+ <string name="android_system_label">"Система Android"</string>
+ <string name="permgrouplab_costMoney">"Платные услуги"</string>
+ <string name="permgroupdesc_costMoney">"Разрешать приложениям использовать платные услуги."</string>
+ <string name="permgrouplab_messages">"Сообщения"</string>
+ <string name="permgroupdesc_messages">"Считывать и записывать SMS, электронные письма и другие сообщения."</string>
+ <string name="permgrouplab_personalInfo">"Личная информация"</string>
+ <string name="permgroupdesc_personalInfo">"Прямой доступ к контактам и событиям календаря, сохраненным в памяти телефона."</string>
+ <string name="permgrouplab_location">"Ваше местоположение"</string>
+ <string name="permgroupdesc_location">"Отслеживание физического местоположения"</string>
+ <string name="permgrouplab_network">"Сетевой обмен данными"</string>
+ <string name="permgroupdesc_network">"Позволяет приложениям получать доступ к различным сетевым функциям."</string>
+ <string name="permgrouplab_accounts">"Ваши аккаунты Google"</string>
+ <string name="permgroupdesc_accounts">"Входить в доступные аккаунты Google."</string>
+ <string name="permgrouplab_hardwareControls">"Элементы управления аппаратным обеспечением"</string>
+ <string name="permgroupdesc_hardwareControls">"Прямой доступ к аппаратному обеспечению телефона."</string>
+ <string name="permgrouplab_phoneCalls">"Телефонные вызовы"</string>
+ <string name="permgroupdesc_phoneCalls">"Отслеживать, записывать и обрабатывать телефонные звонки."</string>
+ <string name="permgrouplab_systemTools">"Системные инструменты"</string>
+ <string name="permgroupdesc_systemTools">"Доступ нижнего уровня и управление системой."</string>
+ <string name="permgrouplab_developmentTools">"Инструменты разработки"</string>
+ <string name="permgroupdesc_developmentTools">"Функции, необходимые только разработчикам приложений."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"отключать или изменять строку состояния"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Позволяет приложению отключать строку состояния или добавлять/удалять системные значки."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"разворачивать/сворачивать строку состояния"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Позволяет приложению разворачивать или сворачивать строку состояния."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"перехватывать исходящие вызовы"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Позволяет приложению обрабатывать исходящие вызовы и изменять набираемый номер. Вредоносные приложения могут отслеживать, перенаправлять или запрещать исходящие вызовы."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"получать SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Позволяет приложению получать и обрабатывать SMS-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"получать MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Позволяет приложению получать и обрабатывать MMS-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"отправлять SMS-сообщения"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Позволяет приложению отправлять SMS-сообщения. Вредоносные приложения могут отправлять сообщения без уведомления, что приведет к непредвиденным расходам."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"считывать SMS или MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Позволяет приложению считывать SMS-сообщения, сохраненные на телефоне или SIM-карте. Вредоносные приложения могут считывать конфиденциальные сообщения."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"изменять SMS или MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Позволяет приложению перезаписывать SMS-сообщения, сохраненные на телефоне или SIM-карте. Вредоносные приложения могут удалить сообщения."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"получать WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Позволяет приложению получать и обрабатывать WAP-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"извлечь запущенные приложения"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Позволяет приложению получать сведения о последних и текущих задачах. Вредоносные приложения могут получить доступ к конфиденциальной информации о других приложениях."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"изменять порядок запущенных приложений"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Позволяет приложению переключать режим выполнения задачи с активного на фоновый. Вредоносные приложения могут установить для себя активный режим без уведомления."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"запускать отладку приложения"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Позволяет приложению запускать процесс отладки другого приложения. Вредоносные приложения могут использовать эту возможность для остановки других приложений."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Позволяет приложению изменять текущую конфигурацию, например региональные настройки или размер шрифта."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"перезапускать другие приложения"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Позволяет приложению принудительно перезапускать другие приложения."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"принудительно закрывать приложения"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Позволяет приложению принудительно закрыть или вернуть в исходное состояние процессы, выполняемые в активном режиме. Не требуется для обычных приложений."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"извлекать данные о внутреннем состоянии системы"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Позволяет приложению извлекать внутренние сведения о состоянии системы. Вредоносные приложения смогут извлечь разнообразные личные и защищенные сведения, в которых обычно нет необходимости."</string>
+ <string name="permlab_statusBar">"отключить или изменить строку состояния"</string>
+ <string name="permdesc_statusBar">"Позволяет приложению отключать строку состояния или добавлять/удалять системные значки."</string>
+ <string name="permlab_expandStatusBar">"разворачивать/сворачивать строку состояния"</string>
+ <string name="permdesc_expandStatusBar">"Позволяет приложению разворачивать или сворачивать строку состояния."</string>
+ <string name="permlab_processOutgoingCalls">"перехватывать исходящие вызовы"</string>
+ <string name="permdesc_processOutgoingCalls">"Позволяет приложению обрабатывать исходящие вызовы и изменять набираемый номер. Вредоносные приложения могут отслеживать, перенаправлять или запрещать исходящие вызовы."</string>
+ <string name="permlab_receiveSms">"получать SMS"</string>
+ <string name="permdesc_receiveSms">"Позволяет приложению получать и обрабатывать SMS-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
+ <string name="permlab_receiveMms">"получать MMS"</string>
+ <string name="permdesc_receiveMms">"Позволяет приложению получать и обрабатывать MMS-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
+ <string name="permlab_sendSms">"отправлять SMS-сообщения"</string>
+ <string name="permdesc_sendSms">"Позволяет приложению отправлять SMS-сообщения. Вредоносные приложения могут отправлять сообщения без уведомления, что приведет к непредвиденным расходам."</string>
+ <string name="permlab_readSms">"считывать SMS или MMS"</string>
+ <string name="permdesc_readSms">"Позволяет приложению считывать SMS-сообщения, сохраненные на телефоне или SIM-карте. Вредоносные приложения могут считывать конфиденциальные сообщения."</string>
+ <string name="permlab_writeSms">"изменить SMS или MMS"</string>
+ <string name="permdesc_writeSms">"Позволяет приложению перезаписывать SMS-сообщения, сохраненные на телефоне или SIM-карте. Вредоносные приложения могут удалить сообщения."</string>
+ <string name="permlab_receiveWapPush">"получать WAP"</string>
+ <string name="permdesc_receiveWapPush">"Позволяет приложению получать и обрабатывать WAP-сообщения. Вредоносные приложения могут отслеживать ваши сообщения или удалять их, не показывая вам."</string>
+ <string name="permlab_getTasks">"извлечь запущенные приложения"</string>
+ <string name="permdesc_getTasks">"Позволяет приложению получать сведения о последних и текущих задачах. Вредоносные приложения могут получить доступ к конфиденциальной информации о других приложениях."</string>
+ <string name="permlab_reorderTasks">"изменять порядок запущенных приложений"</string>
+ <string name="permdesc_reorderTasks">"Позволяет приложению переключать режим выполнения задачи с активного на фоновый. Вредоносные приложения могут установить для себя активный режим без уведомления."</string>
+ <string name="permlab_setDebugApp">"запускать отладку приложения"</string>
+ <string name="permdesc_setDebugApp">"Позволяет приложению запускать процесс отладки другого приложения. Вредоносные приложения могут использовать эту возможность для остановки других приложений."</string>
+ <string name="permlab_changeConfiguration">"изменять настройки пользовательского интерфейса"</string>
+ <string name="permdesc_changeConfiguration">"Позволяет приложению изменять текущую конфигурацию, например региональные настройки или размер шрифта."</string>
+ <string name="permlab_restartPackages">"перезапускать другие приложения"</string>
+ <string name="permdesc_restartPackages">"Позволяет приложению принудительно перезапускать другие приложения."</string>
+ <string name="permlab_forceBack">"принудительно закрывать приложения"</string>
+ <string name="permdesc_forceBack">"Позволяет приложению принудительно закрыть или вернуть в исходное состояние процессы, выполняемые в активном режиме. Не требуется для обычных приложений."</string>
+ <string name="permlab_dump">"извлекать данные о внутреннем состоянии системы"</string>
+ <string name="permdesc_dump">"Позволяет приложению извлекать внутренние сведения о состоянии системы. Вредоносные приложения смогут извлечь разнообразные личные и защищенные сведения, в которых обычно нет необходимости."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"отслеживать и управлять запуском всех приложений"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Позволяет приложению отслеживать и управлять способом подключения системы. Вредоносные приложения могут разгласить конфиденциальную информацию о системе. Это разрешение необходимо только при разработке, но не при обычной работе с телефоном."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"отправлять рассылку об удалении пакета"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Позволяет приложению выполнять рассылку уведомлений об удалении пакета приложения. Вредоносные приложения могут использовать эту возможность для остановки всех остальных выполняющихся приложений."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"отправлять рассылку уведомлений о получении SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Позволяет приложению отправлять уведомления о получении SMS-сообщения. Вредоносные приложения могут использовать эту возможность для имитации получения SMS -сообщений."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"отправлять рассылку уведомлений о получении WAP-сообщений поставщика услуг"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Позволяет приложению отправлять уведомления о получении WAP-сообщения поставщика услуг. Вредоносные приложения могут использовать эту возможность для имитации получения MMS-сообщения или замены содержимого любой веб-страницы на вредоносное без уведомления."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничивать количество запущенных процессов"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Позволяет приложению управлять максимальным количеством выполняемых процессов. Не требуется для обычных приложений."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"закрывать все приложения, работающие в фоновом режиме"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Позволяет приложению контролировать, были ли действия завершены сразу же после их перехода в фоновый режим. Не требуется для обычных приложений."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"изменять статистику батареи"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Позволяет изменять собранную статистику батареи. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_runSetActivityWatcher">"отслеживать и управлять запуском всех приложений"</string>
+ <string name="permdesc_runSetActivityWatcher">"Позволяет приложению отслеживать и управлять способом подключения системы. Вредоносные приложения могут разгласить конфиденциальную информацию о системе. Это разрешение необходимо только при разработке, но не при обычной работе с телефоном."</string>
+ <string name="permlab_broadcastPackageRemoved">"отправлять рассылку об удалении пакета"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Позволяет приложению выполнять рассылку уведомлений об удалении пакета приложения. Вредоносные приложения могут использовать эту возможность для остановки всех остальных выполняющихся приложений."</string>
+ <string name="permlab_broadcastSmsReceived">"отправлять рассылку уведомлений о получении SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Позволяет приложению отправлять уведомления о получении SMS-сообщения. Вредоносные приложения могут использовать эту возможность для имитации получения SMS -сообщений."</string>
+ <string name="permlab_broadcastWapPush">"отправлять рассылку уведомлений о получении WAP-сообщений поставщика услуг"</string>
+ <string name="permdesc_broadcastWapPush">"Позволяет приложению отправлять уведомления о получении WAP-сообщения поставщика услуг. Вредоносные приложения могут использовать эту возможность для имитации получения MMS-сообщения или замены содержимого любой веб-страницы на вредоносное без уведомления."</string>
+ <string name="permlab_setProcessLimit">"ограничивать количество запущенных процессов"</string>
+ <string name="permdesc_setProcessLimit">"Позволяет приложению управлять максимальным количеством выполняемых процессов. Не требуется для обычных приложений."</string>
+ <string name="permlab_setAlwaysFinish">"закрывать все приложения, работающие в фоновом режиме"</string>
+ <string name="permdesc_setAlwaysFinish">"Позволяет приложению контролировать, были ли действия завершены сразу же после их перехода в фоновый режим. Не требуется для обычных приложений."</string>
+ <string name="permlab_batteryStats">"изменять статистику батареи"</string>
+ <string name="permdesc_batteryStats">"Позволяет изменять собранную статистику батареи. Не предназначено для использования обычными приложениями."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"показывать неавторизованные окна"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Разрешает создание окон, предназначенных для использования внутренним пользовательским интерфейсом системы. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"показывать оповещения системного уровня"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Позволяет приложению отображать окна предупреждений системы. Вредоносные приложения смогут получить контроль над всем экраном телефона."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"изменять глобальную скорость анимации"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Позволяет приложению в любое время изменять общую скорость анимации (ускоренная или замедленная анимация)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"управлять маркерами приложений"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Позволяет приложениям создавать собственные маркеры и управлять ими, обходя обычное Z-упорядочивание. Не требуется для обычных приложений."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"отрабатывать нажатия клавиш и кнопок управления"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Позволяет приложению передавать собственные события ввода (например, нажатия клавиш) в другие приложения. Вредоносные приложения могут использовать эту возможность для установки полного контроля над телефоном."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"записывать вводимый текст и совершаемые действия"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Позволяет приложению распознавать нажатые пользователем клавиши даже при работе с другим приложением (например, при вводе пароля). Не требуется для обычных приложений."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"связывать с методом ввода"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Позволяет выполнять привязку к интерфейсу ввода верхнего уровня. Не требуется для обычных приложений."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"изменять ориентацию экрана"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Позволяет приложению изменять ориентацию экрана в любое время. Не требуется для обычных приложений."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"отправлять приложениям сигналы Linux"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Позволяет приложению направлять запрос на передачу предоставленного сигнала всем постоянным процессам."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"запускать постоянную работу приложения"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Позволяет приложению сделать свои компоненты постоянными, благодаря чему система не может использовать их для других приложений."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"удалять приложения"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Позволяет приложению удалять пакеты Android. Вредоносные приложения могут использовать эту возможность для удаления важных приложений."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"удалять данные других приложений"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Позволяет приложению удалять данные пользователя."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"очищать кэши других приложений"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Позволяет приложению удалять файлы из кэша."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"определять объем памяти приложений"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Позволяет приложению получать сведения о размере кода, данных и кэша."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"устанавливать приложения непосредственно"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Позволяет приложению устанавливать новые или обновленные пакеты Android. Вредоносные приложения могут использовать эту возможность для добавления новых приложений со сколь угодно высоким уровнем разрешения."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"удалять все данные из кэша приложений"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Позволяет приложению освобождать память телефона с помощью удаления файлов из каталога кэша приложений. Обычно это разрешается только системным процессам."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"считывать системные файлы журналов"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получить сведения о работе пользователя с телефоном, но они не должны содержать какой-либо личной или конфиденциальной информации."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"считывать/записывать данные в ресурсы, принадлежащие группе диагностики"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Позволяет приложению считывать и записывать данные в любые ресурсы, принадлежащие группе диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Эта возможность может быть использована ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"включать или отключать компоненты приложения"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Позволяет приложению отключать или включать компоненты другого приложения. Вредоносные приложения могут использовать это разрешение для отключения важных возможностей телефона. Это разрешение следует использовать с осторожностью, так как это может привести к несовместимости, нестабильности и неработоспособности компонентов приложения."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"выбирать предпочтительные приложения"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Позволяет приложению изменять предпочтительные приложения. Вредоносные приложения могут использовать эту возможность для незаметного изменения запущенных приложений и для сбора конфиденциальной информации с помощью имитации подключения существующих приложений."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"изменять общие настройки системы"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Позволяет приложению изменять данные настроек системы. Вредоносные приложения могут повредить конфигурацию системы."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"изменять настройки системы безопасности"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Позволяет приложению изменять данные настроек безопасности системы. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"изменять карту служб Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Позволяет приложению изменять карту служб Google. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"автоматически запускать при загрузке"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Позволяет приложению запускаться сразу же по завершении загрузки. Это может увеличить время запуска телефона и замедлить его работу в связи с постоянной работой приложения."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"отправить несрочную рассылку"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Позволяет приложению отправлять несрочные рассылки, которые остались по завершении данной рассылки. Вредоносные приложения могут замедлить работу телефона или сделать ее нестабильной с помощью использования слишком большого объема памяти."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"считывать данные контакта"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Позволяет приложению считывать все данные контактов (адресов), сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для передачи данных посторонним лицам."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"перезаписывать данные контакта"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Позволяет приложению изменять данные (адрес) контакта, сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для удаления или изменения данных контакта."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"перезаписывать данные о владельце"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Позволяет приложению изменять сведения о владельце, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для удаления или изменения данных владельца."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"считывать данные о владельце"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Позволяет приложению считывать сведения о владельце, сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для считывания данных владельца."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"считывать данные календаря"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Позволяет приложению считывать все события календаря, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для передачи ваших событий календаря посторонним лицам."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"записывать данные календаря"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Позволяет приложению изменять события календаря, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для удаления или изменения событий календаря."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"копировать источники мест для проверки"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Создавать копии источников данных о местоположении для проверки. Вредоносные приложения могут использовать эту возможность для перезаписи места и/или состояния, возвращаемого действительными источниками данных о местоположении, такими как GPS или операторы связи."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"получать доступ к дополнительным командам источника данных о местоположении"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Получать доступ к дополнительным командам поставщика данных о местоположении. Вредоносные приложения могут использовать эту возможность для вмешательства в работу GPS или других источников места."</string>
+ <string name="permlab_internalSystemWindow">"показывать неавторизованные окна"</string>
+ <string name="permdesc_internalSystemWindow">"Разрешает создание окон, предназначенных для использования внутренним пользовательским интерфейсом системы. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_systemAlertWindow">"показывать оповещения системного уровня"</string>
+ <string name="permdesc_systemAlertWindow">"Позволяет приложению отображать окна предупреждений системы. Вредоносные приложения смогут получить контроль над всем экраном телефона."</string>
+ <string name="permlab_setAnimationScale">"изменять глобальную скорость анимации"</string>
+ <string name="permdesc_setAnimationScale">"Позволяет приложению в любое время изменять общую скорость анимации (ускоренная или замедленная анимация)."</string>
+ <string name="permlab_manageAppTokens">"управлять маркерами приложений"</string>
+ <string name="permdesc_manageAppTokens">"Позволяет приложениям создавать собственные маркеры и управлять ими, обходя обычное Z-упорядочивание. Не требуется для обычных приложений."</string>
+ <string name="permlab_injectEvents">"отрабатывать нажатия клавиш и кнопок управления"</string>
+ <string name="permdesc_injectEvents">"Позволяет приложению передавать собственные события ввода (например, нажатия клавиш) в другие приложения. Вредоносные приложения могут использовать эту возможность для установки полного контроля над телефоном."</string>
+ <string name="permlab_readInputState">"записывать вводимый текст и совершаемые действия"</string>
+ <string name="permdesc_readInputState">"Позволяет приложению распознавать нажатые пользователем клавиши даже при работе с другим приложением (например, при вводе пароля). Не требуется для обычных приложений."</string>
+ <string name="permlab_bindInputMethod">"связывать с методом ввода"</string>
+ <string name="permdesc_bindInputMethod">"Позволяет выполнять привязку к интерфейсу ввода верхнего уровня. Не требуется для обычных приложений."</string>
+ <string name="permlab_setOrientation">"изменять ориентацию экрана"</string>
+ <string name="permdesc_setOrientation">"Позволяет приложению изменять ориентацию экрана в любое время. Не требуется для обычных приложений."</string>
+ <string name="permlab_signalPersistentProcesses">"отправлять приложениям сигналы Linux"</string>
+ <string name="permdesc_signalPersistentProcesses">"Позволяет приложению направлять запрос на передачу предоставленного сигнала всем постоянным процессам."</string>
+ <string name="permlab_persistentActivity">"запускать постоянную работу приложения"</string>
+ <string name="permdesc_persistentActivity">"Позволяет приложению сделать свои компоненты постоянными, благодаря чему система не может использовать их для других приложений."</string>
+ <string name="permlab_deletePackages">"удалять приложения"</string>
+ <string name="permdesc_deletePackages">"Позволяет приложению удалять пакеты Android. Вредоносные приложения могут использовать эту возможность для удаления важных приложений."</string>
+ <string name="permlab_clearAppUserData">"удалять данные других приложений"</string>
+ <string name="permdesc_clearAppUserData">"Позволяет приложению удалять данные пользователя."</string>
+ <string name="permlab_deleteCacheFiles">"очищать кэши других приложений"</string>
+ <string name="permdesc_deleteCacheFiles">"Позволяет приложению удалять файлы из кэша."</string>
+ <string name="permlab_getPackageSize">"определять объем памяти приложений"</string>
+ <string name="permdesc_getPackageSize">"Позволяет приложению получать сведения о размере кода, данных и кэша."</string>
+ <string name="permlab_installPackages">"устанавливать приложения непосредственно"</string>
+ <string name="permdesc_installPackages">"Позволяет приложению устанавливать новые или обновленные пакеты Android. Вредоносные приложения могут использовать эту возможность для добавления новых приложений со сколь угодно высоким уровнем разрешения."</string>
+ <string name="permlab_clearAppCache">"удалять все данные из кэша приложений"</string>
+ <string name="permdesc_clearAppCache">"Позволяет приложению освобождать память телефона с помощью удаления файлов из каталога кэша приложений. Обычно это разрешается только системным процессам."</string>
+ <string name="permlab_readLogs">"считывать системные файлы журналов"</string>
+ <string name="permdesc_readLogs">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получить сведения о работе пользователя с телефоном, но они не должны содержать какой-либо личной или конфиденциальной информации."</string>
+ <string name="permlab_diagnostic">"считывать/записывать данные в ресурсы, принадлежащие группе диагностики"</string>
+ <string name="permdesc_diagnostic">"Позволяет приложению считывать и записывать данные в любые ресурсы, принадлежащие группе диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Эта возможность может быть использована ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
+ <string name="permlab_changeComponentState">"включать или отключать компоненты приложения"</string>
+ <string name="permdesc_changeComponentState">"Позволяет приложению отключать или включать компоненты другого приложения. Вредоносные приложения могут использовать это разрешение для отключения важных возможностей телефона. Это разрешение следует использовать с осторожностью, так как это может привести к несовместимости, нестабильности и неработоспособности компонентов приложения."</string>
+ <string name="permlab_setPreferredApplications">"выбирать предпочтительные приложения"</string>
+ <string name="permdesc_setPreferredApplications">"Позволяет приложению изменять предпочтительные приложения. Вредоносные приложения могут использовать эту возможность для незаметного изменения запущенных приложений и для сбора конфиденциальной информации с помощью имитации подключения существующих приложений."</string>
+ <string name="permlab_writeSettings">"изменить общие настройки системы"</string>
+ <string name="permdesc_writeSettings">"Позволяет приложению изменять данные настроек системы. Вредоносные приложения могут повредить конфигурацию системы."</string>
+ <string name="permlab_writeSecureSettings">"изменять настройки системы безопасности"</string>
+ <string name="permdesc_writeSecureSettings">"Позволяет приложению изменять данные настроек безопасности системы. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_writeGservices">"изменить карту служб Google"</string>
+ <string name="permdesc_writeGservices">"Позволяет приложению изменять карту служб Google. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_receiveBootCompleted">"автоматически запускать при загрузке"</string>
+ <string name="permdesc_receiveBootCompleted">"Позволяет приложению запускаться сразу же по завершении загрузки. Это может увеличить время запуска телефона и замедлить его работу в связи с постоянной работой приложения."</string>
+ <string name="permlab_broadcastSticky">"отправить несрочную рассылку"</string>
+ <string name="permdesc_broadcastSticky">"Позволяет приложению отправлять несрочные рассылки, которые остались по завершении данной рассылки. Вредоносные приложения могут замедлить работу телефона или сделать ее нестабильной с помощью использования слишком большого объема памяти."</string>
+ <string name="permlab_readContacts">"считывать данные контакта"</string>
+ <string name="permdesc_readContacts">"Позволяет приложению считывать все данные контактов (адресов), сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для передачи данных посторонним лицам."</string>
+ <string name="permlab_writeContacts">"перезаписывать данные контакта"</string>
+ <string name="permdesc_writeContacts">"Позволяет приложению изменять данные (адрес) контакта, сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для удаления или изменения данных контакта."</string>
+ <string name="permlab_writeOwnerData">"перезаписывать данные о владельце"</string>
+ <string name="permdesc_writeOwnerData">"Позволяет приложению изменять сведения о владельце, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для удаления или изменения данных владельца."</string>
+ <string name="permlab_readOwnerData">"считывать данные о владельце"</string>
+ <string name="permdesc_readOwnerData">"Позволяет приложению считывать сведения о владельце, сохраненные в памяти телефона. Вредоносные приложения могут использовать эту возможность для считывания данных владельца."</string>
+ <string name="permlab_readCalendar">"считывать данные календаря"</string>
+ <string name="permdesc_readCalendar">"Позволяет приложению считывать все события календаря, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для передачи ваших событий календаря посторонним лицам."</string>
+ <string name="permlab_writeCalendar">"записывать данные календаря"</string>
+ <string name="permdesc_writeCalendar">"Позволяет приложению изменять события календаря, сохраненные на телефоне. Вредоносные приложения могут использовать эту возможность для удаления или изменения событий календаря."</string>
+ <string name="permlab_accessMockLocation">"копировать источники мест для проверки"</string>
+ <string name="permdesc_accessMockLocation">"Создавать копии источников данных о местоположении для проверки. Вредоносные приложения могут использовать эту возможность для перезаписи места и/или состояния, возвращаемого действительными источниками данных о местоположении, такими как GPS или операторы связи."</string>
+ <string name="permlab_accessLocationExtraCommands">"получать доступ к дополнительным командам источника данных о местоположении"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Получать доступ к дополнительным командам поставщика данных о местоположении. Вредоносные приложения могут использовать эту возможность для вмешательства в работу GPS или других источников места."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"точное местоположение (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Получать доступ к источникам точного местоположения, таким как GPS, если возможно. Вредоносные приложения могут использовать это разрешение для определения вашего местоположения и расходовать ресурс батареи."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"отслеживать местоположение по сигналам сети"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Получать доступ к источникам данных о местоположении, таким как база данных сотовой сети, для определения приблизительного местоположения телефона, если возможно. Вредоносные приложения могут использовать эту возможность для определения вашего приблизительного местоположения."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"получать доступ к SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Позволяет приложению использовать функции SurfaceFlinger нижнего уровня."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"считывать буфер фреймов"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Позволяет приложению использовать функцию чтения содержимого буфера фреймов."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"изменять настройки аудио"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Позволяет приложению изменять глобальные аудионастройки, такие как громкость и маршрутизацию."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"записывать аудио"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Позволяет приложению получать доступ к пути аудиозаписи."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"снимать фотографии"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Позволяет приложению делать снимки с помощью камеры. Это разрешение позволяет приложению в любое время собирать изображения, видимые через объектив камеры."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"отключать телефон"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Позволяет данному приложению отключить телефон навсегда. Это очень опасно."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"принудительно перезагружать телефон"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Позволяет приложению принудительно перезагружать телефон."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"монтировать и удалять файловые системы"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Позволяет приложению монтировать и удалять файловые системы съемных носителей."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"форматировать внешний накопитель"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Позволяет приложению форматировать съемный накопитель."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"управлять вибровызовом"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Позволяет приложению управлять виброзвонком."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"управлять вспышкой"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Позволяет приложению управлять вспышкой."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"проверять аппаратное обеспечение"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Позволяет приложению управлять различными периферийными устройствами для проверки аппаратного обеспечения."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"посылать прямые вызовы на номера телефонов"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Позволяет приложению вызывать телефонные номера без вмешательства пользователя. Вредоносные приложения могут осуществлять нежелательные вызовы. Это разрешение не позволяет приложению совершать вызовы служб экстренной помощи."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"посылать прямые вызовы на любые номера"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Позволяет приложению осуществлять вызов любого номера, включая номера экстренной помощи, без вмешательства пользователя. Вредоносные приложения могут осуществить нежелательные или незаконные вызовы служб экстренной помощи."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"управлять уведомлениями об обновлении местоположения"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Позволяет включать/отключать отправку уведомлений об обновлениях местоположения по радиосвязи. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"получать доступ к свойствам регистрации"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Позволяет получать доступ для чтения/записи свойств, загруженных службой регистрации. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"выбирать виджеты"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Позволяет приложению сообщить системе, какие приложения могут использовать какие виджеты. Это разрешение позволяет приложениям предоставлять другим приложениям доступ к личной информации. Не предназначено для использования обычными приложениями."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"изменять состояние телефона"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Позволяет приложению управлять функциями телефона в устройстве. Приложение, обладающее этим разрешением, может переключать сети, включать и выключать радио на телефоне и выполнять другие подобные действия без соответствующего уведомления."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"предотвратить переключение телефона в спящий режим"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Позволяет приложению запретить переход телефона в спящий режим"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"включать и выключать питание телефона"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Позволяет приложению включать и отключать телефон."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"запустить в тестовом режиме"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Выполнить стандартную проверку нижнего уровня, обеспечивающую полный доступ к аппаратному обеспечению телефона. Доступно, только в режиме стандартной проверки."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"устанавливать фоновый рисунок"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Позволяет данному приложению устанавливать системный фоновый рисунок."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"давать рекомендации по размеру фоновых рисунков"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Позволяет данному приложению устанавливать советы по размеру фоновых рисунков."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"восстанавливать параметры системы по умолчанию, установленные на заводе-изготовителе"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Позволяет приложению восстановить стандартные настройки системы, удалив все данные, конфигурацию и установленные приложения."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"настраивать часовой пояс"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Позволяет приложению изменять часовой пояс телефона."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"обнаруживать известные аккаунты"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Позволяет приложению получать список аккаунтов, известных телефону."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"просматривать состояние сети"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Позволяет приложению просматривать состояние всех сетей."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"неограниченный доступ в Интернет"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Позволяет приложению создавать сетевые сокеты."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"записывать настройки имени точки доступа"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Позволяет приложению изменять настройки APN, такие как прокси-сервер и порт любого APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"изменять настройки подключения к сети"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Позволяет приложению изменять состояние подключаемости сети."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"изменять настройки использования данных в фоновом режиме"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Позволяет приложению изменять настройку использования данных в фоновом режиме."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"просматривать состояние Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Позволяет приложению просматривать сведения о состоянии Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"изменять состояние Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Позволяет приложению подключаться к точкам доступа Wi-Fi и отключаться от них, а также вносить изменения в конфигурацию сетей Wi-Fi."</string>
+ <string name="permlab_accessFineLocation">"точное местоположение (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Получать доступ к источникам точного местоположения, таким как GPS, если возможно. Вредоносные приложения могут использовать это разрешение для определения вашего местоположения и расходовать ресурс батареи."</string>
+ <string name="permlab_accessCoarseLocation">"отслеживать местоположение по сигналам сети"</string>
+ <string name="permdesc_accessCoarseLocation">"Получать доступ к источникам данных о местоположении, таким как база данных сотовой сети, для определения приблизительного местоположения телефона, если возможно. Вредоносные приложения могут использовать эту возможность для определения вашего приблизительного местоположения."</string>
+ <string name="permlab_accessSurfaceFlinger">"получать доступ к SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Позволяет приложению использовать функции SurfaceFlinger нижнего уровня."</string>
+ <string name="permlab_readFrameBuffer">"считывать буфер фреймов"</string>
+ <string name="permdesc_readFrameBuffer">"Позволяет приложению использовать функцию чтения содержимого буфера фреймов."</string>
+ <string name="permlab_modifyAudioSettings">"изменять настройки аудио"</string>
+ <string name="permdesc_modifyAudioSettings">"Позволяет приложению изменять глобальные аудионастройки, такие как громкость и маршрутизацию."</string>
+ <string name="permlab_recordAudio">"записывать аудио"</string>
+ <string name="permdesc_recordAudio">"Позволяет приложению получать доступ к пути аудиозаписи."</string>
+ <string name="permlab_camera">"снимать фотографии"</string>
+ <string name="permdesc_camera">"Позволяет приложению делать снимки с помощью камеры. Это разрешение позволяет приложению в любое время собирать изображения, видимые через объектив камеры."</string>
+ <string name="permlab_brick">"отключать телефон"</string>
+ <string name="permdesc_brick">"Позволяет данному приложению отключить телефон навсегда. Это очень опасно."</string>
+ <string name="permlab_reboot">"принудительно перезагружать телефон"</string>
+ <string name="permdesc_reboot">"Позволяет приложению принудительно перезагружать телефон."</string>
+ <string name="permlab_mount_unmount_filesystems">"монтировать и удалять файловые системы"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Позволяет приложению монтировать и удалять файловые системы съемных носителей."</string>
+ <string name="permlab_mount_format_filesystems">"форматировать внешний накопитель"</string>
+ <string name="permdesc_mount_format_filesystems">"Позволяет приложению форматировать съемный накопитель."</string>
+ <string name="permlab_vibrate">"управлять вибровызовом"</string>
+ <string name="permdesc_vibrate">"Позволяет приложению управлять виброзвонком."</string>
+ <string name="permlab_flashlight">"управлять вспышкой"</string>
+ <string name="permdesc_flashlight">"Позволяет приложению управлять вспышкой."</string>
+ <string name="permlab_hardware_test">"проверять аппаратное обеспечение"</string>
+ <string name="permdesc_hardware_test">"Позволяет приложению управлять различными периферийными устройствами для проверки аппаратного обеспечения."</string>
+ <string name="permlab_callPhone">"посылать прямые вызовы на номера телефонов"</string>
+ <string name="permdesc_callPhone">"Позволяет приложению вызывать телефонные номера без вмешательства пользователя. Вредоносные приложения могут осуществлять нежелательные вызовы. Это разрешение не позволяет приложению совершать вызовы служб экстренной помощи."</string>
+ <string name="permlab_callPrivileged">"посылать прямые вызовы на любые номера"</string>
+ <string name="permdesc_callPrivileged">"Позволяет приложению осуществлять вызов любого номера, включая номера экстренной помощи, без вмешательства пользователя. Вредоносные приложения могут осуществить нежелательные или незаконные вызовы служб экстренной помощи."</string>
+ <string name="permlab_locationUpdates">"управлять уведомлениями об обновлении местоположения"</string>
+ <string name="permdesc_locationUpdates">"Позволяет включать/отключать отправку уведомлений об обновлениях местоположения по радиосвязи. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_checkinProperties">"получать доступ к свойствам регистрации"</string>
+ <string name="permdesc_checkinProperties">"Позволяет получать доступ для чтения/записи свойств, загруженных службой регистрации. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_bindGadget">"выбирать виджеты"</string>
+ <string name="permdesc_bindGadget">"Позволяет приложению сообщить системе, какие приложения могут использовать какие виджеты. Это разрешение позволяет приложениям предоставлять другим приложениям доступ к личной информации. Не предназначено для использования обычными приложениями."</string>
+ <string name="permlab_modifyPhoneState">"изменять состояние телефона"</string>
+ <string name="permdesc_modifyPhoneState">"Позволяет приложению управлять функциями телефона в устройстве. Приложение, обладающее этим разрешением, может переключать сети, включать и выключать радио на телефоне и выполнять другие подобные действия без соответствующего уведомления."</string>
+ <string name="permlab_readPhoneState">"считывать состояние телефона"</string>
+ <string name="permdesc_readPhoneState">"Позволяет приложению получить доступ к функциям телефона на устройстве. Приложение с таким разрешением может определить номер телефона устройства, наличие активного вызова, номер вызываемого/вызывающего абонента и тому подобное."</string>
+ <string name="permlab_wakeLock">"предотвратить переключение телефона в спящий режим"</string>
+ <string name="permdesc_wakeLock">"Позволяет приложению запретить переход телефона в спящий режим"</string>
+ <string name="permlab_devicePower">"включать и выключать питание телефона"</string>
+ <string name="permdesc_devicePower">"Позволяет приложению включать и отключать телефон."</string>
+ <string name="permlab_factoryTest">"запустить в тестовом режиме"</string>
+ <string name="permdesc_factoryTest">"Выполнить стандартную проверку нижнего уровня, обеспечивающую полный доступ к аппаратному обеспечению телефона. Доступно, только в режиме стандартной проверки."</string>
+ <string name="permlab_setWallpaper">"устанавливать фоновый рисунок"</string>
+ <string name="permdesc_setWallpaper">"Позволяет данному приложению устанавливать системный фоновый рисунок."</string>
+ <string name="permlab_setWallpaperHints">"давать рекомендации по размеру фоновых рисунков"</string>
+ <string name="permdesc_setWallpaperHints">"Позволяет данному приложению устанавливать советы по размеру фоновых рисунков."</string>
+ <string name="permlab_masterClear">"восстанавливать параметры системы по умолчанию, установленные на заводе-изготовителе"</string>
+ <string name="permdesc_masterClear">"Позволяет приложению восстановить стандартные настройки системы, удалив все данные, конфигурацию и установленные приложения."</string>
+ <string name="permlab_setTimeZone">"настраивать часовой пояс"</string>
+ <string name="permdesc_setTimeZone">"Позволяет приложению изменять часовой пояс телефона."</string>
+ <string name="permlab_getAccounts">"обнаруживать известные аккаунты"</string>
+ <string name="permdesc_getAccounts">"Позволяет приложению получать список аккаунтов, известных телефону."</string>
+ <string name="permlab_accessNetworkState">"просматривать состояние сети"</string>
+ <string name="permdesc_accessNetworkState">"Позволяет приложению просматривать состояние всех сетей."</string>
+ <string name="permlab_createNetworkSockets">"неограниченный доступ в Интернет"</string>
+ <string name="permdesc_createNetworkSockets">"Позволяет приложению создавать сетевые сокеты."</string>
+ <string name="permlab_writeApnSettings">"записывать настройки имени точки доступа"</string>
+ <string name="permdesc_writeApnSettings">"Позволяет приложению изменять настройки APN, такие как прокси-сервер и порт любого APN."</string>
+ <string name="permlab_changeNetworkState">"изменять настройки подключения к сети"</string>
+ <string name="permdesc_changeNetworkState">"Позволяет приложению изменять состояние подключаемости сети."</string>
+ <string name="permlab_changeBackgroundDataSetting">"изменить настройку использования данных в фоновом режиме"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Позволяет приложению изменять настройку использования данных в фоновом режиме."</string>
+ <string name="permlab_accessWifiState">"просматривать состояние Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Позволяет приложению просматривать сведения о состоянии Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"изменять состояние Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Позволяет приложению подключаться к точкам доступа Wi-Fi и отключаться от них, а также вносить изменения в конфигурацию сетей Wi-Fi."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"управление Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Позволяет приложению настраивать локальный телефон Bluetooth, обнаруживать и выполнять сопряжение удаленных устройств."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"создавать подключения Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Позволяет приложению просматривать конфигурацию локального телефона Bluetooth, создавать подключения с сопряженными устройствами."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"отключать блокировку клавиатуры"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Позволяет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допустимого использования этой функции является отключение блокировки клавиатуры при получении входящего вызова и включение блокировки после завершения разговора."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"считывать настройки синхронизации"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Позволяет приложению считывать настройки синхронизации, такие как включение синхронизации Контактов."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"записывать настройки синхронизации"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Позволяет приложению изменять настройки синхронизации, например включение синхронизации Контактов."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"считывать статистику синхронизации"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Позволяет приложению считывать статистику синхронизации, например историю произведенных синхронизаций."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"считывать каналы, на которые есть подписка"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Позволяет приложению получить сведения о последних синхронизированных каналах."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"изменять каналы, на которые есть подписка"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Позволяет приложению изменять синхронизированные каналы. Вредоносные приложения могут использовать эту возможность для изменения синхронизированных каналов."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"выполнять чтение из пользовательского словаря"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Позволяет приложению считывать любые слова, имена и фразы личного пользования, которые могут храниться в пользовательском словаре."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"записывать в пользовательский словарь"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Позволяет приложению записывать новые слова в пользовательский словарь."</string>
+ <string name="permlab_bluetoothAdmin">"управление Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Позволяет приложению настраивать локальный телефон Bluetooth, обнаруживать и выполнять сопряжение удаленных устройств."</string>
+ <string name="permlab_bluetooth">"создавать подключения Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Позволяет приложению просматривать конфигурацию локального телефона Bluetooth, создавать подключения с сопряженными устройствами."</string>
+ <string name="permlab_disableKeyguard">"отключать блокировку клавиатуры"</string>
+ <string name="permdesc_disableKeyguard">"Позволяет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допустимого использования этой функции является отключение блокировки клавиатуры при получении входящего вызова и включение блокировки после завершения разговора."</string>
+ <string name="permlab_readSyncSettings">"считывать настройки синхронизации"</string>
+ <string name="permdesc_readSyncSettings">"Позволяет приложению считывать настройки синхронизации, такие как включение синхронизации Контактов."</string>
+ <string name="permlab_writeSyncSettings">"записывать настройки синхронизации"</string>
+ <string name="permdesc_writeSyncSettings">"Позволяет приложению изменять настройки синхронизации, например включение синхронизации Контактов."</string>
+ <string name="permlab_readSyncStats">"считывать статистику синхронизации"</string>
+ <string name="permdesc_readSyncStats">"Позволяет приложению считывать статистику синхронизации, например историю произведенных синхронизаций."</string>
+ <string name="permlab_subscribedFeedsRead">"считывать каналы, на которые есть подписка"</string>
+ <string name="permdesc_subscribedFeedsRead">"Позволяет приложению получить сведения о последних синхронизированных каналах."</string>
+ <string name="permlab_subscribedFeedsWrite">"изменять каналы, на которые есть подписка"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Позволяет приложению изменять синхронизированные каналы. Вредоносные приложения могут использовать эту возможность для изменения синхронизированных каналов."</string>
+ <string name="permlab_readDictionary">"выполнять чтение из пользовательского словаря"</string>
+ <string name="permdesc_readDictionary">"Позволяет приложению считывать любые слова, имена и фразы личного пользования, которые могут храниться в пользовательском словаре."</string>
+ <string name="permlab_writeDictionary">"записывать в пользовательский словарь"</string>
+ <string name="permdesc_writeDictionary">"Позволяет приложению записывать новые слова в пользовательский словарь."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Домашний"</item>
- <item msgid="869923650527136615">"Мобильный"</item>
- <item msgid="7897544654242874543">"Рабочий"</item>
- <item msgid="1103601433382158155">"Рабочий факс"</item>
- <item msgid="1735177144948329370">"Домашний факс"</item>
- <item msgid="603878674477207394">"Пейджер"</item>
- <item msgid="1650824275177931637">"Другой"</item>
- <item msgid="9192514806975898961">"Особый"</item>
+ <item>"Домашний"</item>
+ <item>"Мобильный"</item>
+ <item>"Рабочий"</item>
+ <item>"Рабочий факс"</item>
+ <item>"Домашний факс"</item>
+ <item>"Пейджер"</item>
+ <item>"Другой"</item>
+ <item>"Особый"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Домашний"</item>
- <item msgid="7084237356602625604">"Рабочий"</item>
- <item msgid="1112044410659011023">"Другой"</item>
- <item msgid="2374913952870110618">"Особый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"Особый"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Мобильный"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Домашний"</item>
- <item msgid="5629153956045109251">"Рабочий"</item>
- <item msgid="4966604264500343469">"Другой"</item>
- <item msgid="4932682847595299369">"Особый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"Особый"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Домашний"</item>
- <item msgid="1359644565647383708">"Рабочий"</item>
- <item msgid="7868549401053615677">"Другое"</item>
- <item msgid="3145118944639869809">"Особый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другое"</item>
+ <item>"Особый"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Рабочий"</item>
- <item msgid="4378074129049520373">"Другой"</item>
- <item msgid="3455047468583965104">"Особый"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"Особый"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Введите PIN-код"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Неверный PIN-код!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Для разблокировки нажмите \"Меню\", а затем 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Экстренная служба"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Сеть не найдена)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран заблокирован."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Для разблокировки нажмите \"Меню\"."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Для разблокировки введите графический ключ"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Вызов службы экстренной помощи"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правильно!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Повторите попытку"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Введите PIN-код"</string>
+ <string name="keyguard_password_wrong_pin_code">"Неверный PIN-код!"</string>
+ <string name="keyguard_label_text">"Для разблокировки нажмите \"Меню\", а затем 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Номер экстренной службы"</string>
+ <string name="lockscreen_carrier_default">"(Сеть не найдена)"</string>
+ <string name="lockscreen_screen_locked">"Экран заблокирован."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Для разблокировки нажмите \"Меню\"."</string>
+ <string name="lockscreen_pattern_instructions">"Для разблокировки введите графический ключ"</string>
+ <string name="lockscreen_emergency_call">"Вызов службы экстренной помощи"</string>
+ <string name="lockscreen_pattern_correct">"Правильно!"</string>
+ <string name="lockscreen_pattern_wrong">"Повторите попытку"</string>
+ <string name="lockscreen_plugged_in">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарядное устройство."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Нет SIM-карты."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"SIM-карта не установлена."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Вставьте SIM-карту."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Сеть заблокирована"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-карта заблокирована с помощью кода PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"См. руководство пользователя или свяжитесь со службой поддержки."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблокирована."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблокировка SIM-карты…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. После <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон с помощью учетных данных Google.\n "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> с."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забыли графический ключ?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Слишком много попыток ввода графического ключа!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Для разблокировки войдите с помощью своего аккаунта Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Имя пользователя (электронная почта)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Вход"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неверное имя пользователя или пароль."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Подключите зарядное устройство."</string>
+ <string name="lockscreen_missing_sim_message_short">"Нет SIM-карты."</string>
+ <string name="lockscreen_missing_sim_message">"SIM-карта не установлена."</string>
+ <string name="lockscreen_missing_sim_instructions">"Вставьте SIM-карту."</string>
+ <string name="lockscreen_network_locked_message">"Сеть заблокирована"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-карта заблокирована с помощью кода PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"См. руководство пользователя или свяжитесь со службой поддержки."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-карта заблокирована."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Разблокировка SIM-карты…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. После <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон с помощью учетных данных Google.\n "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Забыли графический ключ?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Слишком много попыток ввода графического ключа!"</string>
+ <string name="lockscreen_glogin_instructions">"Для разблокировки войдите с помощью своего аккаунта Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Имя пользователя (электронная почта)"</string>
+ <string name="lockscreen_glogin_password_hint">"Пароль"</string>
+ <string name="lockscreen_glogin_submit_button">"Вход"</string>
+ <string name="lockscreen_glogin_invalid_input">"Неверное имя пользователя или пароль."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нет уведомлений"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Идет зарядка..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Подключите зарядное устройство"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Батарея разряжена:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"осталось менее <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="status_bar_no_notifications_title">"Нет уведомлений"</string>
+ <string name="status_bar_ongoing_events_title">"Текущие"</string>
+ <string name="status_bar_latest_events_title">"Уведомления"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Идет зарядка..."</string>
+ <string name="battery_low_title">"Подключите зарядное устройство"</string>
+ <string name="battery_low_subtitle">"Батарея разряжена:"</string>
+ <string name="battery_low_percent_format">"осталось менее <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Не удалось провести стандартный тест"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Действие FACTORY_TEST поддерживается только для пакетов, установленных в /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Пакет, обеспечивающий действие FACTORY_TEST, не найден."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"На странице по адресу \"<xliff:g id="TITLE">%s</xliff:g>\" сказано:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Перейти с этой страницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться на текущей странице."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
+ <string name="factorytest_failed">"Не удалось провести стандартный тест"</string>
+ <string name="factorytest_not_system">"Действие FACTORY_TEST поддерживается только для пакетов, установленных в /system/app."</string>
+ <string name="factorytest_no_action">"Пакет, обеспечивающий действие FACTORY_TEST, не найден."</string>
+ <string name="factorytest_reboot">"Перезагрузка"</string>
+ <string name="js_dialog_title">"На странице по адресу \"<xliff:g id="TITLE">%s</xliff:g>\" сказано:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Перейти с этой страницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться на текущей странице."</string>
+ <string name="save_password_label">"Подтвердите"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Никогда"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"У вас нет разрешения на открытие этой страницы."</string>
- <string name="text_copied" msgid="4985729524670131385">"Текст скопирован в буфер обмена."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Дополнительно"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Меню+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"пробел"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ввод"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"удалить"</string>
- <string name="search_go" msgid="8298016669822141719">"Поиск"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string>
+ <string name="save_password_message">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
+ <string name="save_password_notnow">"Не сейчас"</string>
+ <string name="save_password_remember">"Запомнить"</string>
+ <string name="save_password_never">"Никогда"</string>
+ <string name="open_permission_deny">"У вас нет разрешения на открытие этой страницы."</string>
+ <string name="text_copied">"Текст скопирован в буфер обмена."</string>
+ <string name="more_item_label">"Дополнительно"</string>
+ <string name="prepend_shortcut_label">"Меню+"</string>
+ <string name="menu_space_shortcut_label">"пробел"</string>
+ <string name="menu_enter_shortcut_label">"ввод"</string>
+ <string name="menu_delete_shortcut_label">"удалить"</string>
+ <string name="search_go">"Поиск"</string>
+ <string name="oneMonthDurationPast">"1 месяц назад"</string>
+ <string name="beforeOneMonthDurationPast">"Более месяца назад"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 секунду назад"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> с. назад"</item>
+ <item quantity="one">"1 секунду назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> с. назад"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 минуту назад"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
+ <item quantity="one">"1 минуту назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 час назад"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
+ <item quantity="one">"1 час назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"вчера"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
+ <item quantity="one">"вчера"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"через 1 секунду"</item>
- <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
+ <item quantity="one">"через 1 секунду"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"через 1 минуту"</item>
- <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
+ <item quantity="one">"через 1 минуту"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"через 1 час"</item>
- <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
+ <item quantity="one">"через 1 час"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"завтра"</item>
- <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
+ <item quantity="one">"завтра"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 сек. назад"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
+ <item quantity="one">"1 сек. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 мин. назад"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
+ <item quantity="one">"1 мин. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 час назад"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
+ <item quantity="one">"1 час назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"вчера"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
+ <item quantity="one">"вчера"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
- <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
+ <item quantity="one">"через 1 с."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"через 1 мин."</item>
- <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
+ <item quantity="one">"через 1 мин."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"через 1 час"</item>
- <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
+ <item quantity="one">"через 1 час"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"завтра"</item>
- <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
+ <item quantity="one">"завтра"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"в %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"в %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"через %s"</string>
- <string name="day" msgid="8144195776058119424">"дн."</string>
- <string name="days" msgid="4774547661021344602">"дн."</string>
- <string name="hour" msgid="2126771916426189481">"ч."</string>
- <string name="hours" msgid="894424005266852993">"ч."</string>
- <string name="minute" msgid="9148878657703769868">"мин."</string>
- <string name="minutes" msgid="5646001005827034509">"мин."</string>
- <string name="second" msgid="3184235808021478">"с."</string>
- <string name="seconds" msgid="3161515347216589235">"с."</string>
- <string name="week" msgid="5617961537173061583">"нед."</string>
- <string name="weeks" msgid="6509623834583944518">"нед."</string>
- <string name="year" msgid="4001118221013892076">"г."</string>
- <string name="years" msgid="6881577717993213522">"г."</string>
- <string name="every_weekday" msgid="8777593878457748503">"Каждый рабочий день (пн-пт)"</string>
- <string name="daily" msgid="5738949095624133403">"Ежедневно"</string>
- <string name="weekly" msgid="983428358394268344">"Еженедельно, <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Ежемесячно"</string>
- <string name="yearly" msgid="1519577999407493836">"Ежегодно"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Не удалось воспроизвести видео"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Это видео не подходит для потокового воспроизведения на данном устройстве."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Невозможно воспроизвести видео."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"ОК"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"полдень"</string>
- <string name="Noon" msgid="3342127745230013127">"Полдень"</string>
- <string name="midnight" msgid="7166259508850457595">"полночь"</string>
- <string name="Midnight" msgid="5630806906897892201">"Полночь"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Выбрать все"</string>
- <string name="selectText" msgid="3889149123626888637">"Выбрать текст"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Остановить выделение текста"</string>
- <string name="cut" msgid="3092569408438626261">"Вырезать"</string>
- <string name="cutAll" msgid="2436383270024931639">"Вырезать все"</string>
- <string name="copy" msgid="2681946229533511987">"Копировать"</string>
- <string name="copyAll" msgid="2590829068100113057">"Копировать все"</string>
- <string name="paste" msgid="5629880836805036433">"Вставить"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Копировать URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Способ ввода"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Добавить \"%s\" в словарь"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Изменить текст"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Недостаточно места"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Заканчивается место в памяти телефона."</string>
- <string name="ok" msgid="5970060430562524910">"ОК"</string>
- <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
- <string name="yes" msgid="5362982303337969312">"ОК"</string>
- <string name="no" msgid="5141531044935541497">"Отмена"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
- <string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
- <string name="capital_off" msgid="6815870386972805832">"ВЫКЛ"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Завершить действие с помощью"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Использовать по умолчанию для этого действия."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Удалить настройки по умолчанию: главный экран > \"Настройки\" > \"Приложения\" > \"Управление приложениями\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Выберите действие"</string>
- <string name="noApplications" msgid="1691104391758345586">"Это действие не может выполнять ни одно приложение."</string>
- <string name="aerr_title" msgid="653922989522758100">"Ошибка приложения!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Произошла неожиданная остановка приложения <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Произошла неожиданная остановка процесса <xliff:g id="PROCESS">%1$s</xliff:g>. Повторите попытку."</string>
- <string name="anr_title" msgid="3100070910664756057">"Извините!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Действие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Действие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_process" msgid="1246866008169975783">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string>
- <string name="force_close" msgid="3653416315450806396">"Принудительное закрытие"</string>
+ <string name="preposition_for_date">"в %s"</string>
+ <string name="preposition_for_time">"в %s"</string>
+ <string name="preposition_for_year">"через %s"</string>
+ <string name="day">"дн."</string>
+ <string name="days">"дн."</string>
+ <string name="hour">"ч."</string>
+ <string name="hours">"ч."</string>
+ <string name="minute">"мин."</string>
+ <string name="minutes">"мин."</string>
+ <string name="second">"с."</string>
+ <string name="seconds">"с."</string>
+ <string name="week">"нед."</string>
+ <string name="weeks">"нед."</string>
+ <string name="year">"г."</string>
+ <string name="years">"г."</string>
+ <string name="every_weekday">"Каждый рабочий день (пн-пт)"</string>
+ <string name="daily">"Ежедневно"</string>
+ <string name="weekly">"Еженедельно, <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Ежемесячно"</string>
+ <string name="yearly">"Ежегодно"</string>
+ <string name="VideoView_error_title">"Не удалось воспроизвести видео"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Это видео не подходит для потокового воспроизведения на данном устройстве."</string>
+ <string name="VideoView_error_text_unknown">"Невозможно воспроизвести видео."</string>
+ <string name="VideoView_error_button">"ОК"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"полдень"</string>
+ <string name="Noon">"Полдень"</string>
+ <string name="midnight">"полночь"</string>
+ <string name="Midnight">"Полночь"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Выбрать все"</string>
+ <string name="selectText">"Выбрать текст"</string>
+ <string name="stopSelectingText">"Остановить выделение текста"</string>
+ <string name="cut">"Вырезать"</string>
+ <string name="cutAll">"Вырезать все"</string>
+ <string name="copy">"Копировать"</string>
+ <string name="copyAll">"Копировать все"</string>
+ <string name="paste">"Вставить"</string>
+ <string name="copyUrl">"Копировать URL"</string>
+ <string name="inputMethod">"Способ ввода"</string>
+ <string name="addToDictionary">"Добавить \"%s\" в словарь"</string>
+ <string name="editTextMenuTitle">"Изменить текст"</string>
+ <string name="low_internal_storage_view_title">"Недостаточно места"</string>
+ <string name="low_internal_storage_view_text">"Заканчивается место в памяти телефона."</string>
+ <string name="ok">"ОК"</string>
+ <string name="cancel">"Отмена"</string>
+ <string name="yes">"ОК"</string>
+ <string name="no">"Отмена"</string>
+ <string name="dialog_alert_title">"Внимание"</string>
+ <string name="capital_on">"ВКЛ"</string>
+ <string name="capital_off">"ВЫКЛ"</string>
+ <string name="whichApplication">"Завершить действие с помощью"</string>
+ <string name="alwaysUse">"Использовать по умолчанию для этого действия."</string>
+ <string name="clearDefaultHintMsg">"Удалить настройки по умолчанию: главный экран > \"Настройки\" > \"Приложения\" > \"Управление приложениями\"."</string>
+ <string name="chooseActivity">"Выберите действие"</string>
+ <string name="noApplications">"Это действие не может выполнять ни одно приложение."</string>
+ <string name="aerr_title">"Ошибка приложения!"</string>
+ <string name="aerr_application">"Произошла неожиданная остановка приложения <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
+ <string name="aerr_process">"Произошла неожиданная остановка процесса <xliff:g id="PROCESS">%1$s</xliff:g>. Повторите попытку."</string>
+ <string name="anr_title">"Извините!"</string>
+ <string name="anr_activity_application">"Действие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_activity_process">"Действие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_application_process">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_process">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string>
+ <string name="force_close">"Принудительное закрытие"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Подождите"</string>
- <string name="debug" msgid="9103374629678531849">"Выполнить отладку"</string>
- <string name="sendText" msgid="5132506121645618310">"Выберите действие для текста"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Громкость звонка"</string>
- <string name="volume_music" msgid="5421651157138628171">"Громкость мультимедиа"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Воспроизведение по каналу Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Громкость входящего вызова"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Громкость входящего вызова Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Громкость сигнала предупреждения"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Громкость уведомления"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Громкость"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Мелодия по умолчанию"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Мелодия по умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Без звука"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестная мелодия"</string>
+ <string name="wait">"Подождите"</string>
+ <string name="debug">"Выполнить отладку"</string>
+ <string name="sendText">"Выберите действие для текста"</string>
+ <string name="volume_ringtone">"Громкость звонка"</string>
+ <string name="volume_music">"Громкость мультимедиа"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Воспроизведение по каналу Bluetooth"</string>
+ <string name="volume_call">"Громкость входящего вызова"</string>
+ <string name="volume_bluetooth_call">"Громкость входящего вызова Bluetooth"</string>
+ <string name="volume_alarm">"Громкость сигнала предупреждения"</string>
+ <string name="volume_notification">"Громкость уведомления"</string>
+ <string name="volume_unknown">"Громкость"</string>
+ <string name="ringtone_default">"Мелодия по умолчанию"</string>
+ <string name="ringtone_default_with_actual">"Мелодия по умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Без звука"</string>
+ <string name="ringtone_picker_title">"Мелодии"</string>
+ <string name="ringtone_unknown">"Неизвестная мелодия"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Доступна сеть Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"Доступна сеть Wi-Fi"</item>
+ <item quantity="one">"Доступна сеть Wi-Fi"</item>
+ <item quantity="other">"Доступна сеть Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Найдена доступная сеть Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Найдены доступные сети Wi-Fi"</item>
+ <item quantity="one">"Найдена доступная сеть Wi-Fi"</item>
+ <item quantity="other">"Найдены доступные сети Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Неизвестное приложение"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Отправляется большое количество SMS-сообщений. Нажмите \"ОК\" для продолжения или \"Отмена\" для прекращения отправки."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Отмена"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Установить"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"По умолчанию"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Скрыть"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Показать все"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Идет загрузка…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"устройство USB подключено"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Телефон подключен к компьютеру через порт USB. Если необходимо копировать файлы с компьютера на SD-карту телефона (или наоборот), выберите \"Установить\"."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Смонтировать"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Не монтировать"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"При использовании SD-карты как USB-накопителя возникла неполадка."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"устройство USB подключено"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберите копирование файлов на компьютер или с компьютера."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключить USB-накопитель"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберите, чтобы выключить USB-накопитель."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Выключить USB-накопитель"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Перед выключением USB-накопителя обязательно отключите USB-хост. Выберите \"Выключить\", чтобы выключить USB-накопитель."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Выключить"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Отмена"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"При выключении USB-накопителя произошла неполадка. Убедитесь, что USB-хост отключен, и повторите попытку."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Форматировать карту SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Отформатировать карту SD? Все данные, находящиеся на карте, будут уничтожены."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Формат"</string>
+ <string name="select_character">"Введите символ"</string>
+ <string name="sms_control_default_app_name">"Неизвестное приложение"</string>
+ <string name="sms_control_title">"Отправка SMS-сообщений"</string>
+ <string name="sms_control_message">"Отправляется большое количество SMS-сообщений. Нажмите \"ОК\" для продолжения или \"Отмена\" для прекращения отправки."</string>
+ <string name="sms_control_yes">"ОК"</string>
+ <string name="sms_control_no">"Отмена"</string>
+ <string name="date_time_set">"Установить"</string>
+ <string name="default_permission_group">"По умолчанию"</string>
+ <string name="no_permissions">"Не требуется разрешений"</string>
+ <string name="perms_hide"><b>"Скрыть"</b></string>
+ <string name="perms_show_all"><b>"Показать все"</b></string>
+ <string name="googlewebcontenthelper_loading">"Идет загрузка…"</string>
+ <string name="usb_storage_title">"устройство USB подключено"</string>
+ <string name="usb_storage_message">"Телефон подключен к компьютеру через порт USB. Если необходимо копировать файлы с компьютера на SD-карту телефона (или наоборот), выберите \"Установить\"."</string>
+ <string name="usb_storage_button_mount">"Смонтировать"</string>
+ <string name="usb_storage_button_unmount">"Не монтировать"</string>
+ <string name="usb_storage_error_message">"При использовании SD-карты как USB-накопителя возникла неполадка."</string>
+ <string name="usb_storage_notification_title">"устройство USB подключено"</string>
+ <string name="usb_storage_notification_message">"Выберите копирование файлов на компьютер или с компьютера."</string>
+ <string name="usb_storage_stop_notification_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_notification_message">"Выберите, чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_message">"Перед выключением USB-накопителя обязательно отключите USB-хост. Выберите \"Выключить\", чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_button_mount">"Выключить"</string>
+ <string name="usb_storage_stop_button_unmount">"Отмена"</string>
+ <string name="usb_storage_stop_error_message">"При выключении USB-накопителя произошла неполадка. Убедитесь, что USB-хост отключен, и повторите попытку."</string>
+ <string name="extmedia_format_title">"Форматировать карту SD"</string>
+ <string name="extmedia_format_message">"Отформатировать карту SD? Все данные, находящиеся на карте, будут уничтожены."</string>
+ <string name="extmedia_format_button_format">"Формат"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Выберите способ ввода"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Подготовка карты SD"</string>
+ <string name="select_input_method">"Выберите способ ввода"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"варианты"</u></string>
+ <string name="ext_media_checking_notification_title">"Подготовка карты SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Пустая карта SD"</string>
+ <string name="ext_media_nofs_notification_title">"Пустая карта SD"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Поврежденная карта SD"</string>
+ <string name="ext_media_unmountable_notification_title">"Поврежденная карта SD"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Карта SD неожиданно извлечена"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Безопасное удаление карты SD"</string>
+ <string name="ext_media_badremoval_notification_title">"Карта SD неожиданно извлечена"</string>
+ <string name="ext_media_badremoval_notification_message">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Безопасное удаление карты SD"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Отсутствует карта SD"</string>
+ <string name="ext_media_nomedia_notification_title">"Отсутствует карта SD"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Подходящих действий не найдено"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"обновлять статистику использования компонентов"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Позволяет изменять собранную статистику использования компонентов. Не предназначено для использования обычными приложениями."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Нажмите дважды для изменения масштаба"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Ошибка при наполнении виджета"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Выбрать"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Поиск"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Отправить"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Далее"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Выполнить"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Набрать номер"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Создать контакт"\n"с номером <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Подходящих действий не найдено"</string>
+ <string name="permlab_pkgUsageStats">"обновлять статистику использования компонентов"</string>
+ <string name="permdesc_pkgUsageStats">"Позволяет изменять собранную статистику использования компонентов. Не предназначено для использования обычными приложениями."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Нажмите дважды для изменения масштаба"</string>
+ <string name="gadget_host_error_inflating">"Ошибка при наполнении виджета"</string>
+ <string name="ime_action_go">"Выбрать"</string>
+ <string name="ime_action_search">"Поиск"</string>
+ <string name="ime_action_send">"Отправить"</string>
+ <string name="ime_action_next">"Далее"</string>
+ <string name="ime_action_done">"Готово"</string>
+ <string name="ime_action_default">"Выполнить"</string>
+ <string name="dial_number_using">"Набрать номер"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Создать контакт"\n"с номером <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 611bfaa..40d2500 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<utan titel>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Inget telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Okänd)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Röstbrevlåda"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Anslutningsproblem eller ogiltig MMI-kod."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjänsten har aktiverats."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjänsten har aktiverats för:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjänsten har inaktiverats."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen slutförd."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Radering lyckades."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Fel lösenord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI slutförd."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamla PIN-koden som du angav är fel."</string>
- <string name="badPuk" msgid="5702522162746042460">"PUK-koden som du angav är fel."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"PIN-koderna som du angav matchar inte."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Ange en PIN-kod som är 4 till 8 siffror."</string>
- <string name="needPuk" msgid="919668385956251611">"Ditt SIM-kort är PUK-låst. Ange PUK-koden om du vill låsa upp det."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Ange PUK2-koden för att häva spärren av SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Nummerpresentatör för inkommande samtal"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Nummerpresentatör för utgående samtal"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Vidarebefordra samtal"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Samtal väntar"</string>
- <string name="BaMmi" msgid="455193067926770581">"Samtalsspärr"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Byt lösenord"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Byt PIN-kod"</string>
+ <string name="untitled">"<utan titel>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Inget telefonnummer)"</string>
+ <string name="unknownName">"(Okänd)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Röstbrevlåda"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Anslutningsproblem eller ogiltig MMI-kod."</string>
+ <string name="serviceEnabled">"Tjänsten har aktiverats."</string>
+ <string name="serviceEnabledFor">"Tjänsten har aktiverats för:"</string>
+ <string name="serviceDisabled">"Tjänsten har inaktiverats."</string>
+ <string name="serviceRegistered">"Registreringen slutförd."</string>
+ <string name="serviceErased">"Radering lyckades."</string>
+ <string name="passwordIncorrect">"Fel lösenord."</string>
+ <string name="mmiComplete">"MMI slutförd."</string>
+ <string name="badPin">"Den gamla PIN-koden som du angav är fel."</string>
+ <string name="badPuk">"PUK-koden som du angav är fel."</string>
+ <string name="mismatchPin">"PIN-koderna som du angav matchar inte."</string>
+ <string name="invalidPin">"Ange en PIN-kod som är 4 till 8 siffror."</string>
+ <string name="needPuk">"Ditt SIM-kort är PUK-låst. Ange PUK-koden om du vill låsa upp det."</string>
+ <string name="needPuk2">"Ange PUK2-koden för att häva spärren av SIM-kortet."</string>
+ <string name="ClipMmi">"Nummerpresentatör för inkommande samtal"</string>
+ <string name="ClirMmi">"Nummerpresentatör för utgående samtal"</string>
+ <string name="CfMmi">"Vidarebefordra samtal"</string>
+ <string name="CwMmi">"Samtal väntar"</string>
+ <string name="BaMmi">"Samtalsspärr"</string>
+ <string name="PwdMmi">"Byt lösenord"</string>
+ <string name="PinMmi">"Byt PIN-kod"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummerpresentatören är begränsad som standard. Nästa samtal: Begränsad"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummerpresentatörens standardinställning är begränsad. Nästa samtal: Inte begränsad"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Begränsad"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjänsten är inte etablerad."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Det går inte att ändra inställningen för nummerpresentatör."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begränsad åtkomst har ändrats"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjänsten är blockerad."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Räddningstjänsten är blockerad."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Tjänsten röst/SMS är blockerad."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alla röst-/SMS-tjänster har blockerats."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Röst"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkront"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkronisera"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Nummerpresentatören är begränsad som standard. Nästa samtal: Begränsad"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Nummerpresentatörens standardinställning är begränsad. Nästa samtal: Inte begränsad"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Begränsad"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
+ <string name="serviceNotProvisioned">"Tjänsten är inte etablerad."</string>
+ <string name="CLIRPermanent">"Det går inte att ändra inställningen för nummerpresentatör."</string>
+ <string name="RestrictedChangedTitle">"Begränsad åtkomst har ändrats"</string>
+ <string name="RestrictedOnData">"Datatjänsten är blockerad."</string>
+ <string name="RestrictedOnEmergency">"Räddningstjänsten är blockerad."</string>
+ <string name="RestrictedOnNormal">"Tjänsten röst/SMS är blockerad."</string>
+ <string name="RestrictedOnAll">"Alla röst-/SMS-tjänster har blockerats."</string>
+ <string name="serviceClassVoice">"Röst"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkront"</string>
+ <string name="serviceClassDataSync">"Synkronisera"</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Vidarebefordras inte"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Vidarebefordras inte"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Webbsidan innehåller ett fel."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Webbadressen kunde inte hittas."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Webbplatsens autentiseringsmetod stöds inte."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Det gick inte att autentisera."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Det gick inte att autentisera via proxyservern."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Det gick inte att ansluta till servern."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Servern kommunicerade inte. Försök igen senare."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Anslutningen till servern har kopplats ifrån."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Sidan innehåller för många serveromdirigeringar."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollet stöds inte."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Det gick inte att upprätta en säker anslutning."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Sidan kunde inte öppnas eftersom webbadressen är ogiltig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Det gick inte att komma åt filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Den begärda filen hittades inte."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"För många begäranden bearbetas. Försök igen senare."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkronisera"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisera"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagringsutrymme är fullt! Radera några filer för att frigöra utrymme."</string>
- <string name="me" msgid="6545696007631404292">"Jag"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonalternativ"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tyst läge"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Aktivera trådlöst"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Inaktivera trådlöst"</string>
- <string name="screen_lock" msgid="799094655496098153">"Skärmlås"</string>
- <string name="power_off" msgid="4266614107412865048">"Stäng av"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Din telefon stängs av."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya program."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonalternativ"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tyst läge"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ljudet är AV"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ljudet är PÅ"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
- <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjänster som kostar pengar"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Tillåter att program gör saker som kostar pengar."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Dina meddelanden"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Läs och skriv SMS, e-post och andra meddelanden."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Dina personliga uppgifter"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direktåtkomst till dina kontakter och kalendern som har lagrats på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Din plats"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Övervaka din fysiska plats"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Nätverkskommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Tillåt att program kommer åt olika nätverksfunktioner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Dina Google-konton"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Få åtkomst till tillgängliga Google-konton."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Kontroller för maskinvara"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkt åtkomst till maskinvara på handenheten."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonsamtal"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Övervaka, spela in och bearbeta telefonsamtal"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemverktyg"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Åtkomst och kontroll av systemet på lägre nivå."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utvecklingsverktyg"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktioner som endast behövs för programutvecklare."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Webbsidan innehåller ett fel."</string>
+ <string name="httpErrorLookup">"Webbadressen kunde inte hittas."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Webbplatsens autentiseringsmetod stöds inte."</string>
+ <string name="httpErrorAuth">"Det gick inte att autentisera."</string>
+ <string name="httpErrorProxyAuth">"Det gick inte att autentisera via proxyservern."</string>
+ <string name="httpErrorConnect">"Det gick inte att ansluta till servern."</string>
+ <string name="httpErrorIO">"Servern kommunicerade inte. Försök igen senare."</string>
+ <string name="httpErrorTimeout">"Anslutningen till servern har kopplats ifrån."</string>
+ <string name="httpErrorRedirectLoop">"Sidan innehåller för många serveromdirigeringar."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollet stöds inte."</string>
+ <string name="httpErrorFailedSslHandshake">"Det gick inte att upprätta en säker anslutning."</string>
+ <string name="httpErrorBadUrl">"Sidan kunde inte öppnas eftersom webbadressen är ogiltig."</string>
+ <string name="httpErrorFile">"Det gick inte att komma åt filen."</string>
+ <string name="httpErrorFileNotFound">"Den begärda filen hittades inte."</string>
+ <string name="httpErrorTooManyRequests">"För många begäranden bearbetas. Försök igen senare."</string>
+ <string name="contentServiceSync">"Synkronisera"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkronisera"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
+ <string name="low_memory">"Telefonens lagringsutrymme är fullt! Radera några filer för att frigöra utrymme."</string>
+ <string name="me">"Jag"</string>
+ <string name="power_dialog">"Telefonalternativ"</string>
+ <string name="silent_mode">"Tyst läge"</string>
+ <string name="turn_on_radio">"Aktivera trådlöst"</string>
+ <string name="turn_off_radio">"Inaktivera trådlöst"</string>
+ <string name="screen_lock">"Skärmlås"</string>
+ <string name="power_off">"Stäng av"</string>
+ <string name="shutdown_progress">"Avslutar…"</string>
+ <string name="shutdown_confirm">"Din telefon stängs av."</string>
+ <string name="no_recent_tasks">"Inga nya program."</string>
+ <string name="global_actions">"Telefonalternativ"</string>
+ <string name="global_action_lock">"Skärmlås"</string>
+ <string name="global_action_power_off">"Stäng av"</string>
+ <string name="global_action_toggle_silent_mode">"Tyst läge"</string>
+ <string name="global_action_silent_mode_on_status">"Ljudet är AV"</string>
+ <string name="global_action_silent_mode_off_status">"Ljudet är PÅ"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flygplansläge"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flygplansläge är AKTIVERAT"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flygplansläge är INAKTIVERAT"</string>
+ <string name="safeMode">"Säkert läge"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Tjänster som kostar pengar"</string>
+ <string name="permgroupdesc_costMoney">"Tillåter att program gör saker som kostar pengar."</string>
+ <string name="permgrouplab_messages">"Dina meddelanden"</string>
+ <string name="permgroupdesc_messages">"Läs och skriv SMS, e-post och andra meddelanden."</string>
+ <string name="permgrouplab_personalInfo">"Dina personliga uppgifter"</string>
+ <string name="permgroupdesc_personalInfo">"Direktåtkomst till dina kontakter och kalendern som har lagrats på telefonen."</string>
+ <string name="permgrouplab_location">"Din plats"</string>
+ <string name="permgroupdesc_location">"Övervaka din fysiska plats"</string>
+ <string name="permgrouplab_network">"Nätverkskommunikation"</string>
+ <string name="permgroupdesc_network">"Tillåt att program kommer åt olika nätverksfunktioner."</string>
+ <string name="permgrouplab_accounts">"Dina Google-konton"</string>
+ <string name="permgroupdesc_accounts">"Få åtkomst till tillgängliga Google-konton."</string>
+ <string name="permgrouplab_hardwareControls">"Kontroller för maskinvara"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkt åtkomst till maskinvara på handenheten."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonsamtal"</string>
+ <string name="permgroupdesc_phoneCalls">"Övervaka, spela in och bearbeta telefonsamtal"</string>
+ <string name="permgrouplab_systemTools">"Systemverktyg"</string>
+ <string name="permgroupdesc_systemTools">"Åtkomst och kontroll av systemet på lägre nivå."</string>
+ <string name="permgrouplab_developmentTools">"Utvecklingsverktyg"</string>
+ <string name="permgroupdesc_developmentTools">"Funktioner som endast behövs för programutvecklare."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Tillåter att programmet inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandera/komprimera statusfält"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Tillåter att program expanderar eller komprimerar statusfältet."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"spärra utgående samtal"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Tillåter att program hanterar utgående samtal och ändrar numret som ska ringas upp. Skadliga program kan övervaka, omdirigera eller förhindra utgående samtal."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"ta emot SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Tillåter att program tar emot och bearbetar SMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"ta emot MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Tillåter att program tar emot och bearbetar MMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem innan du har sett dem."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"skicka SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Tillåter att programmet skickar SMS-meddelanden. Skadliga program kan skicka meddelanden utan ditt godkännande vilket kan kosta pengar."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"läsa SMS eller MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Tillåter att program läser SMS-meddelanden som sparats på din telefon eller SIM-kort. Skadliga program kan läsa dina konfidentiella meddelanden."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"redigera SMS eller MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Tillåter att program skriver till SMS-meddelanden som lagrats på din telefon eller SIM-kort. Skadliga program kan radera dina meddelanden."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"ta emot WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"hämta program som körs"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på program som körs"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av program"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillåter att ett program ändrar den aktuella konfigurationen, till exempel språk eller övergripande teckenformat."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"starta om andra program"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Tillåter att ett program framtvingar omstart av andra program."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga program att avsluta"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hämta systemets interna status"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
+ <string name="permlab_statusBar">"inaktivera eller ändra statusfält"</string>
+ <string name="permdesc_statusBar">"Tillåter att programmet inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
+ <string name="permlab_expandStatusBar">"expandera/komprimera statusfält"</string>
+ <string name="permdesc_expandStatusBar">"Tillåter att program expanderar eller komprimerar statusfältet."</string>
+ <string name="permlab_processOutgoingCalls">"spärra utgående samtal"</string>
+ <string name="permdesc_processOutgoingCalls">"Tillåter att program hanterar utgående samtal och ändrar numret som ska ringas upp. Skadliga program kan övervaka, omdirigera eller förhindra utgående samtal."</string>
+ <string name="permlab_receiveSms">"ta emot SMS"</string>
+ <string name="permdesc_receiveSms">"Tillåter att program tar emot och bearbetar SMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
+ <string name="permlab_receiveMms">"ta emot MMS"</string>
+ <string name="permdesc_receiveMms">"Tillåter att program tar emot och bearbetar MMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem innan du har sett dem."</string>
+ <string name="permlab_sendSms">"skicka SMS"</string>
+ <string name="permdesc_sendSms">"Tillåter att programmet skickar SMS-meddelanden. Skadliga program kan skicka meddelanden utan ditt godkännande vilket kan kosta pengar."</string>
+ <string name="permlab_readSms">"läsa SMS eller MMS"</string>
+ <string name="permdesc_readSms">"Tillåter att program läser SMS-meddelanden som sparats på din telefon eller SIM-kort. Skadliga program kan läsa dina konfidentiella meddelanden."</string>
+ <string name="permlab_writeSms">"redigera SMS eller MMS"</string>
+ <string name="permdesc_writeSms">"Tillåter att program skriver till SMS-meddelanden som lagrats på din telefon eller SIM-kort. Skadliga program kan radera dina meddelanden."</string>
+ <string name="permlab_receiveWapPush">"ta emot WAP"</string>
+ <string name="permdesc_receiveWapPush">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
+ <string name="permlab_getTasks">"hämta program som körs"</string>
+ <string name="permdesc_getTasks">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
+ <string name="permlab_reorderTasks">"byt ordning på program som körs"</string>
+ <string name="permdesc_reorderTasks">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
+ <string name="permlab_setDebugApp">"aktivera felsökning av program"</string>
+ <string name="permdesc_setDebugApp">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
+ <string name="permlab_changeConfiguration">"ändra dina gränssnittsinställningar"</string>
+ <string name="permdesc_changeConfiguration">"Tillåter att ett program ändrar den aktuella konfigurationen, till exempel språk eller övergripande teckenformat."</string>
+ <string name="permlab_restartPackages">"starta om andra program"</string>
+ <string name="permdesc_restartPackages">"Tillåter att ett program framtvingar omstart av andra program."</string>
+ <string name="permlab_forceBack">"tvinga program att avsluta"</string>
+ <string name="permdesc_forceBack">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
+ <string name="permlab_dump">"hämta systemets interna status"</string>
+ <string name="permdesc_dump">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla program som öppnas"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan bryta systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig telefonanvändning."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"skicka SMS-mottagen sändning"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Tillåter att ett program sänder ut en avisering när SMS tas emot. Skadliga program kan använda detta för att förfalska inkommande SMS-meddelanden."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"skicka WAP-PUSH-mottagen sändning"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Tillåter att ett program skickar ut en avisering när ett WAP PUSH-meddelande tas emot. Skadliga program kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begränsa antalet processer som körs"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Tillåter att ett program styr högsta antalet processer som körs. Behövs inte för vanliga program."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"gör så att alla bakgrundsprogram stängs"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Tillåter att ett program bestämmer om aktiviteter alltid är slutförda när de hamnar i bakgrunden. Ska inte behövas för vanliga program."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"ändra batteristatistik"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillåter att samlad batteristatistik ändras. Används inte av vanliga program."</string>
+ <string name="permlab_runSetActivityWatcher">"övervaka och styra alla program som öppnas"</string>
+ <string name="permdesc_runSetActivityWatcher">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan bryta systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig telefonanvändning."</string>
+ <string name="permlab_broadcastPackageRemoved">"skicka meddelande om borttaget paket"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
+ <string name="permlab_broadcastSmsReceived">"skicka SMS-mottagen sändning"</string>
+ <string name="permdesc_broadcastSmsReceived">"Tillåter att ett program sänder ut en avisering när SMS tas emot. Skadliga program kan använda detta för att förfalska inkommande SMS-meddelanden."</string>
+ <string name="permlab_broadcastWapPush">"skicka WAP-PUSH-mottagen sändning"</string>
+ <string name="permdesc_broadcastWapPush">"Tillåter att ett program skickar ut en avisering när ett WAP PUSH-meddelande tas emot. Skadliga program kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
+ <string name="permlab_setProcessLimit">"begränsa antalet processer som körs"</string>
+ <string name="permdesc_setProcessLimit">"Tillåter att ett program styr högsta antalet processer som körs. Behövs inte för vanliga program."</string>
+ <string name="permlab_setAlwaysFinish">"gör så att alla bakgrundsprogram stängs"</string>
+ <string name="permdesc_setAlwaysFinish">"Tillåter att ett program bestämmer om aktiviteter alltid är slutförda när de hamnar i bakgrunden. Ska inte behövas för vanliga program."</string>
+ <string name="permlab_batteryStats">"ändra batteristatistik"</string>
+ <string name="permdesc_batteryStats">"Tillåter att samlad batteristatistik ändras. Används inte av vanliga program."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visa otillåtna fönster"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillåter att fönster skapas och används av det interna systemgränssnittet. Används inte av vanliga program."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visa varningar på systemnivå"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Tillåter att ett program visar fönster med systemvarningar. Skadliga program kan överta hela telefonens skärm."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"ändra global animeringshastighet"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Tillåter att ett program när som helst ändrar den globala animeringshastigheten (snabbare eller långsammare)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"hantera programtoken"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Tillåter att program skapar och hanterar egna token och förbigår normala Z-beställningar. Behövs inte för vanliga program."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"trycka på knappar och styrknappar"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Tillåter att ett program levererar egna inmatningshändelser (knapptryckningar, osv.) till andra program. Skadliga program använder detta för att kapa telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrera vad du skriver och vilka åtgärder du vidtar"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Tillåter att program övervakar knapparna som du trycker på, till och med när du använder andra program (till exempel när du anger ett lösenord). Ska inte behövas för vanliga program."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binda till en metod för indata"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till program"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"se till att programmet alltid körs"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Tillåter att ett program gör vissa delar beständiga så att systemet inte kan använda det för andra program."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"ta bort program"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Tillåter att ett program tar bort Android-paket. Skadliga program kan använda detta för att ta bort viktiga program."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"ta bort de andra programmens uppgifter"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Tillåter att ett program tar bort användardata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"ta bort de andra programmens cacheminnen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillåter att ett program raderar cachefiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"mäta telefonens lagringsutrymme"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installera program direkt"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"ta bort cacheinformation för alla program"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"läsa systemets loggfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga telefonfunktioner. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller ostabila."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade program"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"ändra globala systeminställningar"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"ändra skyddade systeminställningar"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Tillåter att ett program ändrar systemets data för skyddade inställningar. Används inte av vanliga program."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"ändra kartan för Googles tjänster"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Tillåter att ett program ändrar kartan för Google-tjänster. Används inte av vanliga program."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"starta automatiskt vid systemstart"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Tillåter att ett program startar när systemet har startats om. Detta kan innebära att det tar längre tid att starta om telefonen och att telefonen blir långsammare i och med att programmet hela tiden körs i bakgrunden."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"Skicka sticky broadcast"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Tillåter att ett program skickar sticky broadcasts, som finns kvar när sändningen är slut. Skadliga program kan göra telefonen seg eller instabil genom att se till att den använder för mycket minne."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"läsa kontaktinformation"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Tillåter att ett program läser alla kontaktuppgifter (adresser) som har lagrats på din telefon. Skadliga program kan använda detta för att skicka dina data till andra personer."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skriva kontaktuppgifter"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Tillåter att ett program ändrar kontaktuppgifter (adress) som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kontaktuppgifter."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skriva ägarinformation"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Tillåter att ett program ändrar information om telefonens ägare som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra ägaruppgifter."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"läsa information om ägare"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Tillåter att ett program läser information om telefonens ägare som har lagrats på telefonen. Skadliga program kan använda detta för att läsa telefonens ägaruppgifter."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"läsa kalenderinformation"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Tillåter att ett program läser alla händelser i kalendern som har lagrats på din telefon. Skadliga program kan använda detta för att skicka din kalender till andra personer."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skriva kalenderdata"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Tillåter att ett program ändrar kalenderuppgifterna som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kalenderuppgifter."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"skenplatser för att testa"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Skapa skenplatser för att testa. Skadliga program kan använda detta för att åsidosätta platsen och/eller statusen som returneras av riktiga platser, till exempel GPS- eller nätverksleverantörer."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få åtkomst till extra kommandon för platsleverantör"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Få åtkomst till extra kommandon för platsleverantörer. Skadliga program kan använda detta för att störa hur GPS eller andra platskällor fungerar."</string>
+ <string name="permlab_internalSystemWindow">"visa otillåtna fönster"</string>
+ <string name="permdesc_internalSystemWindow">"Tillåter att fönster skapas och används av det interna systemgränssnittet. Används inte av vanliga program."</string>
+ <string name="permlab_systemAlertWindow">"visa varningar på systemnivå"</string>
+ <string name="permdesc_systemAlertWindow">"Tillåter att ett program visar fönster med systemvarningar. Skadliga program kan överta hela telefonens skärm."</string>
+ <string name="permlab_setAnimationScale">"ändra global animeringshastighet"</string>
+ <string name="permdesc_setAnimationScale">"Tillåter att ett program när som helst ändrar den globala animeringshastigheten (snabbare eller långsammare)."</string>
+ <string name="permlab_manageAppTokens">"hantera programtoken"</string>
+ <string name="permdesc_manageAppTokens">"Tillåter att program skapar och hanterar egna token och förbigår normala Z-beställningar. Behövs inte för vanliga program."</string>
+ <string name="permlab_injectEvents">"trycka på knappar och styrknappar"</string>
+ <string name="permdesc_injectEvents">"Tillåter att ett program levererar egna inmatningshändelser (knapptryckningar, osv.) till andra program. Skadliga program använder detta för att kapa telefonen."</string>
+ <string name="permlab_readInputState">"registrera vad du skriver och vilka åtgärder du vidtar"</string>
+ <string name="permdesc_readInputState">"Tillåter att program övervakar knapparna som du trycker på, till och med när du använder andra program (till exempel när du anger ett lösenord). Ska inte behövas för vanliga program."</string>
+ <string name="permlab_bindInputMethod">"binda till en metod för indata"</string>
+ <string name="permdesc_bindInputMethod">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
+ <string name="permlab_setOrientation">"ändra bildskärmens rikting"</string>
+ <string name="permdesc_setOrientation">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
+ <string name="permlab_signalPersistentProcesses">"skicka Linux-signaler till program"</string>
+ <string name="permdesc_signalPersistentProcesses">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
+ <string name="permlab_persistentActivity">"se till att programmet alltid körs"</string>
+ <string name="permdesc_persistentActivity">"Tillåter att ett program gör vissa delar beständiga så att systemet inte kan använda det för andra program."</string>
+ <string name="permlab_deletePackages">"ta bort program"</string>
+ <string name="permdesc_deletePackages">"Tillåter att ett program tar bort Android-paket. Skadliga program kan använda detta för att ta bort viktiga program."</string>
+ <string name="permlab_clearAppUserData">"ta bort de andra programmens uppgifter"</string>
+ <string name="permdesc_clearAppUserData">"Tillåter att ett program tar bort användardata."</string>
+ <string name="permlab_deleteCacheFiles">"ta bort de andra programmens cacheminnen"</string>
+ <string name="permdesc_deleteCacheFiles">"Tillåter att ett program raderar cachefiler."</string>
+ <string name="permlab_getPackageSize">"mäta telefonens lagringsutrymme"</string>
+ <string name="permdesc_getPackageSize">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
+ <string name="permlab_installPackages">"installera program direkt"</string>
+ <string name="permdesc_installPackages">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
+ <string name="permlab_clearAppCache">"ta bort cacheinformation för alla program"</string>
+ <string name="permdesc_clearAppCache">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
+ <string name="permlab_readLogs">"läsa systemets loggfiler"</string>
+ <string name="permdesc_readLogs">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string>
+ <string name="permlab_diagnostic">"läsa/skriva till resurser som ägs av diag"</string>
+ <string name="permdesc_diagnostic">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
+ <string name="permlab_changeComponentState">"aktivera eller inaktivera programkomponenter"</string>
+ <string name="permdesc_changeComponentState">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga telefonfunktioner. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller ostabila."</string>
+ <string name="permlab_setPreferredApplications">"ange önskade program"</string>
+ <string name="permdesc_setPreferredApplications">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
+ <string name="permlab_writeSettings">"ändra globala systeminställningar"</string>
+ <string name="permdesc_writeSettings">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
+ <string name="permlab_writeSecureSettings">"ändra skyddade systeminställningar"</string>
+ <string name="permdesc_writeSecureSettings">"Tillåter att ett program ändrar systemets data för skyddade inställningar. Används inte av vanliga program."</string>
+ <string name="permlab_writeGservices">"ändra kartan för Googles tjänster"</string>
+ <string name="permdesc_writeGservices">"Tillåter att ett program ändrar kartan för Google-tjänster. Används inte av vanliga program."</string>
+ <string name="permlab_receiveBootCompleted">"starta automatiskt vid systemstart"</string>
+ <string name="permdesc_receiveBootCompleted">"Tillåter att ett program startar när systemet har startats om. Detta kan innebära att det tar längre tid att starta om telefonen och att telefonen blir långsammare i och med att programmet hela tiden körs i bakgrunden."</string>
+ <string name="permlab_broadcastSticky">"Skicka sticky broadcast"</string>
+ <string name="permdesc_broadcastSticky">"Tillåter att ett program skickar sticky broadcasts, som finns kvar när sändningen är slut. Skadliga program kan göra telefonen seg eller instabil genom att se till att den använder för mycket minne."</string>
+ <string name="permlab_readContacts">"läsa kontaktinformation"</string>
+ <string name="permdesc_readContacts">"Tillåter att ett program läser alla kontaktuppgifter (adresser) som har lagrats på din telefon. Skadliga program kan använda detta för att skicka dina data till andra personer."</string>
+ <string name="permlab_writeContacts">"skriva kontaktuppgifter"</string>
+ <string name="permdesc_writeContacts">"Tillåter att ett program ändrar kontaktuppgifter (adress) som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kontaktuppgifter."</string>
+ <string name="permlab_writeOwnerData">"skriva ägarinformation"</string>
+ <string name="permdesc_writeOwnerData">"Tillåter att ett program ändrar information om telefonens ägare som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra ägaruppgifter."</string>
+ <string name="permlab_readOwnerData">"läsa information om ägare"</string>
+ <string name="permdesc_readOwnerData">"Tillåter att ett program läser information om telefonens ägare som har lagrats på telefonen. Skadliga program kan använda detta för att läsa telefonens ägaruppgifter."</string>
+ <string name="permlab_readCalendar">"läsa kalenderinformation"</string>
+ <string name="permdesc_readCalendar">"Tillåter att ett program läser alla händelser i kalendern som har lagrats på din telefon. Skadliga program kan använda detta för att skicka din kalender till andra personer."</string>
+ <string name="permlab_writeCalendar">"skriva kalenderdata"</string>
+ <string name="permdesc_writeCalendar">"Tillåter att ett program ändrar kalenderuppgifterna som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kalenderuppgifter."</string>
+ <string name="permlab_accessMockLocation">"skenplatser för att testa"</string>
+ <string name="permdesc_accessMockLocation">"Skapa skenplatser för att testa. Skadliga program kan använda detta för att åsidosätta platsen och/eller statusen som returneras av riktiga platser, till exempel GPS- eller nätverksleverantörer."</string>
+ <string name="permlab_accessLocationExtraCommands">"få åtkomst till extra kommandon för platsleverantör"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få åtkomst till extra kommandon för platsleverantörer. Skadliga program kan använda detta för att störa hur GPS eller andra platskällor fungerar."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"hitta plats (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få åtkomst till detaljerade platskällor som Global Positioning System på telefonen, om det är tillgängligt. Skadliga program kan använda detta för att identifiera var du befinner dig, vilket drar mycket batteri."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (nätverksbaserad) plats"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få åtkomst till grova platser, till exempel mobilnätverkets databas, för att bestämma ungefärlig plats för en telefon. Skadliga program kan använda detta för att avgöra ungefär var du befinner dig."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få åtkomst till SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Tillåter att program använder lågnivåfunktioner i SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"läsa rambuffert"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Tillåter att program använder innehållet i rambufferten."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ändra dina ljudinställningar"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Tillåter att ett program ändrar globala ljudinställningar, till exempel volym och routning."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"spela in ljud"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Tillåter att program får åtkomst till sökvägen för ljudinspelning."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"ta bilder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Tillåter att program tar kort med kameran. Då kan programmet när som helst samla bilderna som visas i kameran."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"inaktivera telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Tillåter att programmet inaktiverar hela telefonen permanent. Detta är mycket farligt."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tvinga omstart av telefon"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Tillåter att ett program tvingar telefonen att starta om."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montering och demontering av filsystem"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Tillåter att programmet monterar och demonterar filsystem för flyttbara lagringsmedia."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatera extern lagring"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Tillåter att programmet formaterar flyttbara lagringsmedia."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrollera vibration"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Tillåter att programmet styr vibratorn."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillåter att programmet styr lampan."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testa maskinvara"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillåter att ett program styr kringutrustning i syfte att testa maskinvara."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Tillåter att programmet ringer telefonnummer utan åtgärd från dig. Skadliga program kan orsaka oväntade samtal på din telefonräkning. Observera att programmet inte tillåts att ringa nödsamtal."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ringa telefonnummer direkt"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Tillåter att programmet ringer ett telefonnummer, inklusive nödnummer, utan att du behöver göra något. Skadliga program kan ringa onödiga och olagliga samtal till räddningtjänsten."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"styra meddelanden för platsuppdatering"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Tillåter aktivering och inaktivering av avisering om platsuppdatering i radion. Används inte av vanliga program."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"få åtkomst till incheckningsegenskaper"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Tillåter läs/skrivåtkomst till egenskaper som läggs upp via incheckningstjänsten. Används inte av vanliga program."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"välja widgetar"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Tillåter att programmet instruerar systemet vilka widgetar som kan användas av vilket program. Med den här behörigheten kan åtkomst till personliga data beviljas andra program. Används inte av vanliga program."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"ändra telefonstatus"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Tillåter att programmet styr enhetens telefonfunktioner. Ett program med denna behörighet kan växla nätverk, aktivera och inaktivera telefonens radio och så vidare utan att ens meddela dig."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Tillåter att ett program förhindrar att telefonen går in i viloläge."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"sätta på eller stänga av telefonen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Tillåter att ett program sätter på eller stänger av telefonen."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kör i fabrikstestläge"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Köra som ett testläge för tillverkaren på låg nivå. På så sätt får du fullständig åtkomst till telefonens maskinvara. Är endast tillgänglig när telefonen körs i tillverkarens testläge."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"ange bakgrund"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Tillåter att programmet anger systemets bakgrund."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"ange tips för bakgrundsstorlek"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Tillåter att programmet ger tips om systemets bakgrundsstorlek."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"återställa systemets fabriksinställningar"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Tillåter att ett program helt återställer systemets fabriksinställningar. Alla data, inställningar och installerade program raderas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"ange tidszon"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Tillåter att ett program ändrar telefonens tidszon."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"upptäcka kända konton"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Tillåter att ett program hämtar en lista över konton som telefonen känner till."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"visa nätverksstatus"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Tillåter att ett program ser status för alla nätverk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"fullständig Internetåtkomst"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Tillåter att ett program skapar nätverksuttag."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skriva inställningar för åtkomstpunktens namn"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Tillåter att ett program ändrar APN-inställningarna, till exempel Proxy och Port för alla APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ändra nätverksanslutning"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Tillåter att ett program ändrar statusens nätverksanslutning."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"ändra inställningar för användning av bakgrundsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Tillåter att ett program ändrar inställningen för användning av bakgrundsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visa Wi-Fi-status"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Tillåter att ett program visar information om statusen för Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"byta Wi-Fi-status"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillåter att ett program ansluter till och kopplar från Wi-Fi-åtkomstpunkter och gör ändringar i konfigurerade Wi-Fi-nätverk."</string>
+ <string name="permlab_accessFineLocation">"hitta plats (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Få åtkomst till detaljerade platskällor som Global Positioning System på telefonen, om det är tillgängligt. Skadliga program kan använda detta för att identifiera var du befinner dig, vilket drar mycket batteri."</string>
+ <string name="permlab_accessCoarseLocation">"grov (nätverksbaserad) plats"</string>
+ <string name="permdesc_accessCoarseLocation">"Få åtkomst till grova platser, till exempel mobilnätverkets databas, för att bestämma ungefärlig plats för en telefon. Skadliga program kan använda detta för att avgöra ungefär var du befinner dig."</string>
+ <string name="permlab_accessSurfaceFlinger">"få åtkomst till SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Tillåter att program använder lågnivåfunktioner i SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"läsa rambuffert"</string>
+ <string name="permdesc_readFrameBuffer">"Tillåter att program använder innehållet i rambufferten."</string>
+ <string name="permlab_modifyAudioSettings">"ändra dina ljudinställningar"</string>
+ <string name="permdesc_modifyAudioSettings">"Tillåter att ett program ändrar globala ljudinställningar, till exempel volym och routning."</string>
+ <string name="permlab_recordAudio">"spela in ljud"</string>
+ <string name="permdesc_recordAudio">"Tillåter att program får åtkomst till sökvägen för ljudinspelning."</string>
+ <string name="permlab_camera">"ta bilder"</string>
+ <string name="permdesc_camera">"Tillåter att program tar kort med kameran. Då kan programmet när som helst samla bilderna som visas i kameran."</string>
+ <string name="permlab_brick">"inaktivera telefonen permanent"</string>
+ <string name="permdesc_brick">"Tillåter att programmet inaktiverar hela telefonen permanent. Detta är mycket farligt."</string>
+ <string name="permlab_reboot">"tvinga omstart av telefon"</string>
+ <string name="permdesc_reboot">"Tillåter att ett program tvingar telefonen att starta om."</string>
+ <string name="permlab_mount_unmount_filesystems">"montering och demontering av filsystem"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Tillåter att programmet monterar och demonterar filsystem för flyttbara lagringsmedia."</string>
+ <string name="permlab_mount_format_filesystems">"formatera extern lagring"</string>
+ <string name="permdesc_mount_format_filesystems">"Tillåter att programmet formaterar flyttbara lagringsmedia."</string>
+ <string name="permlab_vibrate">"kontrollera vibration"</string>
+ <string name="permdesc_vibrate">"Tillåter att programmet styr vibratorn."</string>
+ <string name="permlab_flashlight">"styra lampa"</string>
+ <string name="permdesc_flashlight">"Tillåter att programmet styr lampan."</string>
+ <string name="permlab_hardware_test">"testa maskinvara"</string>
+ <string name="permdesc_hardware_test">"Tillåter att ett program styr kringutrustning i syfte att testa maskinvara."</string>
+ <string name="permlab_callPhone">"ringa telefonnummer direkt"</string>
+ <string name="permdesc_callPhone">"Tillåter att programmet ringer telefonnummer utan åtgärd från dig. Skadliga program kan orsaka oväntade samtal på din telefonräkning. Observera att programmet inte tillåts att ringa nödsamtal."</string>
+ <string name="permlab_callPrivileged">"ringa telefonnummer direkt"</string>
+ <string name="permdesc_callPrivileged">"Tillåter att programmet ringer ett telefonnummer, inklusive nödnummer, utan att du behöver göra något. Skadliga program kan ringa onödiga och olagliga samtal till räddningtjänsten."</string>
+ <string name="permlab_locationUpdates">"styra meddelanden för platsuppdatering"</string>
+ <string name="permdesc_locationUpdates">"Tillåter aktivering och inaktivering av avisering om platsuppdatering i radion. Används inte av vanliga program."</string>
+ <string name="permlab_checkinProperties">"få åtkomst till incheckningsegenskaper"</string>
+ <string name="permdesc_checkinProperties">"Tillåter läs/skrivåtkomst till egenskaper som läggs upp via incheckningstjänsten. Används inte av vanliga program."</string>
+ <string name="permlab_bindGadget">"välja widgetar"</string>
+ <string name="permdesc_bindGadget">"Tillåter att programmet instruerar systemet vilka widgetar som kan användas av vilket program. Med den här behörigheten kan åtkomst till personliga data beviljas andra program. Används inte av vanliga program."</string>
+ <string name="permlab_modifyPhoneState">"ändra telefonstatus"</string>
+ <string name="permdesc_modifyPhoneState">"Tillåter att programmet styr enhetens telefonfunktioner. Ett program med denna behörighet kan växla nätverk, aktivera och inaktivera telefonens radio och så vidare utan att ens meddela dig."</string>
+ <string name="permlab_readPhoneState">"läsa telefonstatus"</string>
+ <string name="permdesc_readPhoneState">"Tillåter att programmet kommer åt enhetens telefonfunktioner. Ett program som har den här behörigheten kan identifiera telefonens telefonnummer, om ett samtal pågår, numret som samtalet är kopplat till och så vidare."</string>
+ <string name="permlab_wakeLock">"förhindra att telefonen sätts i viloläge"</string>
+ <string name="permdesc_wakeLock">"Tillåter att ett program förhindrar att telefonen går in i viloläge."</string>
+ <string name="permlab_devicePower">"sätta på eller stänga av telefonen"</string>
+ <string name="permdesc_devicePower">"Tillåter att ett program sätter på eller stänger av telefonen."</string>
+ <string name="permlab_factoryTest">"kör i fabrikstestläge"</string>
+ <string name="permdesc_factoryTest">"Köra som ett testläge för tillverkaren på låg nivå. På så sätt får du fullständig åtkomst till telefonens maskinvara. Är endast tillgänglig när telefonen körs i tillverkarens testläge."</string>
+ <string name="permlab_setWallpaper">"ange bakgrund"</string>
+ <string name="permdesc_setWallpaper">"Tillåter att programmet anger systemets bakgrund."</string>
+ <string name="permlab_setWallpaperHints">"ange tips för bakgrundsstorlek"</string>
+ <string name="permdesc_setWallpaperHints">"Tillåter att programmet ger tips om systemets bakgrundsstorlek."</string>
+ <string name="permlab_masterClear">"återställa systemets fabriksinställningar"</string>
+ <string name="permdesc_masterClear">"Tillåter att ett program helt återställer systemets fabriksinställningar. Alla data, inställningar och installerade program raderas."</string>
+ <string name="permlab_setTimeZone">"ange tidszon"</string>
+ <string name="permdesc_setTimeZone">"Tillåter att ett program ändrar telefonens tidszon."</string>
+ <string name="permlab_getAccounts">"upptäcka kända konton"</string>
+ <string name="permdesc_getAccounts">"Tillåter att ett program hämtar en lista över konton som telefonen känner till."</string>
+ <string name="permlab_accessNetworkState">"visa nätverksstatus"</string>
+ <string name="permdesc_accessNetworkState">"Tillåter att ett program ser status för alla nätverk."</string>
+ <string name="permlab_createNetworkSockets">"fullständig Internetåtkomst"</string>
+ <string name="permdesc_createNetworkSockets">"Tillåter att ett program skapar nätverksuttag."</string>
+ <string name="permlab_writeApnSettings">"skriva inställningar för åtkomstpunktens namn"</string>
+ <string name="permdesc_writeApnSettings">"Tillåter att ett program ändrar APN-inställningarna, till exempel Proxy och Port för alla APN."</string>
+ <string name="permlab_changeNetworkState">"ändra nätverksanslutning"</string>
+ <string name="permdesc_changeNetworkState">"Tillåter att ett program ändrar statusens nätverksanslutning."</string>
+ <string name="permlab_changeBackgroundDataSetting">"ändra inställningar för användning av bakgrundsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Tillåter att ett program ändrar inställningen för användning av bakgrundsdata."</string>
+ <string name="permlab_accessWifiState">"visa Wi-Fi-status"</string>
+ <string name="permdesc_accessWifiState">"Tillåter att ett program visar information om statusen för Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"byta Wi-Fi-status"</string>
+ <string name="permdesc_changeWifiState">"Tillåter att ett program ansluter till och kopplar från Wi-Fi-åtkomstpunkter och gör ändringar i konfigurerade Wi-Fi-nätverk."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrera bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillåter att ett program konfigurerar den lokala Bluetooth-telefonen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"skapa Bluetooth-anslutningar"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Tillåter att ett program ser den lokala Bluetooth-telefonens konfiguration, och skapar och accepterar anslutningar med parkopplade enheter."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"inaktivera tangentlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillåter att ett program inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel på detta är att telefonen inaktiverar tangentlåset vid inkommande samtal och sedan aktiverar det igen när samtalet är avslutat."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"läsa synkroniseringsinställningar"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Tillåter att ett program läser synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skriva synkroniseringsinställningar"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Tillåter att ett program ändrar synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"läsa synkroniseringsstatistik"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Tillåter att ett program läser synkroniseringsstatistiken, t.ex. historiken över synkroniseringar som har inträffat."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"läsa flöden som du prenumererar på"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Tillåter att ett program får information om aktuella synkroniserade flöden."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skriva flöden som du prenumererar på"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Tillåter att ett program ändrar dina aktuella synkroniserade flöden. Det kan innebära att ett skadligt program kan ändra dina synkroniserade flöden."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"läsa användardefinierad ordlista"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Tillåt att ett program läser alla privata ord, namn och fraser som användaren lagrar i sin ordlista."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skriva till användardefinierad ordlista"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Tillåter att ett program skriver in nya ord i användarordlistan."</string>
+ <string name="permlab_bluetoothAdmin">"administrera bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Tillåter att ett program konfigurerar den lokala Bluetooth-telefonen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
+ <string name="permlab_bluetooth">"skapa Bluetooth-anslutningar"</string>
+ <string name="permdesc_bluetooth">"Tillåter att ett program ser den lokala Bluetooth-telefonens konfiguration, och skapar och accepterar anslutningar med parkopplade enheter."</string>
+ <string name="permlab_disableKeyguard">"inaktivera tangentlås"</string>
+ <string name="permdesc_disableKeyguard">"Tillåter att ett program inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel på detta är att telefonen inaktiverar tangentlåset vid inkommande samtal och sedan aktiverar det igen när samtalet är avslutat."</string>
+ <string name="permlab_readSyncSettings">"läsa synkroniseringsinställningar"</string>
+ <string name="permdesc_readSyncSettings">"Tillåter att ett program läser synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
+ <string name="permlab_writeSyncSettings">"skriva synkroniseringsinställningar"</string>
+ <string name="permdesc_writeSyncSettings">"Tillåter att ett program ändrar synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
+ <string name="permlab_readSyncStats">"läsa synkroniseringsstatistik"</string>
+ <string name="permdesc_readSyncStats">"Tillåter att ett program läser synkroniseringsstatistiken, t.ex. historiken över synkroniseringar som har inträffat."</string>
+ <string name="permlab_subscribedFeedsRead">"läsa flöden som du prenumererar på"</string>
+ <string name="permdesc_subscribedFeedsRead">"Tillåter att ett program får information om aktuella synkroniserade flöden."</string>
+ <string name="permlab_subscribedFeedsWrite">"skriva flöden som du prenumererar på"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Tillåter att ett program ändrar dina aktuella synkroniserade flöden. Det kan innebära att ett skadligt program kan ändra dina synkroniserade flöden."</string>
+ <string name="permlab_readDictionary">"läsa användardefinierad ordlista"</string>
+ <string name="permdesc_readDictionary">"Tillåt att ett program läser alla privata ord, namn och fraser som användaren lagrar i sin ordlista."</string>
+ <string name="permlab_writeDictionary">"skriva till användardefinierad ordlista"</string>
+ <string name="permdesc_writeDictionary">"Tillåter att ett program skriver in nya ord i användarordlistan."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Hem"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbete"</item>
- <item msgid="1103601433382158155">"Fax, arbete"</item>
- <item msgid="1735177144948329370">"Hemfax"</item>
- <item msgid="603878674477207394">"Personsökare"</item>
- <item msgid="1650824275177931637">"Övrigt"</item>
- <item msgid="9192514806975898961">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Mobil"</item>
+ <item>"Arbete"</item>
+ <item>"Fax, arbete"</item>
+ <item>"Hemfax"</item>
+ <item>"Personsökare"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Hem"</item>
- <item msgid="7084237356602625604">"Arbete"</item>
- <item msgid="1112044410659011023">"Övrigt"</item>
- <item msgid="2374913952870110618">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Hem"</item>
- <item msgid="5629153956045109251">"Arbete"</item>
- <item msgid="4966604264500343469">"Övrigt"</item>
- <item msgid="4932682847595299369">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Hem"</item>
- <item msgid="1359644565647383708">"Arbete"</item>
- <item msgid="7868549401053615677">"Övrigt"</item>
- <item msgid="3145118944639869809">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbete"</item>
- <item msgid="4378074129049520373">"Övrigt"</item>
- <item msgid="3455047468583965104">"Anpassad"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ange PIN-kod"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Fel PIN-kod!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Tryck på Meny och sedan på 0 om du vill låsa upp."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nödsamtalsnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen tjänst)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Meny om du vill låsa upp eller ringa nödsamtal."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Meny om du vill låsa upp."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rita grafiskt lösenord för att låsa upp"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nödsamtal"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Korrekt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Försök igen"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Laddar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Ange PIN-kod"</string>
+ <string name="keyguard_password_wrong_pin_code">"Fel PIN-kod!"</string>
+ <string name="keyguard_label_text">"Tryck på Meny och sedan på 0 om du vill låsa upp."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nödsamtalsnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen tjänst)"</string>
+ <string name="lockscreen_screen_locked">"Skärmen har låsts."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Tryck på Meny om du vill låsa upp eller ringa nödsamtal."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Tryck på Meny om du vill låsa upp."</string>
+ <string name="lockscreen_pattern_instructions">"Rita grafiskt lösenord för att låsa upp"</string>
+ <string name="lockscreen_emergency_call">"Nödsamtal"</string>
+ <string name="lockscreen_pattern_correct">"Korrekt!"</string>
+ <string name="lockscreen_pattern_wrong">"Försök igen"</string>
+ <string name="lockscreen_plugged_in">"Laddar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Anslut din laddare."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Inget SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Inget SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Sätt i ett SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Nätverk låst"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kortet är PUK-låst."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se användarhandboken eller kontakta Kundtjänst."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet är låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser upp SIM-kort…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glömt ditt grafiska lösenord?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"För många försök med grafiskt lösenord!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Logga in med ditt Google-konto om du vill låsa upp"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Användarnamn (e-post)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Lösenord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logga in"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ogiltigt användarnamn eller lösenord."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Anslut din laddare."</string>
+ <string name="lockscreen_missing_sim_message_short">"Inget SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Inget SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Sätt i ett SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Nätverk låst"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kortet är PUK-låst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se användarhandboken eller kontakta Kundtjänst."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet är låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser upp SIM-kort…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Glömt ditt grafiska lösenord?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"För många försök med grafiskt lösenord!"</string>
+ <string name="lockscreen_glogin_instructions">"Logga in med ditt Google-konto om du vill låsa upp"</string>
+ <string name="lockscreen_glogin_username_hint">"Användarnamn (e-post)"</string>
+ <string name="lockscreen_glogin_password_hint">"Lösenord"</string>
+ <string name="lockscreen_glogin_submit_button">"Logga in"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ogiltigt användarnamn eller lösenord."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Laddar…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Anslut laddaren"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet håller på att ta slut:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Mindre än <xliff:g id="NUMBER">%d%%</xliff:g> återstår."</string>
+ <string name="status_bar_no_notifications_title">"Inga aviseringar"</string>
+ <string name="status_bar_ongoing_events_title">"Pågående"</string>
+ <string name="status_bar_latest_events_title">"Meddelanden"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Laddar…"</string>
+ <string name="battery_low_title">"Anslut laddaren"</string>
+ <string name="battery_low_subtitle">"Batteriet håller på att ta slut:"</string>
+ <string name="battery_low_percent_format">"Mindre än <xliff:g id="NUMBER">%d%%</xliff:g> återstår."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Det gick fel vid fabrikstestet"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Åtgärden FACTORY_TEST stöds endast för paket som har installerats i /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Vi hittade inget paket som erbjuder åtgärden FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Starta om"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
+ <string name="factorytest_failed">"Det gick fel vid fabrikstestet"</string>
+ <string name="factorytest_not_system">"Åtgärden FACTORY_TEST stöds endast för paket som har installerats i /system/app."</string>
+ <string name="factorytest_no_action">"Vi hittade inget paket som erbjuder åtgärden FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Starta om"</string>
+ <string name="js_dialog_title">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
+ <string name="save_password_label">"Bekräfta"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldrig"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har inte behörighet att öppna den här sidan."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text har kopierats till urklipp."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Meny+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"utrymme"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"retur"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ta bort"</string>
- <string name="search_go" msgid="8298016669822141719">"Sök"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
+ <string name="save_password_message">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
+ <string name="save_password_notnow">"Inte nu"</string>
+ <string name="save_password_remember">"Kom ihåg"</string>
+ <string name="save_password_never">"Aldrig"</string>
+ <string name="open_permission_deny">"Du har inte behörighet att öppna den här sidan."</string>
+ <string name="text_copied">"Text har kopierats till urklipp."</string>
+ <string name="more_item_label">"Mer"</string>
+ <string name="prepend_shortcut_label">"Meny+"</string>
+ <string name="menu_space_shortcut_label">"utrymme"</string>
+ <string name="menu_enter_shortcut_label">"retur"</string>
+ <string name="menu_delete_shortcut_label">"ta bort"</string>
+ <string name="search_go">"Sök"</string>
+ <string name="oneMonthDurationPast">"för 1 månad sedan"</string>
+ <string name="beforeOneMonthDurationPast">"För mer än en månad sedan"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"för 1 sekund sedan"</item>
- <item quantity="other" msgid="3903706804349556379">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
+ <item quantity="one">"för 1 sekund sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"för 1 minut sedan"</item>
- <item quantity="other" msgid="2176942008915455116">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
+ <item quantity="one">"för 1 minut sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"för 1 timme sedan"</item>
- <item quantity="other" msgid="2467273239587587569">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
+ <item quantity="one">"för 1 timme sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"igår"</item>
- <item quantity="other" msgid="2479586466153314633">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
+ <item quantity="one">"igår"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 timme"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
+ <item quantity="one">"om 1 timme"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"imorgon"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
+ <item quantity="one">"imorgon"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"för 1 sek sedan"</item>
- <item quantity="other" msgid="3699169366650930415">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
+ <item quantity="one">"för 1 sek sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"för 1 minut sedan"</item>
- <item quantity="other" msgid="851164968597150710">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
+ <item quantity="one">"för 1 minut sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"för 1 timme sedan"</item>
- <item quantity="other" msgid="6889970745748538901">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
+ <item quantity="one">"för 1 timme sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"igår"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
+ <item quantity="one">"igår"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sekund"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 minut"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 timme"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
+ <item quantity="one">"om 1 timme"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"imorgon"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
+ <item quantity="one">"imorgon"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"den %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"vid %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dagar"</string>
- <string name="hour" msgid="2126771916426189481">"timme"</string>
- <string name="hours" msgid="894424005266852993">"timmar"</string>
- <string name="minute" msgid="9148878657703769868">"minut"</string>
- <string name="minutes" msgid="5646001005827034509">"minuter"</string>
- <string name="second" msgid="3184235808021478">"sekunder"</string>
- <string name="seconds" msgid="3161515347216589235">"sekunder"</string>
- <string name="week" msgid="5617961537173061583">"vecka"</string>
- <string name="weeks" msgid="6509623834583944518">"veckor"</string>
- <string name="year" msgid="4001118221013892076">"år"</string>
- <string name="years" msgid="6881577717993213522">"år"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Alla vardagar (mån–fre)"</string>
- <string name="daily" msgid="5738949095624133403">"Varje dag"</string>
- <string name="weekly" msgid="983428358394268344">"Varje vecka på <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Varje månad"</string>
- <string name="yearly" msgid="1519577999407493836">"Varje år"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Det går inte att spela upp videon"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Det går tyvärr inte att spela upp den här videon."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"eftermiddag"</string>
- <string name="Noon" msgid="3342127745230013127">"Mitt på dagen"</string>
- <string name="midnight" msgid="7166259508850457595">"midnatt"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string>
- <string name="selectText" msgid="3889149123626888637">"Markera text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Sluta välja text"</string>
- <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klipp ut alla"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiera"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopiera alla"</string>
- <string name="paste" msgid="5629880836805036433">"Klistra in"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopiera webbadress"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Indatametod"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Lägg till %s i ordlistan"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Redigera text"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Dåligt med utrymme"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Telefonens lagringsutrymme håller på att ta slut."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Obs!"</string>
- <string name="capital_on" msgid="1544682755514494298">"PÅ"</string>
- <string name="capital_off" msgid="6815870386972805832">"AV"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Slutför åtgärd genom att använda"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Rensa standardinställning i Startinställningar > Program > Hantera program."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Välj en åtgärd"</string>
- <string name="noApplications" msgid="1691104391758345586">"Inga program kan utföra den här åtgärden."</string>
- <string name="aerr_title" msgid="653922989522758100">"Tyvärr!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
- <string name="anr_title" msgid="3100070910664756057">"Tyvärr!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
- <string name="force_close" msgid="3653416315450806396">"Tvinga fram en stängning"</string>
+ <string name="preposition_for_date">"den %s"</string>
+ <string name="preposition_for_time">"vid %s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dagar"</string>
+ <string name="hour">"timme"</string>
+ <string name="hours">"timmar"</string>
+ <string name="minute">"minut"</string>
+ <string name="minutes">"minuter"</string>
+ <string name="second">"sekunder"</string>
+ <string name="seconds">"sekunder"</string>
+ <string name="week">"vecka"</string>
+ <string name="weeks">"veckor"</string>
+ <string name="year">"år"</string>
+ <string name="years">"år"</string>
+ <string name="every_weekday">"Alla vardagar (mån–fre)"</string>
+ <string name="daily">"Varje dag"</string>
+ <string name="weekly">"Varje vecka på <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Varje månad"</string>
+ <string name="yearly">"Varje år"</string>
+ <string name="VideoView_error_title">"Det går inte att spela upp videon"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
+ <string name="VideoView_error_text_unknown">"Det går tyvärr inte att spela upp den här videon."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"eftermiddag"</string>
+ <string name="Noon">"Mitt på dagen"</string>
+ <string name="midnight">"midnatt"</string>
+ <string name="Midnight">"Midnatt"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Välj alla"</string>
+ <string name="selectText">"Markera text"</string>
+ <string name="stopSelectingText">"Sluta välja text"</string>
+ <string name="cut">"Klipp ut"</string>
+ <string name="cutAll">"Klipp ut alla"</string>
+ <string name="copy">"Kopiera"</string>
+ <string name="copyAll">"Kopiera alla"</string>
+ <string name="paste">"Klistra in"</string>
+ <string name="copyUrl">"Kopiera webbadress"</string>
+ <string name="inputMethod">"Indatametod"</string>
+ <string name="addToDictionary">"Lägg till %s i ordlistan"</string>
+ <string name="editTextMenuTitle">"Redigera text"</string>
+ <string name="low_internal_storage_view_title">"Dåligt med utrymme"</string>
+ <string name="low_internal_storage_view_text">"Telefonens lagringsutrymme håller på att ta slut."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Avbryt"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Avbryt"</string>
+ <string name="dialog_alert_title">"Obs!"</string>
+ <string name="capital_on">"PÅ"</string>
+ <string name="capital_off">"AV"</string>
+ <string name="whichApplication">"Slutför åtgärd genom att använda"</string>
+ <string name="alwaysUse">"Använd som standard för denna åtgärd."</string>
+ <string name="clearDefaultHintMsg">"Rensa standardinställning i Startinställningar > Program > Hantera program."</string>
+ <string name="chooseActivity">"Välj en åtgärd"</string>
+ <string name="noApplications">"Inga program kan utföra den här åtgärden."</string>
+ <string name="aerr_title">"Tyvärr!"</string>
+ <string name="aerr_application">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
+ <string name="aerr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
+ <string name="anr_title">"Tyvärr!"</string>
+ <string name="anr_activity_application">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_activity_process">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_application_process">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
+ <string name="force_close">"Tvinga fram en stängning"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Vänta"</string>
- <string name="debug" msgid="9103374629678531849">"Felsökning"</string>
- <string name="sendText" msgid="5132506121645618310">"Välj en åtgärd för text"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ringvolym"</string>
- <string name="volume_music" msgid="5421651157138628171">"Mediavolym"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spelar upp genom Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Samtalsvolym"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Samtalsvolym för Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Larmvolym"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Aviseringsvolym"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volym"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Tyst"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Okänd ringsignal"</string>
+ <string name="wait">"Vänta"</string>
+ <string name="debug">"Felsökning"</string>
+ <string name="sendText">"Välj en åtgärd för text"</string>
+ <string name="volume_ringtone">"Ringvolym"</string>
+ <string name="volume_music">"Mediavolym"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spelar upp genom Bluetooth"</string>
+ <string name="volume_call">"Samtalsvolym"</string>
+ <string name="volume_bluetooth_call">"Samtalsvolym för Bluetooth"</string>
+ <string name="volume_alarm">"Larmvolym"</string>
+ <string name="volume_notification">"Aviseringsvolym"</string>
+ <string name="volume_unknown">"Volym"</string>
+ <string name="ringtone_default">"Standardringsignal"</string>
+ <string name="ringtone_default_with_actual">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Tyst"</string>
+ <string name="ringtone_picker_title">"Ringsignaler"</string>
+ <string name="ringtone_unknown">"Okänd ringsignal"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-nätverk är tillgängliga"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="one">"Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="other">"Wi-Fi-nätverk är tillgängliga"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
- <item quantity="other" msgid="7915895323644292768">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="one">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="other">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Okänt program"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standardinställning"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Dölj"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Visa alla"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Läser in…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-ansluten"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har anslutit telefonen till datorn via USB. Välj Montera om du vill kopiera filer mellan datorn och telefonens SD-kort."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montera"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Montera inte"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Det gick inte att använda ditt SD-kort för USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-ansluten"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Välj om du vill kopiera filer till/från din dator."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Inaktivera USB-lagring"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Välj om USB-lagring ska inaktiveras."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Inaktivera USB-lagring"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Innan du inaktiverar USB-lagring måste du kontrollera att du har demonterat USB-värden. Välj Inaktivera om du vill inaktivera USB-lagring."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Inaktivera"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Avbryt"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Ett problem uppstod när vi skulle inaktivera USB-lagringsplatsen. Kontrollera att USB-värden har demonterats och försök igen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatera SD-kort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Vill du formatera SD-kortet? Alla data på ditt kort kommer att gå förlorade."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
+ <string name="select_character">"Infoga tecken"</string>
+ <string name="sms_control_default_app_name">"Okänt program"</string>
+ <string name="sms_control_title">"Skickar SMS"</string>
+ <string name="sms_control_message">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Avbryt"</string>
+ <string name="date_time_set">"Ställ in"</string>
+ <string name="default_permission_group">"Standardinställning"</string>
+ <string name="no_permissions">"Inga behörigheter krävs"</string>
+ <string name="perms_hide"><b>"Dölj"</b></string>
+ <string name="perms_show_all"><b>"Visa alla"</b></string>
+ <string name="googlewebcontenthelper_loading">"Läser in…"</string>
+ <string name="usb_storage_title">"USB-ansluten"</string>
+ <string name="usb_storage_message">"Du har anslutit telefonen till datorn via USB. Välj Montera om du vill kopiera filer mellan datorn och telefonens SD-kort."</string>
+ <string name="usb_storage_button_mount">"Montera"</string>
+ <string name="usb_storage_button_unmount">"Montera inte"</string>
+ <string name="usb_storage_error_message">"Det gick inte att använda ditt SD-kort för USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB-ansluten"</string>
+ <string name="usb_storage_notification_message">"Välj om du vill kopiera filer till/från din dator."</string>
+ <string name="usb_storage_stop_notification_title">"Inaktivera USB-lagring"</string>
+ <string name="usb_storage_stop_notification_message">"Välj om USB-lagring ska inaktiveras."</string>
+ <string name="usb_storage_stop_title">"Inaktivera USB-lagring"</string>
+ <string name="usb_storage_stop_message">"Innan du inaktiverar USB-lagring måste du kontrollera att du har demonterat USB-värden. Välj Inaktivera om du vill inaktivera USB-lagring."</string>
+ <string name="usb_storage_stop_button_mount">"Inaktivera"</string>
+ <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+ <string name="usb_storage_stop_error_message">"Ett problem uppstod när vi skulle inaktivera USB-lagringsplatsen. Kontrollera att USB-värden har demonterats och försök igen."</string>
+ <string name="extmedia_format_title">"Formatera SD-kort"</string>
+ <string name="extmedia_format_message">"Vill du formatera SD-kortet? Alla data på ditt kort kommer att gå förlorade."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Välj indatametod"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Förbereder SD-kort"</string>
+ <string name="select_input_method">"Välj indatametod"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidater"</u></string>
+ <string name="ext_media_checking_notification_title">"Förbereder SD-kort"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tomt SD-kort"</string>
+ <string name="ext_media_nofs_notification_title">"Tomt SD-kort"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Skadat SD-kort"</string>
+ <string name="ext_media_unmountable_notification_title">"Skadat SD-kort"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kort togs oväntat bort"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Demontera SD-kort innan borttagning för att undvika dataförlust."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Säkert att ta bort SD-kort"</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kort togs oväntat bort"</string>
+ <string name="ext_media_badremoval_notification_message">"Demontera SD-kort innan borttagning för att undvika dataförlust."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Säkert att ta bort SD-kort"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Borttaget SD-kort"</string>
+ <string name="ext_media_nomedia_notification_title">"Borttaget SD-kort"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Inga matchande aktiviteter hittades"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"uppdatera statistik över användning av komponenter"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fel när widgeten expanderades"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Sök"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Skicka"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Nästa"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Färdig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Utför"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Slå nummer "\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Inga matchande aktiviteter hittades"</string>
+ <string name="permlab_pkgUsageStats">"uppdatera statistik över användning av komponenter"</string>
+ <string name="permdesc_pkgUsageStats">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Peka två gånger för zoomkontroll"</string>
+ <string name="gadget_host_error_inflating">"Fel när widgeten expanderades"</string>
+ <string name="ime_action_go">"Kör"</string>
+ <string name="ime_action_search">"Sök"</string>
+ <string name="ime_action_send">"Skicka"</string>
+ <string name="ime_action_next">"Nästa"</string>
+ <string name="ime_action_done">"Färdig"</string>
+ <string name="ime_action_default">"Utför"</string>
+ <string name="dial_number_using">"Slå nummer "\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a8625fd..bda67c7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<başlıksız>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon numarası yok)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Bilinmiyor)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Sesli Mesaj"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Bağlantı sorunu veya geçersiz MMI kodu."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Hizmet etkindi."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Hizmet şunun için etkinleştirildi:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Hizmet devre dışı bırakıldı."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Kayıt işlemi başarılı oldu."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Silme işlemi başarılı."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Yanlış şifre."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI tamamlandı."</string>
- <string name="badPin" msgid="5085454289896032547">"Yazdığınız eski PIN doğru değil."</string>
- <string name="badPuk" msgid="5702522162746042460">"Yazdığınız PUK doğru değil."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Girdiğiniz PIN kodları eşleşmiyor."</string>
- <string name="invalidPin" msgid="3850018445187475377">"4 ila 8 rakamdan oluşan bir PIN girin."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Engellenen SIM kartı açmak için PUK2 kodunu yazın."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Gelen Çağrı Kimliği"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Giden Çağrı Kimliği"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Çağrı yönlendirme"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Çağrı bekletme"</string>
- <string name="BaMmi" msgid="455193067926770581">"Çağrı engelleme"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Şifre değişikliği"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN kodu değişikliği"</string>
+ <string name="untitled">"<başlıksız>"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Telefon numarası yok)"</string>
+ <string name="unknownName">"(Bilinmiyor)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Sesli Mesaj"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Bağlantı sorunu veya geçersiz MMI kodu."</string>
+ <string name="serviceEnabled">"Hizmet etkindi."</string>
+ <string name="serviceEnabledFor">"Hizmet şunun için etkinleştirildi:"</string>
+ <string name="serviceDisabled">"Hizmet devre dışı bırakıldı."</string>
+ <string name="serviceRegistered">"Kayıt işlemi başarılı oldu."</string>
+ <string name="serviceErased">"Silme işlemi başarılı."</string>
+ <string name="passwordIncorrect">"Yanlış şifre."</string>
+ <string name="mmiComplete">"MMI tamamlandı."</string>
+ <string name="badPin">"Yazdığınız eski PIN doğru değil."</string>
+ <string name="badPuk">"Yazdığınız PUK doğru değil."</string>
+ <string name="mismatchPin">"Girdiğiniz PIN kodları eşleşmiyor."</string>
+ <string name="invalidPin">"4 ila 8 rakamdan oluşan bir PIN girin."</string>
+ <string name="needPuk">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
+ <string name="needPuk2">"Engellenen SIM kartı açmak için PUK2 kodunu yazın."</string>
+ <string name="ClipMmi">"Gelen Çağrı Kimliği"</string>
+ <string name="ClirMmi">"Giden Çağrı Kimliği"</string>
+ <string name="CfMmi">"Çağrı yönlendirme"</string>
+ <string name="CwMmi">"Çağrı bekletme"</string>
+ <string name="BaMmi">"Çağrı engelleme"</string>
+ <string name="PwdMmi">"Şifre değişikliği"</string>
+ <string name="PinMmi">"PIN kodu değişikliği"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmış"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmamış"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmış"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Hizmet sağlanamadı."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Arayan kimliği ayarı değiştirilemez."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Kısıtlanmış erişim değiştirildi"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Veri hizmeti engellendi."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Acil durum hizmeti engellendi."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Ses/SMS hizmeti engellendi."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tüm ses/SMS hizmetleri engellendi."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Ses"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Veri"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asenk."</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Senk."</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmış"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmamış"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmış"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
+ <string name="serviceNotProvisioned">"Hizmet sağlanamadı."</string>
+ <string name="CLIRPermanent">"Arayan kimliği ayarı değiştirilemez."</string>
+ <string name="RestrictedChangedTitle">"Kısıtlanmış erişim değiştirildi"</string>
+ <string name="RestrictedOnData">"Veri hizmeti engellendi."</string>
+ <string name="RestrictedOnEmergency">"Acil durum hizmeti engellendi."</string>
+ <string name="RestrictedOnNormal">"Ses/SMS hizmeti engellendi."</string>
+ <string name="RestrictedOnAll">"Tüm ses/SMS hizmetleri engellendi."</string>
+ <string name="serviceClassVoice">"Ses"</string>
+ <string name="serviceClassData">"Veri"</string>
+ <string name="serviceClassFAX">"FAKS"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asenk."</string>
+ <string name="serviceClassDataSync">"Senk."</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"Tamam"</string>
- <string name="httpError" msgid="2567300624552921790">"Web sayfası hata içeriyor."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL bulunamadı."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Site kimlik doğrulaması şeması desteklenmiyor."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Kimlik doğrulanamadı."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Proxy sunucusu üzerinden kimlik doğrulanamadı."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Sunucu ile bağlantı kurulamadı."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Sunucu iletişim kuramadı. Daha sonra yeniden deneyin."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Sunucuya bağlanma işlemi zaman aşımına uğradı."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Sayfada çok fazla sunucu yeniden yönlendirmesi bulunuyor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokol desteklenmiyor."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Güvenli bir bağlantı kurulamadı."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URL geçersiz olduğundan sayfa açılamadı."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Dosyaya erişilemedi."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"İstenen dosya bulunamadı."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Çok fazla sayıda istek işleniyor. Daha sonra yeniden deneyin."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Senk."</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Senk."</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonun depolama alanı doldu! Yer açmak için bazı dosyaları silin."</string>
- <string name="me" msgid="6545696007631404292">"Ben"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefon seçenekleri"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Sessiz mod"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Kablosuzu aç"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Kablosuzu kapat"</string>
- <string name="screen_lock" msgid="799094655496098153">"Ekran kilidi"</string>
- <string name="power_off" msgid="4266614107412865048">"Kapat"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Kapanıyor…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefonunuz kapanacak."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Hiçbir yeni uygulama yok."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefon seçenekleri"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Sessiz mod"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ses KAPALI"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ses AÇIK"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
- <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Uygulamaların size maliyet getirebilecek işlemler yapmasına izin verir."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS mesajlarınızı, e-posta iletilerinizi ve diğer mesajlarınızı okuyup yazın."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Kişisel bilgileriniz"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Telefonunuzda depolanan kişilere ve takvime doğrudan erişim."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Konumunuz"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Fiziksel konumunuzu izleyin"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Ağ iletişimi"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Uygulamaların çeşitli ağ özelliklerine erişmesine izin verir."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google hesaplarınız"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Kullanılabilir Google hesaplarına erişin."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Donanım denetimleri"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Telefon donanımına doğrudan erişim."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefon çağrıları"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Telefon görüşmelerini izleyin, kaydedin ve işleyin."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Sistem araçları"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Sisteme alt düzey erişim ve denetimi."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Geliştirme araçları"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Yalnızca uygulama geliştiriciler için gerekli özellikler."</string>
+ <string name="httpErrorOk">"Tamam"</string>
+ <string name="httpError">"Web sayfası hata içeriyor."</string>
+ <string name="httpErrorLookup">"URL bulunamadı."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Site kimlik doğrulaması şeması desteklenmiyor."</string>
+ <string name="httpErrorAuth">"Kimlik doğrulanamadı."</string>
+ <string name="httpErrorProxyAuth">"Proxy sunucusu üzerinden kimlik doğrulanamadı."</string>
+ <string name="httpErrorConnect">"Sunucu ile bağlantı kurulamadı."</string>
+ <string name="httpErrorIO">"Sunucu iletişim kuramadı. Daha sonra yeniden deneyin."</string>
+ <string name="httpErrorTimeout">"Sunucuya bağlanma işlemi zaman aşımına uğradı."</string>
+ <string name="httpErrorRedirectLoop">"Sayfada çok fazla sunucu yeniden yönlendirmesi bulunuyor."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokol desteklenmiyor."</string>
+ <string name="httpErrorFailedSslHandshake">"Güvenli bir bağlantı kurulamadı."</string>
+ <string name="httpErrorBadUrl">"URL geçersiz olduğundan sayfa açılamadı."</string>
+ <string name="httpErrorFile">"Dosyaya erişilemedi."</string>
+ <string name="httpErrorFileNotFound">"İstenen dosya bulunamadı."</string>
+ <string name="httpErrorTooManyRequests">"Çok fazla sayıda istek işleniyor. Daha sonra yeniden deneyin."</string>
+ <string name="contentServiceSync">"Senk."</string>
+ <string name="contentServiceSyncNotificationTitle">"Senk."</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
+ <string name="low_memory">"Telefonun depolama alanı doldu! Yer açmak için bazı dosyaları silin."</string>
+ <string name="me">"Ben"</string>
+ <string name="power_dialog">"Telefon seçenekleri"</string>
+ <string name="silent_mode">"Sessiz mod"</string>
+ <string name="turn_on_radio">"Kablosuzu aç"</string>
+ <string name="turn_off_radio">"Kablosuzu kapat"</string>
+ <string name="screen_lock">"Ekran kilidi"</string>
+ <string name="power_off">"Kapat"</string>
+ <string name="shutdown_progress">"Kapanıyor…"</string>
+ <string name="shutdown_confirm">"Telefonunuz kapanacak."</string>
+ <string name="no_recent_tasks">"Hiçbir yeni uygulama yok."</string>
+ <string name="global_actions">"Telefon seçenekleri"</string>
+ <string name="global_action_lock">"Ekran kilidi"</string>
+ <string name="global_action_power_off">"Kapat"</string>
+ <string name="global_action_toggle_silent_mode">"Sessiz mod"</string>
+ <string name="global_action_silent_mode_on_status">"Ses KAPALI"</string>
+ <string name="global_action_silent_mode_off_status">"Ses AÇIK"</string>
+ <string name="global_actions_toggle_airplane_mode">"Uçak modu"</string>
+ <string name="global_actions_airplane_mode_on_status">"Uçak modu AÇIK"</string>
+ <string name="global_actions_airplane_mode_off_status">"Uçak modu KAPALI"</string>
+ <string name="safeMode">"Güvenli mod"</string>
+ <string name="android_system_label">"Android Sistemi"</string>
+ <string name="permgrouplab_costMoney">"Size maliyet getiren hizmetler"</string>
+ <string name="permgroupdesc_costMoney">"Uygulamaların size maliyet getirebilecek işlemler yapmasına izin verir."</string>
+ <string name="permgrouplab_messages">"Mesajlarınız"</string>
+ <string name="permgroupdesc_messages">"SMS mesajlarınızı, e-postanızı ve diğer mesajlarınızı okuyup yazın."</string>
+ <string name="permgrouplab_personalInfo">"Kişisel bilgileriniz"</string>
+ <string name="permgroupdesc_personalInfo">"Telefonunuzda depolanan kişilere ve takvime doğrudan erişim."</string>
+ <string name="permgrouplab_location">"Konumunuz"</string>
+ <string name="permgroupdesc_location">"Fiziksel konumunuzu izleyin"</string>
+ <string name="permgrouplab_network">"Ağ iletişimi"</string>
+ <string name="permgroupdesc_network">"Uygulamaların çeşitli ağ özelliklerine erişmesine izin verir."</string>
+ <string name="permgrouplab_accounts">"Google hesaplarınız"</string>
+ <string name="permgroupdesc_accounts">"Kullanılabilir Google hesaplarına erişin."</string>
+ <string name="permgrouplab_hardwareControls">"Donanım denetimleri"</string>
+ <string name="permgroupdesc_hardwareControls">"Telefon donanımına doğrudan erişim."</string>
+ <string name="permgrouplab_phoneCalls">"Telefon çağrıları"</string>
+ <string name="permgroupdesc_phoneCalls">"Telefon görüşmelerini izleyin, kaydedin ve işleyin."</string>
+ <string name="permgrouplab_systemTools">"Sistem araçları"</string>
+ <string name="permgroupdesc_systemTools">"Sisteme alt düzey erişim ve denetimi."</string>
+ <string name="permgrouplab_developmentTools">"Geliştirme araçları"</string>
+ <string name="permgroupdesc_developmentTools">"Yalnızca uygulama geliştiriciler için gerekli özellikler."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Uygulamanın durum çubuğunu devre dışı bırakmasına veya sistem simgeleri ekleyip kaldırmasına izin verir."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"durum çubuğunu genişlet/daralt"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Uygulamanın, durum çubuğunu genişletip daraltmasına izin verir."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"giden aramalarda araya gir"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Uygulamanın, giden çağrıları işlemesine ve aranacak numarayı değiştirmesine izin verir. Kötü amaçlı uygulamalar giden çağrıları izleyebilir, yönlendirebilir veya engelleyebilir."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS al"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Uygulamanın SMS mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS al"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Uygulamanın MMS mesajları almasına ve işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya size göstermeden silebilir."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS mesajları gönder"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Uygulamaların SMS mesajları göndermesine izin verir. Kötü amaçlı uygulamalar, onayınızı almadan mesaj göndererek size maliyet çıkarabilir."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS veya MMS oku"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Uygulamaların, telefonunuzda veya SIM kartta depolanan SMS mesajlarını okumasına izin verir. Kötü amaçlı uygulamalar gizli mesajlarınızı okuyabilir."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS veya MMS düzenle"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Uygulamanın telefonunuzda veya SIM kartta depolanan SMS mesajlarına yazmasına izin verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP al"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Uygulamanın WAP mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"çalışan uygulamaları al"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Uygulamaların şu anda ve yakın geçmişte çalışmakta olan işlemler hakkında bilgi almasına izin verir. Kötü amaçlı uygulamaların diğer uygulamalar ile ilgili gizli bilgileri keşfetmesine izin verebilir."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"çalışan uygulamaları yeniden sırala"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Uygulamaların görevleri ön plana ve arka plana taşımasına izin verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında zorla ön plana çıkarabilir."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"uygulama hata ayıklamayı etkinleştir"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Bir uygulamanın başka bir uygulama için hata ayıklamayı çalıştırmasına izin verir. Kötü amaçlı uygulamalar bu işlevi başka uygulamaları kapatmak için kullanabilir."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Uygulamaların güncel yapılandırmayı; örneğin yerel ayarı veya genel yazı tipi boyutunu değiştirmesine izin verir."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"diğer uygulamaları yeniden başlat"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Uygulamaların başka uygulamaları zorla yeniden başlatmasına izin verir."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"uygulamayı kapanmaya zorla"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Uygulamaların, ön plandaki herhangi bir etkinliği kapanmaya ve arka plana geçmeye zorlamasına izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"sistemin dahili durumunu al"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Uygulamanın dahili sistem durumunu almasına izin verir. Kötü amaçlı uygulamalar, normalde gerekli olmaması gereken çok çeşitli özel ve koruma altındaki bilgiyi alabilir."</string>
+ <string name="permlab_statusBar">"durum çubuğunu devre dışı bırak veya değiştir"</string>
+ <string name="permdesc_statusBar">"Uygulamanın durum çubuğunu devre dışı bırakmasına veya sistem simgeleri ekleyip kaldırmasına izin verir."</string>
+ <string name="permlab_expandStatusBar">"durum çubuğunu genişlet/daralt"</string>
+ <string name="permdesc_expandStatusBar">"Uygulamanın, durum çubuğunu genişletip daraltmasına izin verir."</string>
+ <string name="permlab_processOutgoingCalls">"giden aramalarda araya gir"</string>
+ <string name="permdesc_processOutgoingCalls">"Uygulamanın, giden çağrıları işlemesine ve aranacak numarayı değiştirmesine izin verir. Kötü amaçlı uygulamalar giden çağrıları izleyebilir, yönlendirebilir veya engelleyebilir."</string>
+ <string name="permlab_receiveSms">"SMS al"</string>
+ <string name="permdesc_receiveSms">"Uygulamanın SMS mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
+ <string name="permlab_receiveMms">"MMS al"</string>
+ <string name="permdesc_receiveMms">"Uygulamanın MMS mesajları almasına ve işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya size göstermeden silebilir."</string>
+ <string name="permlab_sendSms">"SMS mesajları gönder"</string>
+ <string name="permdesc_sendSms">"Uygulamaların SMS mesajları göndermesine izin verir. Kötü amaçlı uygulamalar, onayınızı almadan mesaj göndererek size maliyet çıkarabilir."</string>
+ <string name="permlab_readSms">"SMS veya MMS oku"</string>
+ <string name="permdesc_readSms">"Uygulamaların, telefonunuzda veya SIM kartta depolanan SMS mesajlarını okumasına izin verir. Kötü amaçlı uygulamalar gizli mesajlarınızı okuyabilir."</string>
+ <string name="permlab_writeSms">"SMS veya MMS düzenle"</string>
+ <string name="permdesc_writeSms">"Uygulamanın telefonunuzda veya SIM kartta depolanan SMS mesajlarına yazmasına izin verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
+ <string name="permlab_receiveWapPush">"WAP al"</string>
+ <string name="permdesc_receiveWapPush">"Uygulamanın WAP mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
+ <string name="permlab_getTasks">"çalışan uygulamaları al"</string>
+ <string name="permdesc_getTasks">"Uygulamaların şu anda ve yakın geçmişte çalışmakta olan işlemler hakkında bilgi almasına izin verir. Kötü amaçlı uygulamaların diğer uygulamalar ile ilgili gizli bilgileri keşfetmesine izin verebilir."</string>
+ <string name="permlab_reorderTasks">"çalışan uygulamaları yeniden sırala"</string>
+ <string name="permdesc_reorderTasks">"Uygulamaların görevleri ön plana ve arka plana taşımasına izin verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında zorla ön plana çıkarabilir."</string>
+ <string name="permlab_setDebugApp">"uygulama hata ayıklamayı etkinleştir"</string>
+ <string name="permdesc_setDebugApp">"Bir uygulamanın başka bir uygulama için hata ayıklamayı çalıştırmasına izin verir. Kötü amaçlı uygulamalar bu işlevi başka uygulamaları kapatmak için kullanabilir."</string>
+ <string name="permlab_changeConfiguration">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
+ <string name="permdesc_changeConfiguration">"Uygulamaların güncel yapılandırmayı; örneğin yerel ayarı veya genel yazı tipi boyutunu değiştirmesine izin verir."</string>
+ <string name="permlab_restartPackages">"diğer uygulamaları yeniden başlat"</string>
+ <string name="permdesc_restartPackages">"Uygulamaların başka uygulamaları zorla yeniden başlatmasına izin verir."</string>
+ <string name="permlab_forceBack">"uygulamayı kapanmaya zorla"</string>
+ <string name="permdesc_forceBack">"Uygulamaların, ön plandaki herhangi bir etkinliği kapanmaya ve arka plana geçmeye zorlamasına izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
+ <string name="permlab_dump">"sistemin dahili durumunu al"</string>
+ <string name="permdesc_dump">"Uygulamanın dahili sistem durumunu almasına izin verir. Kötü amaçlı uygulamalar, normalde gerekli olmaması gereken çok çeşitli özel ve koruma altındaki bilgiyi alabilir."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Uygulamaların, sistemin etkinlikleri nasıl başlattığını izlemesine ve denetlemesine izin verir. Kötü amaçlı uygulamalar sistemin güvenliğini tamamen tehlikeye atabilir. Bu izin yalnızca program geliştirme amacıyla gereklidir, normal telefon kullanımı için gerekli değildir."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Uygulamaların bir uygulama paketinin kaldırıldığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bunu çalışan diğer herhangi bir uygulamayı kapatmak için kullanabilir."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS ile alınan yayın gönder"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Uygulamaların bir SMS mesajı alındığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi telefona sahte SMS mesajları göndermek için kullanabilir."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Uygulamaların, WAP PUSH mesajının alındığına dair bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi, sahte MMS alındıları göndermek veya bir web sayfasını sessizce kötü amaçla tasarlanmış başkaları ile değiştirmek için kullanabilir."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Uygulamaların, çalışacak maksimum işlem sayısını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"tüm arka plan uygulamalarını kapat"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Uygulamaların, etkinliklerin arka planda daima tamamlanıp tamamlanmadığını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"pil istatistiklerini değiştir"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Toplanan pil istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_runSetActivityWatcher">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
+ <string name="permdesc_runSetActivityWatcher">"Uygulamaların, sistemin etkinlikleri nasıl başlattığını izlemesine ve denetlemesine izin verir. Kötü amaçlı uygulamalar sistemin güvenliğini tamamen tehlikeye atabilir. Bu izin yalnızca program geliştirme amacıyla gereklidir, normal telefon kullanımı için gerekli değildir."</string>
+ <string name="permlab_broadcastPackageRemoved">"paket ile kaldırılan yayını gönder"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Uygulamaların bir uygulama paketinin kaldırıldığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bunu çalışan diğer herhangi bir uygulamayı kapatmak için kullanabilir."</string>
+ <string name="permlab_broadcastSmsReceived">"SMS ile alınan yayın gönder"</string>
+ <string name="permdesc_broadcastSmsReceived">"Uygulamaların bir SMS mesajı alındığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi telefona sahte SMS mesajları göndermek için kullanabilir."</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH ile alınan yayın gönder"</string>
+ <string name="permdesc_broadcastWapPush">"Uygulamaların, WAP PUSH mesajının alındığına dair bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi, sahte MMS alındıları göndermek veya bir web sayfasını sessizce kötü amaçla tasarlanmış başkaları ile değiştirmek için kullanabilir."</string>
+ <string name="permlab_setProcessLimit">"çalışan işlem sayısını sınırla"</string>
+ <string name="permdesc_setProcessLimit">"Uygulamaların, çalışacak maksimum işlem sayısını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
+ <string name="permlab_setAlwaysFinish">"tüm arka plan uygulamaları kapat"</string>
+ <string name="permdesc_setAlwaysFinish">"Uygulamaların, etkinliklerin arka planda daima tamamlanıp tamamlanmadığını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
+ <string name="permlab_batteryStats">"pil istatistiklerini değiştir"</string>
+ <string name="permdesc_batteryStats">"Toplanan pil istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"yetkisiz pencereleri görüntüle"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Dahili sistem kullanıcı arayüzü tarafından kullanılmak üzere tasarlanmış pencerelerin oluşturulmasına izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"sistem düzeyi uyarıları görüntüle"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Uygulamaların sistem uyarı pencereleri göstermesine izin verir. Kötü amaçlı uygulamalar telefonun tüm ekranını işgal edebilir."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"genel animasyon hızını değiştir"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Uygulamaların, istedikleri zaman genel animasyon hızını değiştirmesine (animasyonları hızlandırmasına veya yavaşlatmasına) izin verir."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"uygulama simgelerini yönet"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Uygulamaların, kendi normal Z sıralamalarını atlayarak kendi simgelerini oluşturup yönetmelerine izin verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"tuşlara bas ve düğmeleri denetle"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Uygulamaların kendi giriş işlemlerini (tuşa basma vb.) başka uygulamalara göndermesine izin verir. Kötü amaçlı uygulamalar bunu telefonun denetimini ele geçirmek için kullanabilir."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"yazdıklarınızı ve yaptığınız işlemleri kaydet"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Uygulamaların, başka bir uygulama ile etkileşim halindeyken (örneğin bir şifre girerken) bile bastığınız tuşları izlemesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"bir giriş yöntemine bağla"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Tutucunun bir giriş yönteminin en üst düzey arayüzüne bağlanmasına izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"uygulamalara Linux sinyalleri gönder"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"uygulamayı her zaman çalıştır"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Uygulamaların, sistemin başka uygulamalarda kullanamaması için kendi parçalarını kalıcı kılmasına izin verir."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"uygulamaları sil"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Uygulamaların Android paketlerini silmesine izin verir. Kötü amaçlı uygulamalar bu işlevi önemli uygulamaları silmek için kullanabilir."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"diğer uygulamaların verilerini sil"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Uygulamaların kullanıcı verilerini temizlemesine izin verir."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"diğer uygulamaların önbelleklerini sil"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Uygulamaların önbellek dosyalarını silmesine izin verir."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"uygulama depolama alanını ölç"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Uygulamanın kodunu, verilerini ve önbellek boyutunu almasına izin verir"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"doğrudan uygulama yükle"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Uygulamaların yeni veya güncellenmiş Android paketleri yüklemesine izin verir. Kötü amaçlı uygulamalar bunu, kendilerine verilen izin derecesi keyfi olarak değişen yeni uygulamalar eklemek için kullanabilir."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"tüm uygulama önbelleği verilerini sil"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"sistem günlük dosyalarını oku"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Uygulamaların başka bir uygulamanın bir bileşenini etkinleştirme ayarını değiştirmesine izin verir. Kötü amaçlı uygulamalar bu ayarı telefonun önemli yeteneklerini devre dışı bırakmak için kullanabilir. Bu iznin verilmesi uygulama bileşenlerini kullanılamaz, tutarsız veya kararsız bir duruma sokabileceği için izin verilirken dikkatli olunmalıdır."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"tercih edilen uygulamaları ayarla"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Uygulamanın tercih ettiğiniz uygulamaları değiştirmesine izin verir. Bu işlem, kötü amaçlı uygulamaların, çalışmakta olan uygulamaları sessizce değiştirerek mevcut uygulamalarınızı aldatıp kişisel bilgilerinizi almasına izin verebilir."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"genel sistem ayarlarını değiştir"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Uygulamaların sistem ayar verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar sisteminizin yapılandırmasını bozabilir."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"güvenli sistem ayarlarını değiştir"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Uygulamaların sistemin güvenlik ayarları verilerini değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google hizmetler haritasını değiştir"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Uygulamanın, Google hizmetleri haritasını değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"açılışta otomatik başlat"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Uygulamaların, sistem açıldıktan hemen sonra kendini başlatmasına izin verir. Bu işlev, telefonu başlatma süresini uzatabilir ve uygulama, sürekli çalışması nedeniyle telefonun çalışmasını genel olarak yavaşlatabilir."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sabit yayın gönder"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Uygulamaların yayın bittikten sonra da kalan sabit yayınlar göndermesine izin verir. Kötü amaçlı uygulamalar telefonun aşırı miktarda bellek kullanmasına neden olarak telefonu yavaşlatabilir veya telefonun kararsız hale gelmesine neden olabilir."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"kişi verilerini oku"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Uygulamaların telefonunuzda depolanan tüm kişi (adres) verilerini okumasına izin verir. Kötü amaçlı uygulamalar bu işlevi verilerinizi başkalarına göndermek için kullanabilir."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"kişi verileri yaz"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Uygulamaların telefonunuzda depolanan kişi (adres) verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kişi verilerinizi silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"sahip verilerini yaz"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kullanıcı verilerini silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"sahip verilerini oku"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini okumasına izin verir. Kötü amaçlı uygulamalar bunu telefon sahibi verilerini okumak için kullanabilir."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"takvim verilerini oku"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Uygulamaların telefonunuzda depolanan takvim etkinliklerinin tümünü okumasına izin verir. Kötü amaçlı uygulamalar bunu, takvim etkinliklerinizi başkalarına göndermek için kullanabilir."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"takvim verilerini yaz"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Uygulamaların telefonunuzda depolanan takvim etkinliklerini değiştirmesine izin verir. Kötü amaçlı uygulamaları bunu takvim verilerinizi silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"test için sahte konum kaynakları"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Test amacıyla sahte konum kaynakları oluşturur. Kötü amaçlı uygulamalar bu işlevi GPS veya Ağ Hizmeti sağlayıcılar gibi gerçek kaynaklardan gelen konum ve/veya durum bilgilerini geçersiz kılmak için kullanabilir."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ek konum sağlayıcı komutlarına eriş"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Ek konum sağlayıcı komutlarına erişin. Kötü amaçlı uygulamalar bu işlevi GPS veya diğer konum kaynaklarının işleyişine müdahale etmek için kullanabilir."</string>
+ <string name="permlab_internalSystemWindow">"yetkisiz pencereleri görüntüle"</string>
+ <string name="permdesc_internalSystemWindow">"Dahili sistem kullanıcı arayüzü tarafından kullanılmak üzere tasarlanmış pencerelerin oluşturulmasına izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_systemAlertWindow">"sistem düzeyi uyarıları görüntüle"</string>
+ <string name="permdesc_systemAlertWindow">"Uygulamaların sistem uyarı pencereleri göstermesine izin verir. Kötü amaçlı uygulamalar telefonun tüm ekranını işgal edebilir."</string>
+ <string name="permlab_setAnimationScale">"genel animasyon hızını değiştir"</string>
+ <string name="permdesc_setAnimationScale">"Uygulamaların, istedikleri zaman genel animasyon hızını değiştirmesine (animasyonları hızlandırmasına veya yavaşlatmasına) izin verir."</string>
+ <string name="permlab_manageAppTokens">"uygulama simgelerini yönet"</string>
+ <string name="permdesc_manageAppTokens">"Uygulamaların, kendi normal Z sıralamalarını atlayarak kendi simgelerini oluşturup yönetmelerine izin verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
+ <string name="permlab_injectEvents">"tuşlara bas ve düğmeleri denetle"</string>
+ <string name="permdesc_injectEvents">"Uygulamaların kendi giriş işlemlerini (tuşa basma vb.) başka uygulamalara göndermesine izin verir. Kötü amaçlı uygulamalar bunu telefonun denetimini ele geçirmek için kullanabilir."</string>
+ <string name="permlab_readInputState">"yazdıklarınızı ve yaptığınız işlemleri kaydedin"</string>
+ <string name="permdesc_readInputState">"Uygulamaların, başka bir uygulama ile etkileşim halindeyken (örneğin bir şifre girerken) bile bastığınız tuşları izlemesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
+ <string name="permlab_bindInputMethod">"bir giriş yöntemine bağla"</string>
+ <string name="permdesc_bindInputMethod">"Tutucunun bir giriş yönteminin en üst düzey arayüzüne bağlanmasına izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
+ <string name="permlab_setOrientation">"ekran yönünü değiştir"</string>
+ <string name="permdesc_setOrientation">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
+ <string name="permlab_signalPersistentProcesses">"uygulamalara Linux sinyalleri gönder"</string>
+ <string name="permdesc_signalPersistentProcesses">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string>
+ <string name="permlab_persistentActivity">"uygulamayı her zaman çalıştır"</string>
+ <string name="permdesc_persistentActivity">"Uygulamaların, sistemin başka uygulamalarda kullanamaması için kendi parçalarını kalıcı kılmasına izin verir."</string>
+ <string name="permlab_deletePackages">"uygulamaları sil"</string>
+ <string name="permdesc_deletePackages">"Uygulamaların Android paketlerini silmesine izin verir. Kötü amaçlı uygulamalar bu işlevi önemli uygulamaları silmek için kullanabilir."</string>
+ <string name="permlab_clearAppUserData">"diğer uygulamaların verilerini sil"</string>
+ <string name="permdesc_clearAppUserData">"Uygulamaların kullanıcı verilerini temizlemesine izin verir."</string>
+ <string name="permlab_deleteCacheFiles">"diğer uygulamaların önbelleklerini sil"</string>
+ <string name="permdesc_deleteCacheFiles">"Uygulamaların önbellek dosyalarını silmesine izin verir."</string>
+ <string name="permlab_getPackageSize">"uygulama depolama alanını ölç"</string>
+ <string name="permdesc_getPackageSize">"Uygulamanın kodunu, verilerini ve önbellek boyutunu almasına izin verir"</string>
+ <string name="permlab_installPackages">"doğrudan uygulama yükle"</string>
+ <string name="permdesc_installPackages">"Uygulamaların yeni veya güncellenmiş Android paketleri yüklemesine izin verir. Kötü amaçlı uygulamalar bunu, kendilerine verilen izin derecesi keyfi olarak değişen yeni uygulamalar eklemek için kullanabilir."</string>
+ <string name="permlab_clearAppCache">"tüm uygulama önbelleği verilerini sil"</string>
+ <string name="permdesc_clearAppCache">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string>
+ <string name="permlab_readLogs">"sistem günlük dosyalarını oku"</string>
+ <string name="permdesc_readLogs">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string>
+ <string name="permlab_diagnostic">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
+ <string name="permdesc_diagnostic">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
+ <string name="permlab_changeComponentState">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
+ <string name="permdesc_changeComponentState">"Uygulamaların başka bir uygulamanın bir bileşenini etkinleştirme ayarını değiştirmesine izin verir. Kötü amaçlı uygulamalar bu ayarı telefonun önemli yeteneklerini devre dışı bırakmak için kullanabilir. Bu iznin verilmesi uygulama bileşenlerini kullanılamaz, tutarsız veya kararsız bir duruma sokabileceği için izin verilirken dikkatli olunmalıdır."</string>
+ <string name="permlab_setPreferredApplications">"tercih edilen uygulamaları ayarla"</string>
+ <string name="permdesc_setPreferredApplications">"Uygulamanın tercih ettiğiniz uygulamaları değiştirmesine izin verir. Bu işlem, kötü amaçlı uygulamaların, çalışmakta olan uygulamaları sessizce değiştirerek mevcut uygulamalarınızı aldatıp kişisel bilgilerinizi almasına izin verebilir."</string>
+ <string name="permlab_writeSettings">"genel sistem ayarlarını değiştir"</string>
+ <string name="permdesc_writeSettings">"Uygulamaların sistem ayar verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar sisteminizin yapılandırmasını bozabilir."</string>
+ <string name="permlab_writeSecureSettings">"güvenli sistem ayarlarını değiştir"</string>
+ <string name="permdesc_writeSecureSettings">"Uygulamaların sistemin güvenlik ayarları verilerini değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_writeGservices">"Google hizmetler haritasını değiştir"</string>
+ <string name="permdesc_writeGservices">"Uygulamanın, Google hizmetleri haritasını değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_receiveBootCompleted">"açılışta otomatik başlat"</string>
+ <string name="permdesc_receiveBootCompleted">"Uygulamaların, sistem açıldıktan hemen sonra kendini başlatmasına izin verir. Bu işlev, telefonu başlatma süresini uzatabilir ve uygulama, sürekli çalışması nedeniyle telefonun çalışmasını genel olarak yavaşlatabilir."</string>
+ <string name="permlab_broadcastSticky">"sabit yayın gönder"</string>
+ <string name="permdesc_broadcastSticky">"Uygulamaların yayın bittikten sonra da kalan sabit yayınlar göndermesine izin verir. Kötü amaçlı uygulamalar telefonun aşırı miktarda bellek kullanmasına neden olarak telefonu yavaşlatabilir veya telefonun kararsız hale gelmesine neden olabilir."</string>
+ <string name="permlab_readContacts">"kişi verilerini oku"</string>
+ <string name="permdesc_readContacts">"Uygulamaların telefonunuzda depolanan tüm kişi (adres) verilerini okumasına izin verir. Kötü amaçlı uygulamalar bu işlevi verilerinizi başkalarına göndermek için kullanabilir."</string>
+ <string name="permlab_writeContacts">"kişi verileri yaz"</string>
+ <string name="permdesc_writeContacts">"Uygulamaların telefonunuzda depolanan kişi (adres) verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kişi verilerinizi silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_writeOwnerData">"sahip verilerini yaz"</string>
+ <string name="permdesc_writeOwnerData">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kullanıcı verilerini silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_readOwnerData">"sahip verilerini oku"</string>
+ <string name="permdesc_readOwnerData">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini okumasına izin verir. Kötü amaçlı uygulamalar bunu telefon sahibi verilerini okumak için kullanabilir."</string>
+ <string name="permlab_readCalendar">"takvim verilerini oku"</string>
+ <string name="permdesc_readCalendar">"Uygulamaların telefonunuzda depolanan takvim etkinliklerinin tümünü okumasına izin verir. Kötü amaçlı uygulamalar bunu, takvim etkinliklerinizi başkalarına göndermek için kullanabilir."</string>
+ <string name="permlab_writeCalendar">"takvim verilerini yaz"</string>
+ <string name="permdesc_writeCalendar">"Uygulamaların telefonunuzda depolanan takvim etkinliklerini değiştirmesine izin verir. Kötü amaçlı uygulamaları bunu takvim verilerinizi silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_accessMockLocation">"test için sahte konum kaynakları"</string>
+ <string name="permdesc_accessMockLocation">"Test amacıyla sahte konum kaynakları oluşturur. Kötü amaçlı uygulamalar bu işlevi GPS veya Ağ Hizmeti sağlayıcılar gibi gerçek kaynaklardan gelen konum ve/veya durum bilgilerini geçersiz kılmak için kullanabilir."</string>
+ <string name="permlab_accessLocationExtraCommands">"ek konum sağlayıcı komutlarına eriş"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Ek konum sağlayıcı komutlarına erişin. Kötü amaçlı uygulamalar bu işlevi GPS veya diğer konum kaynaklarının işleyişine müdahale etmek için kullanabilir."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"kesinliği yüksek (GPS) konum"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Bulunduğu yerlerde telefondan Küresel Konumlandırma Sistemi gibi hassas konum bulma kaynaklarına erişin. Kötü amaçlı uygulamalar bu işlevi bulunduğunuz yeri belirlemek için kullanabilir ve ek pil gücü tüketebilir."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"kesinliği düşük (ağ tabanlı) konum"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Telefonun yaklaşık yerini belirlemek için bulunduğu yerlerde hücresel ağ veritabanı gibi tahmini konum kaynaklarına erişir. Kötü amaçlı uygulamalar, bu işlevi bulunduğunuz yeri yaklaşık olarak belirlemek için kullanabilir."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger\'a eriş"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Uygulamanın SurfaceFlinger alt düzey özelliklerini kullanmasına izin verir."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"çerçeve arabelleğini oku"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Kullanılacak uygulamanın çerçeve arabelleğinin içeriğini okumasına izin verir."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ses ayarlarınızı değiştirin"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Uygulamaların, ses düzeyi ve yönlendirme gibi genel ses ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ses kaydet"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Uygulamanın, ses kayıt yoluna erişmesine izin verir."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"resim çek"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Uygulamaların kamera ile resim çekmesine izin verir. Bu işlev herhangi bir zamanda kameranın görmekte olduğu görüntüyü uygulamaların toplamasına izin verir."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"telefonu tamamen devre dışı bırak"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Uygulamaların tüm telefonu kalıcı olarak devre dışı bırakmasına izin verir. Bu çok tehlikelidir."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"telefonu yeniden başlamaya zorla"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Uygulamanın telefonu yeniden açılmaya zorlamasına izin verir."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"dosya sistemlerini bağla ve bağlantısını kes"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Uygulamaların çıkarılabilir depolama birimleri için dosya sistemleri ile bağlantı kurmasına ve bağlantıyı kesmesine izin verir."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"harici depolama birimini biçimlendir"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Uygulamanın çıkarılabilir depolama birimini biçimlendirmesine izin verir."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"titreşimi denetle"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Uygulamanın titreşimi denetlemesine izin verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"flaşı denetle"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"donanımı test et"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Uygulamanın donanım testi için çeşitli çevre birimlerini denetlemesine izin verir."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarını doğrudan ara"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Uygulamanın müdahaleniz olmadan telefon numaralarını aramasına izin verir. Kötü amaçlı uygulamalar, telefon faturanızda beklenmedik görüşmeler çıkmasına neden olabilir. Bu işlev, uygulamanın acil numara aramasına izin vermez."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"herhangi bir telefon numarasını doğrudan ara"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Uygulamanın, siz müdahale etmeden acil numaralar dahil herhangi bir numarayı aramasına izin verir. Kötü amaçlı uygulamalar acil servisleri gereksiz yere ve yasal olmayan şekilde arayabilir."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"konum güncelleme bildirimlerini denetle"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Radyo ile alınan konum güncelleme bildirimlerini etkinleştirmeye/devreden çıkarmaya izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"erişim giriş özellikleri"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Kayıt hizmeti tarafından karşıya yüklenen özelliklere okuma/yazma erişimi verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"widget seç"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Uygulamaların sisteme hangi uygulamalar tarafından hangi widget\'ların kullanılabileceğini söylemesine izin verir. Bu izin sayesinde uygulamalar, başka uygulamalara kişisel verilere erişim verebilir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefon durumunu değiştir"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Uygulamaların cihazın telefon özelliklerini kullanmasına izin verir. Bu izne sahip bir uygulama, size bildirmeden ağ değiştirebilir ve telefon radyosunu kapatıp açabilir."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"telefonunun uykuya geçmesini önle"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Uygulamaların telefonun uykuya geçmesini önlemesine izin verir."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"telefonu aç veya kapat"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Uygulamaların telefonunuzu açmasına veya kapatmasına izin verir."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"fabrika test modunda çalıştır"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Telefon donanımına tam erişim veren alt düzey bir üretici testi olarak çalıştırılır. Yalnızca telefon üretici test modunda çalışırken kullanılabilir."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"duvar kağıdını ayarla"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Uygulamanın sistem duvar kağıdını ayarlamasına izin verir."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"duvar kağıdı boyutu ipuçlarını ayarla"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Uygulamanın sistem duvar kağıdı boyutu ipuçlarını ayarlamasına izin verir."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"sistemi fabrika değerlerine sıfırla"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Uygulamanın, sistemi tamamen fabrika ayarlarına sıfırlamasına; verileri, yapılandırmayı ve yüklü uygulamaları silmesine izin verir."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"saat dilimini ayarla"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Uygulamaların telefonun saat dilimini değiştirmesine izin verir."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bilinen hesapları keşfet"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Uygulamaların telefonda bilinen hesapların listesini almasına izin verir."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ağ durumunu görüntüle"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Uygulamaların, tüm ağların durumunu görmesine izin verir."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"tam İnternet erişimi"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Uygulamaların ağ yuvaları oluşturmasına izin verir."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Erişim Noktası Adı ayarlarını yaz"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Uygulamaların herhangi bir APN\'nin Proxy ve Bağlantı Noktası gibi APN ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ağ bağlantısını değiştir"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Uygulamaların ağ bağlantı durumunu değiştirmesine izin verir."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"arka plan veri kullanımı ayarını değiştir"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Uygulamaların arka plan veri kullanımı ayarını değiştirmesine izin verir."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Kablosuz durumunu görüntüle"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Uygulamaların, kablosuz bağlantının durumu ile ilgili bilgileri görüntülemesine izin verir."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Kablosuz durumunu değiştir"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Uygulamaların kablosuz erişim noktalarına bağlanıp bunlarla bağlantısını kesmesine ve yapılandırılmış kablosuz ağlarda değişiklikler yapmasına izin verir."</string>
+ <string name="permlab_accessFineLocation">"iyi (GPS) konum"</string>
+ <string name="permdesc_accessFineLocation">"Bulunduğu yerlerde telefondan Küresel Konumlandırma Sistemi gibi hassas konum bulma kaynaklarına erişin. Kötü amaçlı uygulamalar bu işlevi bulunduğunuz yeri belirlemek için kullanabilir ve ek pil gücü tüketebilir."</string>
+ <string name="permlab_accessCoarseLocation">"kesinliksiz (ağ tabanlı) konum"</string>
+ <string name="permdesc_accessCoarseLocation">"Telefonun yaklaşık yerini belirlemek için bulunduğu yerlerde hücresel ağ veritabanı gibi tahmini konum kaynaklarına erişir. Kötü amaçlı uygulamalar, bu işlevi bulunduğunuz yeri yaklaşık olarak belirlemek için kullanabilir."</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlinger\'a eriş"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Uygulamanın SurfaceFlinger alt düzey özelliklerini kullanmasına izin verir."</string>
+ <string name="permlab_readFrameBuffer">"çerçeve arabelleğini oku"</string>
+ <string name="permdesc_readFrameBuffer">"Kullanılacak uygulamanın çerçeve arabelleğinin içeriğini okumasına izin verir."</string>
+ <string name="permlab_modifyAudioSettings">"ses ayarlarınızı değiştirin"</string>
+ <string name="permdesc_modifyAudioSettings">"Uygulamaların, ses düzeyi ve yönlendirme gibi genel ses ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_recordAudio">"ses kaydet"</string>
+ <string name="permdesc_recordAudio">"Uygulamanın, ses kayıt yoluna erişmesine izin verir."</string>
+ <string name="permlab_camera">"resim çek"</string>
+ <string name="permdesc_camera">"Uygulamaların kamera ile resim çekmesine izin verir. Bu işlev herhangi bir zamanda kameranın görmekte olduğu görüntüyü uygulamaların toplamasına izin verir."</string>
+ <string name="permlab_brick">"telefonu tamamen devre dışı bırak"</string>
+ <string name="permdesc_brick">"Uygulamaların tüm telefonu kalıcı olarak devre dışı bırakmasına izin verir. Bu çok tehlikelidir."</string>
+ <string name="permlab_reboot">"telefonu yeniden başlamaya zorla"</string>
+ <string name="permdesc_reboot">"Uygulamanın telefonu yeniden açılmaya zorlamasına izin verir."</string>
+ <string name="permlab_mount_unmount_filesystems">"dosya sistemlerini bağlama ve bağlantısını kesme"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Uygulamaların çıkarılabilir depolama birimleri için dosya sistemleri ile bağlantı kurmasına ve bağlantıyı kesmesine izin verir."</string>
+ <string name="permlab_mount_format_filesystems">"harici depolama birimini biçimlendir"</string>
+ <string name="permdesc_mount_format_filesystems">"Uygulamanın çıkarılabilir depolama birimini biçimlendirmesine izin verir."</string>
+ <string name="permlab_vibrate">"titreşimi denetle"</string>
+ <string name="permdesc_vibrate">"Uygulamanın titreşimi denetlemesine izin verir."</string>
+ <string name="permlab_flashlight">"flaşı denetle"</string>
+ <string name="permdesc_flashlight">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
+ <string name="permlab_hardware_test">"donanımı test et"</string>
+ <string name="permdesc_hardware_test">"Uygulamanın donanım testi için çeşitli çevre birimlerini denetlemesine izin verir."</string>
+ <string name="permlab_callPhone">"telefon numaralarını doğrudan ara"</string>
+ <string name="permdesc_callPhone">"Uygulamanın müdahaleniz olmadan telefon numaralarını aramasına izin verir. Kötü amaçlı uygulamalar, telefon faturanızda beklenmedik görüşmeler çıkmasına neden olabilir. Bu işlev, uygulamanın acil numara aramasına izin vermez."</string>
+ <string name="permlab_callPrivileged">"herhangi bir telefon numarasını doğrudan ara"</string>
+ <string name="permdesc_callPrivileged">"Uygulamanın, siz müdahale etmeden acil numaralar dahil herhangi bir numarayı aramasına izin verir. Kötü amaçlı uygulamalar acil servisleri gereksiz yere ve yasal olmayan şekilde arayabilir."</string>
+ <string name="permlab_locationUpdates">"konum güncelleme bildirimlerini denetle"</string>
+ <string name="permdesc_locationUpdates">"Radyo ile alınan konum güncelleme bildirimlerini etkinleştirmeye/devreden çıkarmaya izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_checkinProperties">"erişim giriş özellikleri"</string>
+ <string name="permdesc_checkinProperties">"Kayıt hizmeti tarafından karşıya yüklenen özelliklere okuma/yazma erişimi verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_bindGadget">"widget seç"</string>
+ <string name="permdesc_bindGadget">"Uygulamaların sisteme hangi uygulamalar tarafından hangi widget\'ların kullanılabileceğini söylemesine izin verir. Bu izin sayesinde uygulamalar, başka uygulamalara kişisel verilere erişim verebilir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_modifyPhoneState">"telefon durumunu değiştir"</string>
+ <string name="permdesc_modifyPhoneState">"Uygulamaların cihazın telefon özelliklerini kullanmasına izin verir. Bu izne sahip bir uygulama, size bildirmeden ağ değiştirebilir ve telefon radyosunu kapatıp açabilir."</string>
+ <string name="permlab_readPhoneState">"telefon durumunu oku"</string>
+ <string name="permdesc_readPhoneState">"Uygulamaların cihazın telefon özelliklerine erişmesine izin verir. Bu izne sahip bir uygulama telefonun telefon numarasını, o anda bir çağrı sürmekte olup olmadığını, çağrının bağlanmış olduğu numarayı ve benzerini belirleyebilir."</string>
+ <string name="permlab_wakeLock">"telefonunun uykuya geçmesini önle"</string>
+ <string name="permdesc_wakeLock">"Uygulamaların telefonun uykuya geçmesini önlemesine izin verir."</string>
+ <string name="permlab_devicePower">"telefonu aç veya kapat"</string>
+ <string name="permdesc_devicePower">"Uygulamaların telefonunuzu açmasına veya kapatmasına izin verir."</string>
+ <string name="permlab_factoryTest">"fabrika test modunda çalıştır"</string>
+ <string name="permdesc_factoryTest">"Telefon donanımına tam erişim veren alt düzey bir üretici testi olarak çalıştırılır. Yalnızca telefon üretici test modunda çalışırken kullanılabilir."</string>
+ <string name="permlab_setWallpaper">"duvar kağıdını ayarla"</string>
+ <string name="permdesc_setWallpaper">"Uygulamanın sistem duvar kağıdını ayarlamasına izin verir."</string>
+ <string name="permlab_setWallpaperHints">"duvar kağıdı boyutu ipuçlarını ayarla"</string>
+ <string name="permdesc_setWallpaperHints">"Uygulamanın sistem duvar kağıdı boyutu ipuçlarını ayarlamasına izin verir."</string>
+ <string name="permlab_masterClear">"sistemi fabrika değerlerine sıfırla"</string>
+ <string name="permdesc_masterClear">"Uygulamanın, sistemi tamamen fabrika ayarlarına sıfırlamasına; verileri, yapılandırmayı ve yüklü uygulamaları silmesine izin verir."</string>
+ <string name="permlab_setTimeZone">"saat dilimini ayarla"</string>
+ <string name="permdesc_setTimeZone">"Uygulamaların telefonun saat dilimini değiştirmesine izin verir."</string>
+ <string name="permlab_getAccounts">"bilinen hesapları keşfet"</string>
+ <string name="permdesc_getAccounts">"Uygulamaların telefonda bilinen hesapların listesini almasına izin verir."</string>
+ <string name="permlab_accessNetworkState">"ağ durumunu görüntüle"</string>
+ <string name="permdesc_accessNetworkState">"Uygulamaların, tüm ağların durumunu görmesine izin verir."</string>
+ <string name="permlab_createNetworkSockets">"tam İnternet erişimi"</string>
+ <string name="permdesc_createNetworkSockets">"Uygulamaların ağ yuvaları oluşturmasına izin verir."</string>
+ <string name="permlab_writeApnSettings">"Erişim Noktası Adı ayarlarını yaz"</string>
+ <string name="permdesc_writeApnSettings">"Uygulamaların herhangi bir APN\'nin Proxy ve Bağlantı Noktası gibi APN ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_changeNetworkState">"ağ bağlantısını değiştir"</string>
+ <string name="permdesc_changeNetworkState">"Uygulamaların ağ bağlantı durumunu değiştirmesine izin verir."</string>
+ <string name="permlab_changeBackgroundDataSetting">"arka plan veri kullanımı ayarını değiştir"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Uygulamaların arka plan veri kullanımı ayarını değiştirmesine izin verir."</string>
+ <string name="permlab_accessWifiState">"Kablosuz durumunu görüntüle"</string>
+ <string name="permdesc_accessWifiState">"Uygulamaların, kablosuz bağlantının durumu ile ilgili bilgileri görüntülemesine izin verir."</string>
+ <string name="permlab_changeWifiState">"Kablosuz durumunu değiştir"</string>
+ <string name="permdesc_changeWifiState">"Uygulamaların kablosuz erişim noktalarına bağlanıp bunlarla bağlantısını kesmesine ve yapılandırılmış kablosuz ağlarda değişiklikler yapmasına izin verir."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth yönetimi"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Uygulamaların yerel Bluetooth telefonunu yapılandırmasına ve uzak cihazları keşfedip bunlar ile eşleşmesine izin verir."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth bağlantıları oluştur"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Uygulamaların yerel Bluetooth telefonunun yapılandırmasını görüntülemesine ve eşleşilmiş cihazlar ile bağlantı kurup kabul etmesine izin verir."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"tuş kilidini devre dışı bırak"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Uygulamaların tuş kilidini ve ilgili şifreli güvenlik önlemini devre dışı bırakmasına izin verir. Bunun geçerli bir örneği gelen bir çağrı alındığında tuş kilidinin devre dışı bırakılması, sonra çağrı bittiğinde kilidin yeniden devreye sokulmasıdır."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"senk. ayarlarını oku"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını okumasına izin verir."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"senk. ayarlarını yaz"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"senk. istatistiklerini oku"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Uygulamaların senk. istatistiklerini; örn. geçmişte yapılmış senkronizasyonları okumasına izin verir."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abone olunan yayınları oku"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Uygulamaların, o anda senkronize olan yayınlar ile ilgili bilgi almasına izin verir."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abone olunan yayınları yaz"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Uygulamaların senkronize edilmiş yayınlarınızı değiştirmesine izin verir. Bu ayar, kötü amaçlı bir uygulamanın senkronize edilmiş yayınlarınızı değiştirmesine izin verebilir."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"kullanıcı tanımlı sözlüğü oku"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Kullanıcının kullanıcı sözlüğünde depolamış olabileceği kişisel kelimeleri, adları ve kelime öbeklerini uygulamaların okumasına izin verir."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"kullanıcı tanımlı sözlüğe yaz"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Uygulamaların kullanıcı sözlüğüne yeni kelimeler yazmasına izin verir."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth yönetimi"</string>
+ <string name="permdesc_bluetoothAdmin">"Uygulamaların yerel Bluetooth telefonunu yapılandırmasına ve uzak cihazları keşfedip bunlar ile eşleşmesine izin verir."</string>
+ <string name="permlab_bluetooth">"Bluetooth bağlantıları oluştur"</string>
+ <string name="permdesc_bluetooth">"Uygulamaların yerel Bluetooth telefonunun yapılandırmasını görüntülemesine ve eşleşilmiş cihazlar ile bağlantı kurup kabul etmesine izin verir."</string>
+ <string name="permlab_disableKeyguard">"tuş kilidini devre dışı bırak"</string>
+ <string name="permdesc_disableKeyguard">"Uygulamaların tuş kilidini ve ilgili şifreli güvenlik önlemini devre dışı bırakmasına izin verir. Bunun geçerli bir örneği gelen bir çağrı alındığında tuş kilidinin devre dışı bırakılması, sonra çağrı bittiğinde kilidin yeniden devreye sokulmasıdır."</string>
+ <string name="permlab_readSyncSettings">"senk. ayarlarını oku"</string>
+ <string name="permdesc_readSyncSettings">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını okumasına izin verir."</string>
+ <string name="permlab_writeSyncSettings">"senk. ayarlarını yaz"</string>
+ <string name="permdesc_writeSyncSettings">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_readSyncStats">"senk. istatistiklerini oku"</string>
+ <string name="permdesc_readSyncStats">"Uygulamaların senk. istatistiklerini; örn. geçmişte yapılmış senkronizasyonları okumasına izin verir."</string>
+ <string name="permlab_subscribedFeedsRead">"abone olunan yayınları oku"</string>
+ <string name="permdesc_subscribedFeedsRead">"Uygulamaların, o anda senkronize olan yayınlar ile ilgili bilgi almasına izin verir."</string>
+ <string name="permlab_subscribedFeedsWrite">"abone olunan yayınları yaz"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Uygulamaların senkronize edilmiş yayınlarınızı değiştirmesine izin verir. Bu ayar, kötü amaçlı bir uygulamanın senkronize edilmiş yayınlarınızı değiştirmesine izin verebilir."</string>
+ <string name="permlab_readDictionary">"kullanıcı tanımlı sözlüğü oku"</string>
+ <string name="permdesc_readDictionary">"Kullanıcının kullanıcı sözlüğünde depolamış olabileceği kişisel kelimeleri, adları ve kelime öbeklerini uygulamaların okumasına izin verir."</string>
+ <string name="permlab_writeDictionary">"kullanıcı tanımlı sözlüğe yaz"</string>
+ <string name="permdesc_writeDictionary">"Uygulamaların kullanıcı sözlüğüne yeni kelimeler yazmasına izin verir."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Ev"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"İş"</item>
- <item msgid="1103601433382158155">"İş Faks"</item>
- <item msgid="1735177144948329370">"Ev Faks"</item>
- <item msgid="603878674477207394">"Çağrı cihazı"</item>
- <item msgid="1650824275177931637">"Diğer"</item>
- <item msgid="9192514806975898961">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"Mobil"</item>
+ <item>"İş"</item>
+ <item>"İş Faks"</item>
+ <item>"Ev Faks"</item>
+ <item>"Çağrı cihazı"</item>
+ <item>"Diğer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Ev"</item>
- <item msgid="7084237356602625604">"İş"</item>
- <item msgid="1112044410659011023">"Diğer"</item>
- <item msgid="2374913952870110618">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"İş"</item>
+ <item>"Diğer"</item>
+ <item>"Özel"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Ev"</item>
- <item msgid="5629153956045109251">"İş"</item>
- <item msgid="4966604264500343469">"Diğer"</item>
- <item msgid="4932682847595299369">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"İş"</item>
+ <item>"Diğer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Ev"</item>
- <item msgid="1359644565647383708">"İş"</item>
- <item msgid="7868549401053615677">"Diğer"</item>
- <item msgid="3145118944639869809">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"İş"</item>
+ <item>"Diğer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"İş"</item>
- <item msgid="4378074129049520373">"Diğer"</item>
- <item msgid="3455047468583965104">"Özel"</item>
+ <item>"İş"</item>
+ <item>"Diğer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN kodunu gir"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Yanlış PIN kodu!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Acil durum numarası"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Hizmet yok)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran kilitli."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Kilidi açmak için Menü\'ye basın."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Kilit açmak için deseni çizin"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Acil durum çağrısı"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Doğru!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Üzgünüz, lütfen yeniden deneyin"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Şarj oluyor (<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN kodunu gir"</string>
+ <string name="keyguard_password_wrong_pin_code">"Yanlış PIN kodu!"</string>
+ <string name="keyguard_label_text">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
+ <string name="emergency_call_dialog_number_for_display">"Acil durum numarası"</string>
+ <string name="lockscreen_carrier_default">"(Hizmet yok)"</string>
+ <string name="lockscreen_screen_locked">"Ekran kilitli."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Kilidi açmak için Menü\'ye basın."</string>
+ <string name="lockscreen_pattern_instructions">"Kilit açmak için deseni çizin"</string>
+ <string name="lockscreen_emergency_call">"Acil durum çağrısı"</string>
+ <string name="lockscreen_pattern_correct">"Doğru!"</string>
+ <string name="lockscreen_pattern_wrong">"Üzgünüz, lütfen yeniden deneyin"</string>
+ <string name="lockscreen_plugged_in">"Şarj oluyor (<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Şarj cihazınızı bağlayın."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIM kart yok."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Telefonda SIM kart yok."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Lütfen SIM kart takın."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Ağ kilitli"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM kart PUK kilidi devrede."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Lütfen Kullanıcı Rehberi\'ne bakın veya Müşteri Hizmetleri\'ne başvurun."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kart kilitli."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM kart kilidi açılıyor…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Deseni unuttunuz mu?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Çok fazla sayıda desen denemesi yapıldı!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Kilidi açmak için Google hesabınızla oturum açın"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Kullanıcı adı (e-posta)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Şifre"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Oturum aç"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Geçersiz kullanıcı adı veya şifre."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Şarj cihazınızı bağlayın."</string>
+ <string name="lockscreen_missing_sim_message_short">"SIM kart yok."</string>
+ <string name="lockscreen_missing_sim_message">"Telefonda SIM kart yok."</string>
+ <string name="lockscreen_missing_sim_instructions">"Lütfen SIM kart takın."</string>
+ <string name="lockscreen_network_locked_message">"Ağ kilitli"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM kart PUK kilidi devrede."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Lütfen Kullanıcı Rehberi\'ne bakın veya Müşteri Hizmetleri\'ne başvurun."</string>
+ <string name="lockscreen_sim_locked_message">"SIM kart kilitli."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM kart kilidi açılıyor…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Deseni unuttunuz mu?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Çok fazla sayıda desen denemesi yapıldı!"</string>
+ <string name="lockscreen_glogin_instructions">"Kilidi açmak için Google hesabınızla oturum açın"</string>
+ <string name="lockscreen_glogin_username_hint">"Kullanıcı adı (e-posta)"</string>
+ <string name="lockscreen_glogin_password_hint">"Şifre"</string>
+ <string name="lockscreen_glogin_submit_button">"Oturum aç"</string>
+ <string name="lockscreen_glogin_invalid_input">"Geçersiz kullanıcı adı veya şifre."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Şarj oluyor…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Lütfen şarj cihazını takın"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Pil tükeniyor:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"<xliff:g id="NUMBER">%d%%</xliff:g> adetten daha az kaldı."</string>
+ <string name="status_bar_no_notifications_title">"Bildirim yok"</string>
+ <string name="status_bar_ongoing_events_title">"Sürüyor"</string>
+ <string name="status_bar_latest_events_title">"Bildirimler"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Şarj oluyor…"</string>
+ <string name="battery_low_title">"Lütfen şarj cihazını takın"</string>
+ <string name="battery_low_subtitle">"Pil tükeniyor:"</string>
+ <string name="battery_low_percent_format">"<xliff:g id="NUMBER">%d%%</xliff:g> adetten daha az kaldı."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabrika testi yapılamadı"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST işlemi yalnızca /system/app dizinine yüklenmiş paketler için desteklenir."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST işlemini sağlayan hiçbir paket bulunamadı."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Yeniden başlat"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada şunlar belirtiliyor:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, sayfada kalmak için İptal\'i tıklatın."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
+ <string name="factorytest_failed">"Fabrika testi yapılamadı"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST işlemi yalnızca /system/app dizinine yüklenmiş paketler için desteklenir."</string>
+ <string name="factorytest_no_action">"FACTORY_TEST işlemini sağlayan hiçbir paket bulunamadı."</string>
+ <string name="factorytest_reboot">"Yeniden başlat"</string>
+ <string name="js_dialog_title">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada şunlar belirtiliyor:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, sayfada kalmak için İptal\'i tıklatın."</string>
+ <string name="save_password_label">"Onayla"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Hiçbir zaman"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Bu sayfayı açma izniniz yok."</string>
- <string name="text_copied" msgid="4985729524670131385">"Metin panoya kopyalandı."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Diğer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"boşluk"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"gir"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"sil"</string>
- <string name="search_go" msgid="8298016669822141719">"Ara"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
+ <string name="save_password_message">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
+ <string name="save_password_notnow">"Şimdi değil"</string>
+ <string name="save_password_remember">"Anımsa"</string>
+ <string name="save_password_never">"Hiçbir zaman"</string>
+ <string name="open_permission_deny">"Bu sayfayı açma izniniz yok."</string>
+ <string name="text_copied">"Metin panoya kopyalandı."</string>
+ <string name="more_item_label">"Diğer"</string>
+ <string name="prepend_shortcut_label">"Menü+"</string>
+ <string name="menu_space_shortcut_label">"boşluk"</string>
+ <string name="menu_enter_shortcut_label">"gir"</string>
+ <string name="menu_delete_shortcut_label">"sil"</string>
+ <string name="search_go">"Ara"</string>
+ <string name="oneMonthDurationPast">"1 ay önce"</string>
+ <string name="beforeOneMonthDurationPast">"1 ay önce"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 saniye önce"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
+ <item quantity="one">"1 saniye önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 dakika önce"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
+ <item quantity="one">"1 dakika önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 saat önce"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
+ <item quantity="one">"1 saat önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"dün"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
+ <item quantity="one">"dün"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 saniye içinde"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
+ <item quantity="one">"1 saniye içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 dakika içinde"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
+ <item quantity="one">"1 dakika içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 saat içinde"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
+ <item quantity="one">"1 saat içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"yarın"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
+ <item quantity="one">"yarın"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 saniye önce"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
+ <item quantity="one">"1 saniye önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 dak. önce"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
+ <item quantity="one">"1 dak. önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 saat önce"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
+ <item quantity="one">"1 saat önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"dün"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
+ <item quantity="one">"dün"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 san. içinde"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
+ <item quantity="one">"1 san. içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 dak. içinde"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
+ <item quantity="one">"1 dak. içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 saat içinde"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
+ <item quantity="one">"1 saat içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"yarın"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
+ <item quantity="one">"yarın"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s üzerinde"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"saat: %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s içinde"</string>
- <string name="day" msgid="8144195776058119424">"gün"</string>
- <string name="days" msgid="4774547661021344602">"gün"</string>
- <string name="hour" msgid="2126771916426189481">"saat"</string>
- <string name="hours" msgid="894424005266852993">"saat"</string>
- <string name="minute" msgid="9148878657703769868">"dak"</string>
- <string name="minutes" msgid="5646001005827034509">"dakika"</string>
- <string name="second" msgid="3184235808021478">"san."</string>
- <string name="seconds" msgid="3161515347216589235">"saniye"</string>
- <string name="week" msgid="5617961537173061583">"hafta"</string>
- <string name="weeks" msgid="6509623834583944518">"hafta"</string>
- <string name="year" msgid="4001118221013892076">"yıl"</string>
- <string name="years" msgid="6881577717993213522">"yıl"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hafta içi her gün (Pzt-Cum)"</string>
- <string name="daily" msgid="5738949095624133403">"Her gün"</string>
- <string name="weekly" msgid="983428358394268344">"Her hafta <xliff:g id="DAY">%s</xliff:g> günü"</string>
- <string name="monthly" msgid="2667202947170988834">"Aylık"</string>
- <string name="yearly" msgid="1519577999407493836">"Yılda bir"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video oynatılamıyor"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Maalesef, bu video cihaza akışla göndermek için uygun değil."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Maalesef bu video oynatılamıyor."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Tamam"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"öğle"</string>
- <string name="Noon" msgid="3342127745230013127">"Öğle"</string>
- <string name="midnight" msgid="7166259508850457595">"geceyarısı"</string>
- <string name="Midnight" msgid="5630806906897892201">"Gece Yarısı"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string>
- <string name="selectText" msgid="3889149123626888637">"Metni seç"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Metin seçmeyi durdur"</string>
- <string name="cut" msgid="3092569408438626261">"Kes"</string>
- <string name="cutAll" msgid="2436383270024931639">"Tümünü kes"</string>
- <string name="copy" msgid="2681946229533511987">"Kopyala"</string>
- <string name="copyAll" msgid="2590829068100113057">"Tümünü kopyala"</string>
- <string name="paste" msgid="5629880836805036433">"Yapıştır"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL\'yi kopyala"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Giriş Yöntemi"</string>
- <string name="addToDictionary" msgid="726256909274177272">"\"%s\" kelimesini sözlüğe ekle"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Metin düzenle"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Yer az"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Telefonun depolama alanı azalıyor."</string>
- <string name="ok" msgid="5970060430562524910">"Tamam"</string>
- <string name="cancel" msgid="6442560571259935130">"İptal"</string>
- <string name="yes" msgid="5362982303337969312">"Tamam"</string>
- <string name="no" msgid="5141531044935541497">"İptal"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Dikkat"</string>
- <string name="capital_on" msgid="1544682755514494298">"AÇIK"</string>
- <string name="capital_off" msgid="6815870386972805832">"KAPALI"</string>
- <string name="whichApplication" msgid="4533185947064773386">"İşlemi şunu kullanarak tamamla"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Varsayılan olarak bu işlem için kullan."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Giriş Ayarları > Uygulamalar > Uygulamaları yönet\'te varsayılanı temizleyin."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"İşlem seç"</string>
- <string name="noApplications" msgid="1691104391758345586">"Hiçbir uygulama bu işlemi yapamaz."</string>
- <string name="aerr_title" msgid="653922989522758100">"Üzgünüz!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
- <string name="anr_title" msgid="3100070910664756057">"Üzgünüz!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasında) yanıt vermiyor."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
- <string name="force_close" msgid="3653416315450806396">"Kapanmaya zorla"</string>
+ <string name="preposition_for_date">"%s üzerinde"</string>
+ <string name="preposition_for_time">"saat: %s"</string>
+ <string name="preposition_for_year">"%s içinde"</string>
+ <string name="day">"gün"</string>
+ <string name="days">"gün"</string>
+ <string name="hour">"saat"</string>
+ <string name="hours">"saat"</string>
+ <string name="minute">"dak"</string>
+ <string name="minutes">"dakika"</string>
+ <string name="second">"san."</string>
+ <string name="seconds">"saniye"</string>
+ <string name="week">"hafta"</string>
+ <string name="weeks">"hafta"</string>
+ <string name="year">"yıl"</string>
+ <string name="years">"yıl"</string>
+ <string name="every_weekday">"Hafta içi her gün (Pzt-Cum)"</string>
+ <string name="daily">"Günlük"</string>
+ <string name="weekly">"Her hafta <xliff:g id="DAY">%s</xliff:g> günü"</string>
+ <string name="monthly">"Aylık"</string>
+ <string name="yearly">"Yılda bir"</string>
+ <string name="VideoView_error_title">"Video oynatılamıyor"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Maalesef, bu video cihaza akışla göndermek için uygun değil."</string>
+ <string name="VideoView_error_text_unknown">"Maalesef bu video oynatılamıyor."</string>
+ <string name="VideoView_error_button">"Tamam"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"öğle"</string>
+ <string name="Noon">"Öğle"</string>
+ <string name="midnight">"geceyarısı"</string>
+ <string name="Midnight">"Gece Yarısı"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Tümünü seç"</string>
+ <string name="selectText">"Metni seç"</string>
+ <string name="stopSelectingText">"Metin seçmeyi durdur"</string>
+ <string name="cut">"Kes"</string>
+ <string name="cutAll">"Tümünü kes"</string>
+ <string name="copy">"Kopyala"</string>
+ <string name="copyAll">"Tümünü kopyala"</string>
+ <string name="paste">"Yapıştır"</string>
+ <string name="copyUrl">"URL\'yi kopyala"</string>
+ <string name="inputMethod">"Giriş Yöntemi"</string>
+ <string name="addToDictionary">"\"%s\" kelimesini sözlüğe ekle"</string>
+ <string name="editTextMenuTitle">"Metin düzenle"</string>
+ <string name="low_internal_storage_view_title">"Yer az"</string>
+ <string name="low_internal_storage_view_text">"Telefonun depolama alanı azalıyor."</string>
+ <string name="ok">"Tamam"</string>
+ <string name="cancel">"İptal"</string>
+ <string name="yes">"Tamam"</string>
+ <string name="no">"İptal"</string>
+ <string name="dialog_alert_title">"Dikkat"</string>
+ <string name="capital_on">"AÇIK"</string>
+ <string name="capital_off">"KAPALI"</string>
+ <string name="whichApplication">"İşlemi şunu kullanarak tamamla"</string>
+ <string name="alwaysUse">"Varsayılan olarak bu işlem için kullan."</string>
+ <string name="clearDefaultHintMsg">"Giriş Ayarları > Uygulamalar > Uygulamaları yönet\'te varsayılanı temizleyin."</string>
+ <string name="chooseActivity">"İşlem seç"</string>
+ <string name="noApplications">"Hiçbir uygulama bu işlemi yapamaz."</string>
+ <string name="aerr_title">"Üzgünüz!"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
+ <string name="anr_title">"Üzgünüz!"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasında) yanıt vermiyor."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
+ <string name="force_close">"Kapanmaya zorla"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Bekle"</string>
- <string name="debug" msgid="9103374629678531849">"Hata ayıkla"</string>
- <string name="sendText" msgid="5132506121645618310">"Metin için bir işlem seçin"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Zil sesi düzeyi"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medya ses düzeyi"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth üzerinden çalıyor"</string>
- <string name="volume_call" msgid="3941680041282788711">"Gelen çağrı ses düzeyi"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth gelen çağrı ses düzeyi"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarm ses düzeyi"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Bildirim ses düzeyi"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Ses"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Varsayılan zil sesi"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Sessiz"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Bilinmeyen zil sesi"</string>
+ <string name="wait">"Bekle"</string>
+ <string name="debug">"Hata ayıkla"</string>
+ <string name="sendText">"Metin için bir işlem seçin"</string>
+ <string name="volume_ringtone">"Zil sesi düzeyi"</string>
+ <string name="volume_music">"Medya ses düzeyi"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth üzerinden çalıyor"</string>
+ <string name="volume_call">"Gelen çağrı ses düzeyi"</string>
+ <string name="volume_bluetooth_call">"Bluetooth gelen çağrı ses düzeyi"</string>
+ <string name="volume_alarm">"Alarm ses düzeyi"</string>
+ <string name="volume_notification">"Bildirim ses düzeyi"</string>
+ <string name="volume_unknown">"Ses"</string>
+ <string name="ringtone_default">"Varsayılan zil sesi"</string>
+ <string name="ringtone_default_with_actual">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Sessiz"</string>
+ <string name="ringtone_picker_title">"Zil sesleri"</string>
+ <string name="ringtone_unknown">"Bilinmeyen zil sesi"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Kablosuz ağ var"</item>
- <item quantity="other" msgid="4192424489168397386">"Kablosuz ağlar var"</item>
+ <item quantity="one">"Kablosuz ağ var"</item>
+ <item quantity="other">"Kablosuz ağlar var"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Kullanılabilir kablosuz ağı aç"</item>
- <item quantity="other" msgid="7915895323644292768">"Kullanılabilir kablosuz ağları aç"</item>
+ <item quantity="one">"Kullanılabilir kablosuz ağı aç"</item>
+ <item quantity="other">"Kullanılabilir kablosuz ağları aç"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Bilinmeyen uygulama"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için \"Tamam\"ı, göndermeyi durdurmak için \"İptal\"i seçin."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Tamam"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"İptal"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Varsayılan"</string>
- <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Gizle"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Tümünü göster"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Yükleniyor…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB bağlandı"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Telefonunuzu bilgisayarınıza USB ile bağladınız. Bilgisayarınız ve telefonunuzun SD kartı arasında dosya kopyalamak istiyorsanız, \"Bağla\"\'yı seçin."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Bağla"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Bağlama"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"SD kartınızı USB depolama birimi için kullanmada bir sorun var."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB bağlandı"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Bilgisayarınıza/bilgisayarınızdan dosya kopyalamak için seçin."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB depolama birimini kapat"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB depolama birimini kapatmak için seçin."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB depolama birimini kapat"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USB depolama birimini kapatmadan önce USB ana makinesinde bağlantıyı kestiğinizden emin olun. USB depolama birimini kapatmak için \"Kapat\"ı seçin."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Kapat"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"İptal"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USB depolama birimini kapatırken bir sorunla karşılaştık. USB ana makinesinde bağlantıyı kestiğinizden emin olun, sonra yeniden deneyin."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD kartı biçimlendir"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Biçimlendir"</string>
+ <string name="select_character">"Karakter ekle"</string>
+ <string name="sms_control_default_app_name">"Bilinmeyen uygulama"</string>
+ <string name="sms_control_title">"SMS mesajları gönderme"</string>
+ <string name="sms_control_message">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için \"Tamam\"ı, göndermeyi durdurmak için \"İptal\"i seçin."</string>
+ <string name="sms_control_yes">"Tamam"</string>
+ <string name="sms_control_no">"İptal"</string>
+ <string name="date_time_set">"Ayarla"</string>
+ <string name="default_permission_group">"Varsayılan"</string>
+ <string name="no_permissions">"İzin gerektirmez"</string>
+ <string name="perms_hide"><b>"Gizle"</b></string>
+ <string name="perms_show_all"><b>"Tümünü göster"</b></string>
+ <string name="googlewebcontenthelper_loading">"Yükleniyor…"</string>
+ <string name="usb_storage_title">"USB bağlandı"</string>
+ <string name="usb_storage_message">"Telefonunuzu bilgisayarınıza USB ile bağladınız. Bilgisayarınız ve telefonunuzun SD kartı arasında dosya kopyalamak istiyorsanız, \"Bağla\"\'yı seçin."</string>
+ <string name="usb_storage_button_mount">"Bağla"</string>
+ <string name="usb_storage_button_unmount">"Bağlama"</string>
+ <string name="usb_storage_error_message">"SD kartınızı USB depolama birimi için kullanmada bir sorun var."</string>
+ <string name="usb_storage_notification_title">"USB bağlandı"</string>
+ <string name="usb_storage_notification_message">"Bilgisayarınıza/bilgisayarınızdan dosya kopyalamak için seçin."</string>
+ <string name="usb_storage_stop_notification_title">"USB depolama birimini kapat"</string>
+ <string name="usb_storage_stop_notification_message">"USB depolama birimini kapatmak için seçin."</string>
+ <string name="usb_storage_stop_title">"USB depolama birimini kapat"</string>
+ <string name="usb_storage_stop_message">"USB depolama birimini kapatmadan önce USB ana makinesinde bağlantıyı kestiğinizden emin olun. USB depolama birimini kapatmak için \"Kapat\"ı seçin."</string>
+ <string name="usb_storage_stop_button_mount">"Kapat"</string>
+ <string name="usb_storage_stop_button_unmount">"İptal"</string>
+ <string name="usb_storage_stop_error_message">"USB depolama birimini kapatırken bir sorunla karşılaştık. USB ana makinesinde bağlantıyı kestiğinizden emin olun, sonra yeniden deneyin."</string>
+ <string name="extmedia_format_title">"SD kartı biçimlendir"</string>
+ <string name="extmedia_format_message">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string>
+ <string name="extmedia_format_button_format">"Biçimlendir"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Giriş Yöntemini Seç"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD kart hazırlanıyor"</string>
+ <string name="select_input_method">"Giriş Yöntemini Seç"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"adaylar"</u></string>
+ <string name="ext_media_checking_notification_title">"SD kart hazırlanıyor"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Boş SD kart"</string>
+ <string name="ext_media_nofs_notification_title">"Boş SD kart"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Hasarlı SD kart"</string>
+ <string name="ext_media_unmountable_notification_title">"Hasarlı SD kart"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD kart beklenmedik biçimde çıkarıldı"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Veri kaybından kaçınmak için SD kartı çıkarmadan önce bağlantısını kesin."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD kart güvenle çıkarılabilir"</string>
+ <string name="ext_media_badremoval_notification_title">"SD kart beklenmedik biçimde çıkarıldı"</string>
+ <string name="ext_media_badremoval_notification_message">"Veri kaybından kaçınmak için SD kartı çıkarmadan önce bağlantısını kesin."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD kart güvenle çıkarılabilir"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD kart çıkarılmış"</string>
+ <string name="ext_media_nomedia_notification_title">"SD kart çıkarılmış"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Eşleşen hiçbir etkinlik bulunamadı"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"bileşen kullanım istatistiklerini güncelle"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Toplanmış bileşen istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zum denetimi için iki kez dokun"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Widget\'ı genişletirken hata oluştu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Git"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Ara"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Gönder"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"İleri"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Bitti"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Çalıştır"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Numarayı çevir:"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>"\n" ile kişi oluştur"</string>
+ <string name="activity_list_empty">"Eşleşen hiçbir etkinlik bulunamadı"</string>
+ <string name="permlab_pkgUsageStats">"bileşen kullanım istatistiklerini güncelle"</string>
+ <string name="permdesc_pkgUsageStats">"Toplanmış bileşen istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Zum denetimi için iki kez dokun"</string>
+ <string name="gadget_host_error_inflating">"Widget\'ı genişletirken hata oluştu"</string>
+ <string name="ime_action_go">"Git"</string>
+ <string name="ime_action_search">"Ara"</string>
+ <string name="ime_action_send">"Gönder"</string>
+ <string name="ime_action_next">"İleri"</string>
+ <string name="ime_action_done">"Bitti"</string>
+ <string name="ime_action_default">"Çalıştır"</string>
+ <string name="dial_number_using">"Numarayı çevir:"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"<xliff:g id="NUMBER">%s</xliff:g>"\n" ile kişi oluştur"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c7eb522..6741b3b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"<无标题>"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(无电话号码)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(未知)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"语音信箱"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"出现连接问题或 MMI 码无效。"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"服务已启用。"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"已针对以下内容启用了服务:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"服务已被停用。"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"注册成功。"</string>
- <string name="serviceErased" msgid="1288584695297200972">"清除成功。"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"密码不正确。"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 完成。"</string>
- <string name="badPin" msgid="5085454289896032547">"您输入的旧 PIN 不正确。"</string>
- <string name="badPuk" msgid="5702522162746042460">"您输入的 PUK 不正确。"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"您输入的 PIN 码不一致。"</string>
- <string name="invalidPin" msgid="3850018445187475377">"输入一个 4 至 8 位数的 PIN。"</string>
- <string name="needPuk" msgid="919668385956251611">"您的 SIM 卡被 PUK 锁定。请输入 PUK 码进行解锁。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"输入 PUK2 以解锁 SIM 卡。"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"来电显示"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"外拨电话显示"</string>
- <string name="CfMmi" msgid="5123218989141573515">"呼叫转接"</string>
- <string name="CwMmi" msgid="9129678056795016867">"呼叫等待"</string>
- <string name="BaMmi" msgid="455193067926770581">"呼叫限制"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"密码更改"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN 码更改"</string>
+ <string name="untitled">"<无标题>"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(无电话号码)"</string>
+ <string name="unknownName">"(未知)"</string>
+ <string name="defaultVoiceMailAlphaTag">"语音信箱"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"出现连接问题或 MMI 码无效。"</string>
+ <string name="serviceEnabled">"服务已启用。"</string>
+ <string name="serviceEnabledFor">"已针对以下内容启用了服务:"</string>
+ <string name="serviceDisabled">"服务已被停用。"</string>
+ <string name="serviceRegistered">"注册成功。"</string>
+ <string name="serviceErased">"清除成功。"</string>
+ <string name="passwordIncorrect">"密码不正确。"</string>
+ <string name="mmiComplete">"MMI 完成。"</string>
+ <string name="badPin">"您输入的旧 PIN 不正确。"</string>
+ <string name="badPuk">"您输入的 PUK 不正确。"</string>
+ <string name="mismatchPin">"您输入的 PIN 码不一致。"</string>
+ <string name="invalidPin">"输入一个 4 至 8 位数的 PIN。"</string>
+ <string name="needPuk">"您的 SIM 卡被 PUK 锁定。请输入 PUK 码进行解锁。"</string>
+ <string name="needPuk2">"输入 PUK2 以解锁 SIM 卡。"</string>
+ <string name="ClipMmi">"收到来电显示"</string>
+ <string name="ClirMmi">"外拨电话显示"</string>
+ <string name="CfMmi">"呼叫转接"</string>
+ <string name="CwMmi">"呼叫等待"</string>
+ <string name="BaMmi">"呼叫限制"</string>
+ <string name="PwdMmi">"密码更改"</string>
+ <string name="PinMmi">"PIN 码更改"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"来电显示默认设置为受限制。下一个呼叫:受限制"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"来电显示默认设置为受限制。下一个呼叫:不受限制"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"来电显示默认设置为不受限制。下一个呼叫:受限制"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"来电显示默认设置为不受限制。下一个呼叫:不受限制"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"无法更改来电显示设置。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"访问受限情况已发生变化"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"数据服务已禁用。"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已禁用。"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"语音/短信服务已禁用。"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"所有语音/短信服务均已禁用。"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"语音"</string>
- <string name="serviceClassData" msgid="872456782077937893">"数据"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"传真"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"短信"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"异步"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"同步"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"封包"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"来电显示默认设置为受限制。下一个呼叫:受限制"</string>
+ <string name="CLIRDefaultOnNextCallOff">"来电显示默认设置为受限制。下一个呼叫:不受限制"</string>
+ <string name="CLIRDefaultOffNextCallOn">"来电显示默认设置为不受限制。下一个呼叫:受限制"</string>
+ <string name="CLIRDefaultOffNextCallOff">"来电显示默认设置为不受限制。下一个呼叫:不受限制"</string>
+ <string name="serviceNotProvisioned">"未提供服务。"</string>
+ <string name="CLIRPermanent">"无法更改来电显示设置。"</string>
+ <string name="RestrictedChangedTitle">"访问受限情况已发生变化"</string>
+ <string name="RestrictedOnData">"数据服务已禁用。"</string>
+ <string name="RestrictedOnEmergency">"紧急服务已禁用。"</string>
+ <string name="RestrictedOnNormal">"语音/短信服务已禁用。"</string>
+ <string name="RestrictedOnAll">"所有语音/短信服务均已禁用。"</string>
+ <string name="serviceClassVoice">"语音"</string>
+ <string name="serviceClassData">"数据"</string>
+ <string name="serviceClassFAX">"传真"</string>
+ <string name="serviceClassSMS">"短信"</string>
+ <string name="serviceClassDataAsync">"异步"</string>
+ <string name="serviceClassDataSync">"同步"</string>
+ <string name="serviceClassPacket">"封包"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒后拨打 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒后拨打 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"确定"</string>
- <string name="httpError" msgid="2567300624552921790">"网页包含错误。"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"找不到网址。"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"不支持此网站身份验证方案。"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"身份验证失败。"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"通过代理服务器进行身份验证失败。"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"未能连接到服务器。"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"服务器无法通信,请稍后重试。"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"与服务器的连接超时。"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"网页包含过多服务器重定向。"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"不支持该协议。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"无法建立安全连接。"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"网址无效,此网页无法打开。"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"无法访问该文件。"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"找不到请求的文件。"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"正在处理的请求太多,请稍后重试。"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"同步"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
- <string name="low_memory" msgid="6632412458436461203">"手机存储空间已满!请删除一些文件来腾出空间。"</string>
- <string name="me" msgid="6545696007631404292">"我"</string>
- <string name="power_dialog" msgid="1319919075463988638">"手机选项"</string>
- <string name="silent_mode" msgid="7167703389802618663">"静音模式"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"打开无线电"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"关闭无线电"</string>
- <string name="screen_lock" msgid="799094655496098153">"屏幕锁定"</string>
- <string name="power_off" msgid="4266614107412865048">"关机"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"正在关机..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"您的手机会关闭。"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"无最近的应用程序。"</string>
- <string name="global_actions" msgid="2406416831541615258">"手机选项"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"静音模式"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"声音已“关闭”"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"声音已“开启”"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飞行模式已开启"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飞行模式已关闭"</string>
- <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"允许应用程序执行可能需要您付费的操作。"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"您的消息"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"读/写短信、电子邮件和其他消息。"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"您的个人信息"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"直接访问手机上存储的联系人和日历。"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"您的位置"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"监视您的物理位置"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"网络通信"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"允许应用程序访问各种网络功能。"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"您的 Google 帐户"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"访问可用的 Google 帐户。"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬件控制"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"直接访问手机上的硬件。"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"手机通话"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"监视、记录和处理电话。"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"系统工具"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"对系统的低级别访问和控制。"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"开发工具"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"只有应用程序开发人员需要这些功能。"</string>
+ <string name="httpErrorOk">"确定"</string>
+ <string name="httpError">"网页包含错误。"</string>
+ <string name="httpErrorLookup">"找不到网址。"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"不支持此网站身份验证方案。"</string>
+ <string name="httpErrorAuth">"身份验证失败。"</string>
+ <string name="httpErrorProxyAuth">"通过代理服务器进行身份验证失败。"</string>
+ <string name="httpErrorConnect">"未能连接到服务器。"</string>
+ <string name="httpErrorIO">"服务器无法通信,请稍后重试。"</string>
+ <string name="httpErrorTimeout">"与服务器的连接超时。"</string>
+ <string name="httpErrorRedirectLoop">"网页包含过多服务器重定向。"</string>
+ <string name="httpErrorUnsupportedScheme">"不支持该协议。"</string>
+ <string name="httpErrorFailedSslHandshake">"无法建立安全连接。"</string>
+ <string name="httpErrorBadUrl">"网址无效,此网页无法打开。"</string>
+ <string name="httpErrorFile">"无法访问该文件。"</string>
+ <string name="httpErrorFileNotFound">"找不到请求的文件。"</string>
+ <string name="httpErrorTooManyRequests">"正在处理的请求太多,请稍后重试。"</string>
+ <string name="contentServiceSync">"同步"</string>
+ <string name="contentServiceSyncNotificationTitle">"同步"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
+ <string name="low_memory">"手机存储空间已满!请删除一些文件来腾出空间。"</string>
+ <string name="me">"我"</string>
+ <string name="power_dialog">"手机选项"</string>
+ <string name="silent_mode">"静音模式"</string>
+ <string name="turn_on_radio">"打开收音机"</string>
+ <string name="turn_off_radio">"关闭收音机"</string>
+ <string name="screen_lock">"屏幕锁定"</string>
+ <string name="power_off">"关机"</string>
+ <string name="shutdown_progress">"正在关机..."</string>
+ <string name="shutdown_confirm">"您的手机会关闭。"</string>
+ <string name="no_recent_tasks">"无最近的应用程序。"</string>
+ <string name="global_actions">"手机选项"</string>
+ <string name="global_action_lock">"屏幕锁定"</string>
+ <string name="global_action_power_off">"关机"</string>
+ <string name="global_action_toggle_silent_mode">"静音模式"</string>
+ <string name="global_action_silent_mode_on_status">"声音已“关闭”"</string>
+ <string name="global_action_silent_mode_off_status">"声音已“开启”"</string>
+ <string name="global_actions_toggle_airplane_mode">"飞行模式"</string>
+ <string name="global_actions_airplane_mode_on_status">"飞行模式已开启"</string>
+ <string name="global_actions_airplane_mode_off_status">"飞行模式已关闭"</string>
+ <string name="safeMode">"安全模式"</string>
+ <string name="android_system_label">"Android 系统"</string>
+ <string name="permgrouplab_costMoney">"需要您付费的服务"</string>
+ <string name="permgroupdesc_costMoney">"允许应用程序执行可能需要您付费的操作。"</string>
+ <string name="permgrouplab_messages">"您的消息"</string>
+ <string name="permgroupdesc_messages">"读/写短信、电子邮件和其他消息。"</string>
+ <string name="permgrouplab_personalInfo">"您的个人信息"</string>
+ <string name="permgroupdesc_personalInfo">"直接访问手机上存储的联系人和日历。"</string>
+ <string name="permgrouplab_location">"您的位置"</string>
+ <string name="permgroupdesc_location">"监视您的物理位置"</string>
+ <string name="permgrouplab_network">"网络通信"</string>
+ <string name="permgroupdesc_network">"允许应用程序访问各种网络功能。"</string>
+ <string name="permgrouplab_accounts">"您的 Google 帐户"</string>
+ <string name="permgroupdesc_accounts">"访问可用的 Google 帐户。"</string>
+ <string name="permgrouplab_hardwareControls">"硬件控制"</string>
+ <string name="permgroupdesc_hardwareControls">"直接访问手机上的硬件。"</string>
+ <string name="permgrouplab_phoneCalls">"手机通话"</string>
+ <string name="permgroupdesc_phoneCalls">"监视、记录和处理电话。"</string>
+ <string name="permgrouplab_systemTools">"系统工具"</string>
+ <string name="permgroupdesc_systemTools">"对系统的低级别访问和控制。"</string>
+ <string name="permgrouplab_developmentTools">"开发工具"</string>
+ <string name="permgroupdesc_developmentTools">"只有应用程序开发人员需要这些功能。"</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"停用或修改状态栏"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"允许应用程序停用状态栏,或者添加和删除系统图标。"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"展开/折叠状态栏"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"允许应用程序展开或折叠状态栏。"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"拦截对外呼叫"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"允许应用程序处理对外呼叫和更改要拨打的号码。恶意应用程序可借此监视、重定向或阻止对外呼叫。"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"接收短信"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"允许应用程序接收和处理短信。恶意应用程序可借此监视您的信息,或者将信息删除而不向您显示。"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"接收彩信"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"允许应用程序接收和处理彩信。恶意应用程序可借此监视您的信息,或者将信息删除而不向您显示。"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"发送短信"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"允许应用程序发送短信。恶意应用程序可借此不经您的确认发送信息来让您付费。"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"读取短信或彩信"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"允许应用程序读取您的手机或 SIM 卡中存储的短信。恶意应用程序可借此读取您的机密信息。"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"编辑短信或彩信"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"允许应用程序写入手机或 SIM 卡中存储的短信。恶意应用程序可借此删除您的信息。"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"接收 WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"允许应用程序接收和处理 WAP 消息。恶意应用程序可借此监视您的消息,或者将消息删除而不向您显示。"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"检索所运行的应用程序"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"允许应用程序检索有关当前和最近运行的任务的信息。恶意应用程序可借此发现有关其他应用程序的私有信息。"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"对正在运行的应用程序重新排序"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"允许应用程序将任务移至前台和后台。恶意应用程序可借此强行进到前台,而不受您的控制。"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"启用应用程序调试"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"允许应用程序启动对其他应用程序的调试。恶意应用程序可借此终止其他应用程序。"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"允许应用程序更改当前配置,例如语言区域或整体字号。"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"重新启动其他应用程序"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"允许应用程序强行重新启动其他应用程序。"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"强行关闭应用程序"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"允许应用程序强行关闭前台中的任何活动并返回。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"检索系统内部状态"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"允许应用程序检索系统的内部状态。恶意应用程序可借此检索它们通常并不需要的各种私有信息和安全信息。"</string>
+ <string name="permlab_statusBar">"停用或修改状态栏"</string>
+ <string name="permdesc_statusBar">"允许应用程序停用状态栏,或者添加和删除系统图标。"</string>
+ <string name="permlab_expandStatusBar">"展开/折叠状态栏"</string>
+ <string name="permdesc_expandStatusBar">"允许应用程序展开或折叠状态栏。"</string>
+ <string name="permlab_processOutgoingCalls">"拦截对外呼叫"</string>
+ <string name="permdesc_processOutgoingCalls">"允许应用程序处理对外呼叫和更改要拨打的号码。恶意应用程序可借此监视、重定向或阻止对外呼叫。"</string>
+ <string name="permlab_receiveSms">"接收短信"</string>
+ <string name="permdesc_receiveSms">"允许应用程序接收和处理短信。恶意应用程序可借此监视您的信息,或者将信息删除而不向您显示。"</string>
+ <string name="permlab_receiveMms">"接收彩信"</string>
+ <string name="permdesc_receiveMms">"允许应用程序接收和处理彩信。恶意应用程序可借此监视您的信息,或者将信息删除而不向您显示。"</string>
+ <string name="permlab_sendSms">"发送短信"</string>
+ <string name="permdesc_sendSms">"允许应用程序发送短信。恶意应用程序可借此不经您的确认发送信息来让您付费。"</string>
+ <string name="permlab_readSms">"读取短信或彩信"</string>
+ <string name="permdesc_readSms">"允许应用程序读取您的手机或 SIM 卡中存储的短信。恶意应用程序可借此读取您的机密信息。"</string>
+ <string name="permlab_writeSms">"编辑短信或彩信"</string>
+ <string name="permdesc_writeSms">"允许应用程序写入手机或 SIM 卡中存储的短信。恶意应用程序可借此删除您的信息。"</string>
+ <string name="permlab_receiveWapPush">"接收 WAP"</string>
+ <string name="permdesc_receiveWapPush">"允许应用程序接收和处理 WAP 消息。恶意应用程序可借此监视您的消息,或者将消息删除而不向您显示。"</string>
+ <string name="permlab_getTasks">"检索所运行的应用程序"</string>
+ <string name="permdesc_getTasks">"允许应用程序检索有关当前和最近运行的任务的信息。恶意应用程序可借此发现有关其他应用程序的私有信息。"</string>
+ <string name="permlab_reorderTasks">"对正在运行的应用程序重新排序"</string>
+ <string name="permdesc_reorderTasks">"允许应用程序将任务移至前台和后台。恶意应用程序可借此强行进到前台,而不受您的控制。"</string>
+ <string name="permlab_setDebugApp">"启用应用程序调试"</string>
+ <string name="permdesc_setDebugApp">"允许应用程序启动对其他应用程序的调试。恶意应用程序可借此终止其他应用程序。"</string>
+ <string name="permlab_changeConfiguration">"更改您的用户界面设置"</string>
+ <string name="permdesc_changeConfiguration">"允许应用程序更改当前配置,例如语言区域或整体字号。"</string>
+ <string name="permlab_restartPackages">"重新启动其他应用程序"</string>
+ <string name="permdesc_restartPackages">"允许应用程序强行重新启动其他应用程序。"</string>
+ <string name="permlab_forceBack">"强行关闭应用程序"</string>
+ <string name="permdesc_forceBack">"允许应用程序强行关闭前台中的任何活动并返回。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_dump">"检索系统内部状态"</string>
+ <string name="permdesc_dump">"允许应用程序检索系统的内部状态。恶意应用程序可借此检索它们通常并不需要的各种私有信息和安全信息。"</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"监控所有应用程序的启动"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"允许应用程序监控系统启动活动的方式。恶意应用程序可借此彻底损坏系统。这一权限只在开发过程中需要,普通的手机操作不需要。"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"发送已删除包的广播"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"允许应用程序广播已删除应用程序包的通知。恶意应用程序可借此终止任何正在运行的其他应用程序。"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"发送可通过短信接收的广播"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"允许应用程序广播已收到短信的通知。恶意应用程序可借此伪造收到的短信。"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"发送 WAP 一键接收广播"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"允许应用程序广播收到 WAP 一键信息的通知。恶意应用程序可借此乱发彩信或暗中用恶意内容替换任意网页中的内容。"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"限制所运行进程的数量"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"允许应用程序控制将运行的最大进程数。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"关闭所有后台应用程序"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"允许应用程序控制活动是否始终是一转至后台就完成。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"修改电池使用情况统计信息"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"允许修改收集的电池使用情况统计信息。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_runSetActivityWatcher">"监控所有应用程序的启动"</string>
+ <string name="permdesc_runSetActivityWatcher">"允许应用程序监控系统启动活动的方式。恶意应用程序可借此彻底损坏系统。这一权限只在开发过程中需要,普通的手机操作不需要。"</string>
+ <string name="permlab_broadcastPackageRemoved">"发送已删除包的广播"</string>
+ <string name="permdesc_broadcastPackageRemoved">"允许应用程序广播已删除应用程序包的通知。恶意应用程序可借此终止任何正在运行的其他应用程序。"</string>
+ <string name="permlab_broadcastSmsReceived">"发送可通过短信接收的广播"</string>
+ <string name="permdesc_broadcastSmsReceived">"允许应用程序广播已收到短信的通知。恶意应用程序可借此伪造收到的短信。"</string>
+ <string name="permlab_broadcastWapPush">"发送 WAP 一键接收广播"</string>
+ <string name="permdesc_broadcastWapPush">"允许应用程序广播收到 WAP 一键信息的通知。恶意应用程序可借此乱发彩信或暗中用恶意内容替换任意网页中的内容。"</string>
+ <string name="permlab_setProcessLimit">"限制所运行进程的数量"</string>
+ <string name="permdesc_setProcessLimit">"允许应用程序控制将运行的最大进程数。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_setAlwaysFinish">"关闭所有后台应用程序"</string>
+ <string name="permdesc_setAlwaysFinish">"允许应用程序控制活动是否始终是一转至后台就完成。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_batteryStats">"修改电池使用情况统计信息"</string>
+ <string name="permdesc_batteryStats">"允许修改收集的电池使用情况统计信息。普通应用程序不能使用此权限。"</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"显示未授权的窗口"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允许创建专供内部系统用户界面使用的窗口。普通应用程序不能使用此权限。"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"显示系统级警报"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"允许应用程序显示系统警报窗口。恶意应用程序可借此掌控整个手机屏幕。"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"修改全局动画速度"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"允许应用程序随时更改全局动画速度(加快或放慢动画)。"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"管理应用程序令牌"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"允许应用程序创建和管理自己的令牌,从而绕开正常的 Z 排序方式。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"按键和控制按钮"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"允许应用程序将其自己的输入活动(按键等)提供给其他应用程序。恶意应用程序可借此掌控手机。"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"记录您输入的内容和采取的操作"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"允许应用程序查看您按的键,即使在与其他应用程序交互(例如输入密码)时也不例外。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"绑定至输入法"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"允许手机用户绑定至输入法的顶级界面。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕浏览模式"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"允许应用程序随时更改屏幕的旋转方向。普通应用程序从不需要使用此权限。"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"向应用程序发送 Linux 信号"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允许应用程序请求将提供的信号发送给所有持续的进程。"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"让应用程序始终运行"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"允许应用程序部分持续运行,这样系统便不能将其用于其他应用程序。"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"删除应用程序"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"允许应用程序删除 Android 包。恶意应用程序可借此删除重要的应用程序。"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"删除其他应用程序的数据"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"允许应用程序清除用户数据。"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"删除其他应用程序缓存"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"允许应用程序删除缓存文件。"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"计算应用程序存储空间"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"允许应用程序检索其代码、数据和缓存大小"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"直接安装应用程序"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"允许应用程序安装新的或更新的 Android 包。恶意应用程序可借此添加具有极大权限的新应用程序。"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"删除所有应用程序缓存数据"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"允许应用程序通过删除应用程序缓存目录中的文件释放手机存储空间。对系统进程的访问通常受到严格限制。"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"读取系统日志文件"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"允许应用程序读取系统的各日志文件。这样应用程序可以发现有关您操作手机的一般信息,但这些信息不应包含任何个人信息或私有信息。"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"允许应用程序读取/写入诊断组所拥有的任何资源;例如,/dev 中的文件。这可能会影响系统稳定性和安全性。此权限只应由制造商或运营商用于硬件特定的诊断。"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"启用或停用应用程序组件"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"允许应用程序更改是否启用其他应用程序的组件。恶意应用程序可借此停用重要的手机功能。使用此权限时务必谨慎,因为这可能导致应用程序组件进入不可用、不一致或不稳定的状态。"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"设置首选应用程序"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"允许应用程序修改首选的应用程序。这样恶意应用程序可能会暗中更改运行的应用程序,从而骗过您的现有应用程序来收集您的私有数据。"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"修改全局系统设置"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"允许应用程序修改系统的设置数据。恶意应用程序可借此破坏您的系统配置。"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"修改安全系统设置"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"允许应用程序修改系统安全设置数据。普通应用程序不能使用此权限。"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"修改 Google 服务地图"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"允许应用程序修改 Google 服务地图。普通应用程序不能使用此权限。"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"开机时自动启动"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"允许应用程序在系统完成启动后即自行启动。这样会延长手机的启动时间,而且如果应用程序一直运行,会降低手机的整体速度。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"发送顽固广播"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可能会借此使手机耗用太多内存,从而降低其速度或稳定性。"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"读取联系人数据"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"允许应用程序读取您手机上存储的所有联系人(地址)数据。恶意应用程序可借此将您的数据发送给其他人。"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"写入联系数据"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"允许应用程序修改您手机上存储的联系人(地址)数据。恶意应用程序可借此清除或修改您的联系人数据。"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"写入拥有者数据"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"允许应用程序修改您手机上存储的手机拥有者数据。恶意应用程序可借此清除或修改拥有者数据。"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"读取拥有者数据"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"允许应用程序读取您手机上存储的手机拥有者数据。恶意应用程序可借此读取手机拥有者数据。"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"读取日历数据"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"允许应用程序读取您手机上存储的所有日历活动。恶意应用程序可借此将您的日历活动发送给其他人。"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"写入日历数据"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"允许应用程序修改您手机上存储的日历活动。恶意应用程序可借此清除或修改您的日历数据。"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"用于测试的模拟位置源"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"创建用于测试的模拟位置源。恶意应用程序可借此替代真正的位置源(如 GPS 或网络提供商)返回的位置和/或状态。"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收额外的位置提供者命令"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"访问额外的位置提供程序命令。恶意应用程序可借此干扰 GPS 或其他位置源的运作。"</string>
+ <string name="permlab_internalSystemWindow">"显示未授权的窗口"</string>
+ <string name="permdesc_internalSystemWindow">"允许创建专供内部系统用户界面使用的窗口。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_systemAlertWindow">"显示系统级警报"</string>
+ <string name="permdesc_systemAlertWindow">"允许应用程序显示系统警报窗口。恶意应用程序可借此掌控整个手机屏幕。"</string>
+ <string name="permlab_setAnimationScale">"修改全局动画速度"</string>
+ <string name="permdesc_setAnimationScale">"允许应用程序随时更改全局动画速度(加快或放慢动画)。"</string>
+ <string name="permlab_manageAppTokens">"管理应用程序令牌"</string>
+ <string name="permdesc_manageAppTokens">"允许应用程序创建和管理自己的令牌,从而绕开正常的 Z 排序方式。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_injectEvents">"按键和控制按钮"</string>
+ <string name="permdesc_injectEvents">"允许应用程序将其自己的输入活动(按键等)提供给其他应用程序。恶意应用程序可借此掌控手机。"</string>
+ <string name="permlab_readInputState">"记录您输入的内容和采取的操作"</string>
+ <string name="permdesc_readInputState">"允许应用程序查看您按的键,即使在与其他应用程序交互(例如输入密码)时也不例外。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_bindInputMethod">"绑定至输入法"</string>
+ <string name="permdesc_bindInputMethod">"允许手机用户绑定至输入法的顶级界面。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_setOrientation">"更改屏幕浏览模式"</string>
+ <string name="permdesc_setOrientation">"允许应用程序随时更改屏幕的旋转方向。普通应用程序从不需要使用此权限。"</string>
+ <string name="permlab_signalPersistentProcesses">"向应用程序发送 Linux 信号"</string>
+ <string name="permdesc_signalPersistentProcesses">"允许应用程序请求将提供的信号发送给所有持续的进程。"</string>
+ <string name="permlab_persistentActivity">"让应用程序始终运行"</string>
+ <string name="permdesc_persistentActivity">"允许应用程序部分持续运行,这样系统便不能将其用于其他应用程序。"</string>
+ <string name="permlab_deletePackages">"删除应用程序"</string>
+ <string name="permdesc_deletePackages">"允许应用程序删除 Android 包。恶意应用程序可借此删除重要的应用程序。"</string>
+ <string name="permlab_clearAppUserData">"删除其他应用程序的数据"</string>
+ <string name="permdesc_clearAppUserData">"允许应用程序清除用户数据。"</string>
+ <string name="permlab_deleteCacheFiles">"删除其他应用程序缓存"</string>
+ <string name="permdesc_deleteCacheFiles">"允许应用程序删除缓存文件。"</string>
+ <string name="permlab_getPackageSize">"计算应用程序存储空间"</string>
+ <string name="permdesc_getPackageSize">"允许应用程序检索其代码、数据和缓存大小"</string>
+ <string name="permlab_installPackages">"直接安装应用程序"</string>
+ <string name="permdesc_installPackages">"允许应用程序安装新的或更新的 Android 包。恶意应用程序可借此添加具有极大权限的新应用程序。"</string>
+ <string name="permlab_clearAppCache">"删除所有应用程序缓存数据"</string>
+ <string name="permdesc_clearAppCache">"允许应用程序通过删除应用程序缓存目录中的文件释放手机存储空间。对系统进程的访问通常受到严格限制。"</string>
+ <string name="permlab_readLogs">"读取系统日志文件"</string>
+ <string name="permdesc_readLogs">"允许应用程序读取系统的各日志文件。这样应用程序可以发现有关您操作手机的一般信息,但这些信息不应包含任何个人信息或私有信息。"</string>
+ <string name="permlab_diagnostic">"读取/写入诊断所拥有的资源"</string>
+ <string name="permdesc_diagnostic">"允许应用程序读取/写入诊断组所拥有的任何资源;例如,/dev 中的文件。这可能会影响系统稳定性和安全性。此权限只应由制造商或运营商用于硬件特定的诊断。"</string>
+ <string name="permlab_changeComponentState">"启用或停用应用程序组件"</string>
+ <string name="permdesc_changeComponentState">"允许应用程序更改是否启用其他应用程序的组件。恶意应用程序可借此停用重要的手机功能。使用此权限时务必谨慎,因为这可能导致应用程序组件进入不可用、不一致或不稳定的状态。"</string>
+ <string name="permlab_setPreferredApplications">"设置首选应用程序"</string>
+ <string name="permdesc_setPreferredApplications">"允许应用程序修改首选的应用程序。这样恶意应用程序可能会暗中更改运行的应用程序,从而骗过您的现有应用程序来收集您的私有数据。"</string>
+ <string name="permlab_writeSettings">"修改全局系统设置"</string>
+ <string name="permdesc_writeSettings">"允许应用程序修改系统的设置数据。恶意应用程序可借此破坏您的系统配置。"</string>
+ <string name="permlab_writeSecureSettings">"修改安全系统设置"</string>
+ <string name="permdesc_writeSecureSettings">"允许应用程序修改系统安全设置数据。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_writeGservices">"修改 Google 服务地图"</string>
+ <string name="permdesc_writeGservices">"允许应用程序修改 Google 服务地图。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_receiveBootCompleted">"开机时自动启动"</string>
+ <string name="permdesc_receiveBootCompleted">"允许应用程序在系统完成启动后即自行启动。这样会延长手机的启动时间,而且如果应用程序一直运行,会降低手机的整体速度。"</string>
+ <string name="permlab_broadcastSticky">"发送顽固广播"</string>
+ <string name="permdesc_broadcastSticky">"允许应用程序发送顽固广播,这些广播在结束后仍会保留。恶意应用程序可能会借此使手机耗用太多内存,从而降低其速度或稳定性。"</string>
+ <string name="permlab_readContacts">"读取联系人数据"</string>
+ <string name="permdesc_readContacts">"允许应用程序读取您手机上存储的所有联系人(地址)数据。恶意应用程序可借此将您的数据发送给其他人。"</string>
+ <string name="permlab_writeContacts">"写入联系数据"</string>
+ <string name="permdesc_writeContacts">"允许应用程序修改您手机上存储的联系人(地址)数据。恶意应用程序可借此清除或修改您的联系人数据。"</string>
+ <string name="permlab_writeOwnerData">"写入拥有者数据"</string>
+ <string name="permdesc_writeOwnerData">"允许应用程序修改您手机上存储的手机拥有者数据。恶意应用程序可借此清除或修改拥有者数据。"</string>
+ <string name="permlab_readOwnerData">"读取拥有者数据"</string>
+ <string name="permdesc_readOwnerData">"允许应用程序读取您手机上存储的手机拥有者数据。恶意应用程序可借此读取手机拥有者数据。"</string>
+ <string name="permlab_readCalendar">"读取日历数据"</string>
+ <string name="permdesc_readCalendar">"允许应用程序读取您手机上存储的所有日历活动。恶意应用程序可借此将您的日历活动发送给其他人。"</string>
+ <string name="permlab_writeCalendar">"写入日历数据"</string>
+ <string name="permdesc_writeCalendar">"允许应用程序修改您手机上存储的日历活动。恶意应用程序可借此清除或修改您的日历数据。"</string>
+ <string name="permlab_accessMockLocation">"用于测试的模拟位置源"</string>
+ <string name="permdesc_accessMockLocation">"创建用于测试的模拟位置源。恶意应用程序可借此替代真正的位置源(如 GPS 或网络提供商)返回的位置和/或状态。"</string>
+ <string name="permlab_accessLocationExtraCommands">"允许访问额外的位置提供命令"</string>
+ <string name="permdesc_accessLocationExtraCommands">"访问额外的位置提供程序命令。恶意应用程序可借此干扰 GPS 或其他位置源的运作。"</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"精准位置 (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"访问精准的位置源,例如手机上的全球定位系统(如果适用)。恶意应用程序可能借此确定您所处的位置,并消耗额外的电池电量。"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"粗略位置(以网络为基础)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"访问粗略的位置源(例如蜂窝网络数据库)以确定手机的大体位置(如果适用)。恶意应用程序可借此确定您所处的大体位置。"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"访问 SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"允许应用程序使用 SurfaceFlinger 低级别功能。"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读取帧缓冲区"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"允许应用程序读取帧缓冲区的内容。"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"更改您的音频设置"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"允许应用程序修改全局音频设置,如音量和路由。"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"录音"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"允许应用程序访问录音路径。"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"拍照"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"允许应用程序使用相机拍照。此权限允许应用程序随时收集相机看到的图片。"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"永久停用手机"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"允许应用程序永久停用整个手机,这非常危险。"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"强行重新启动手机"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"允许应用程序强行重新启动手机。"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"安装和卸载文件系统"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"允许应用程序安装和卸载可移动存储器的文件系统。"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"格式化外部存储设备"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"允许应用程序格式化可移除的存储设备。"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"控制振动器"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"允许应用程序控制振动器。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"允许应用程序控制闪光灯。"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"测试硬件"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"允许应用程序控制各种用于硬件测试的外围设备。"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"允许应用程序在没有您干预的情况下呼叫电话号码。恶意应用程序可借此在您的话费单上产生意外通话费。请注意,此权限不允许应用程序呼叫紧急电话号码。"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"直接呼叫任何电话号码"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"允许应用程序在没有您干预的情况下呼叫任何电话号码(包括紧急电话号码)。恶意应用程序可借此对紧急服务拨打骚扰电话和非法电话。"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"允许启用/停用收音机的位置更新通知。普通应用程序不能使用此权限。"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"访问检入属性"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"允许对检入服务上传的属性进行读/写访问。普通应用程序不能使用此权限。"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"选择窗口小部件"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"允许应用程序告诉系统哪个应用程序可以使用哪些窗口小部件。具有该权限的应用程序可以允许其他应用程序访问个人数据。普通应用程序不适合使用此权限。"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手机状态"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"允许应用程序控制设备的手机功能。具有此权限的应用程序可切换网络、打开和关闭手机收音机等,而不通知您。"</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"防止手机休眠"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"允许应用程序防止手机进入休眠状态。"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"开机或关机"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"允许应用程序打开或关闭手机。"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"在出厂测试模式下运行"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"作为低级别制造商测试运行,以允许完全访问手机硬件。此权限只有当手机在制造商测试模式下运行时才可用。"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"设置壁纸"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"允许应用程序设置系统壁纸。"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"设置壁纸大小提示"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"允许应用程序设置系统壁纸大小提示。"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"将系统重置为出厂时的默认设置"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"允许应用程序将系统完全重置为出厂设置,即清除所有数据、配置和安装的应用程序。"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"设置时区"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"允许应用程序更改手机的时区。"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"发现已知帐户"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"允许应用程序获取手机已知的帐户列表。"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"查看网络状态"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"允许应用程序查看所有网络的状态。"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"互联网完全访问"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"允许应用程序创建网络套接字。"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"写入接入点名称设置"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"允许应用程序修改 APN 设置,例如任何 APN 的代理和端口。"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"更改网络连接"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"允许应用程序更改网络连接状态。"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"更改背景数据使用设置"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"允许应用程序更改背景数据使用设置。"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"查看 Wi-Fi 状态"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"允许应用程序查看有关 Wi-Fi 状态的信息。"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"更改 Wi-Fi 状态"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"允许应用程序连接到 Wi-Fi 接入点以及与 Wi-Fi 接入点断开连接,并对配置的 Wi-Fi 网络进行更改。"</string>
+ <string name="permlab_accessFineLocation">"精准位置 (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"访问精准的位置源,例如手机上的全球定位系统(如果适用)。恶意应用程序可能借此确定您所处的位置,并消耗额外的电池电量。"</string>
+ <string name="permlab_accessCoarseLocation">"粗略位置(所在网络)"</string>
+ <string name="permdesc_accessCoarseLocation">"访问粗略的位置源(例如蜂窝网络数据库)以确定手机的大体位置(如果适用)。恶意应用程序可借此确定您所处的大体位置。"</string>
+ <string name="permlab_accessSurfaceFlinger">"访问 SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"允许应用程序使用 SurfaceFlinger 低级别功能。"</string>
+ <string name="permlab_readFrameBuffer">"读取帧缓冲区"</string>
+ <string name="permdesc_readFrameBuffer">"允许应用程序读取帧缓冲区的内容。"</string>
+ <string name="permlab_modifyAudioSettings">"更改您的音频设置"</string>
+ <string name="permdesc_modifyAudioSettings">"允许应用程序修改全局音频设置,如音量和路由。"</string>
+ <string name="permlab_recordAudio">"录音"</string>
+ <string name="permdesc_recordAudio">"允许应用程序访问录音路径。"</string>
+ <string name="permlab_camera">"拍照"</string>
+ <string name="permdesc_camera">"允许应用程序使用相机拍照。此权限允许应用程序随时收集相机看到的图片。"</string>
+ <string name="permlab_brick">"永久停用手机"</string>
+ <string name="permdesc_brick">"允许应用程序永久停用整个手机,这非常危险。"</string>
+ <string name="permlab_reboot">"强行重新启动手机"</string>
+ <string name="permdesc_reboot">"允许应用程序强行重新启动手机。"</string>
+ <string name="permlab_mount_unmount_filesystems">"安装和卸载文件系统"</string>
+ <string name="permdesc_mount_unmount_filesystems">"允许应用程序安装和卸载可移动存储器的文件系统。"</string>
+ <string name="permlab_mount_format_filesystems">"格式化外部存储设备"</string>
+ <string name="permdesc_mount_format_filesystems">"允许应用程序格式化可移除的存储设备。"</string>
+ <string name="permlab_vibrate">"控制振动器"</string>
+ <string name="permdesc_vibrate">"允许应用程序控制振动器。"</string>
+ <string name="permlab_flashlight">"控制闪光灯"</string>
+ <string name="permdesc_flashlight">"允许应用程序控制闪光灯。"</string>
+ <string name="permlab_hardware_test">"测试硬件"</string>
+ <string name="permdesc_hardware_test">"允许应用程序控制各种用于硬件测试的外围设备。"</string>
+ <string name="permlab_callPhone">"直接拨打电话号码"</string>
+ <string name="permdesc_callPhone">"允许应用程序在没有您干预的情况下呼叫电话号码。恶意应用程序可借此在您的话费单上产生意外通话费。请注意,此权限不允许应用程序呼叫紧急电话号码。"</string>
+ <string name="permlab_callPrivileged">"直接呼叫任何电话号码"</string>
+ <string name="permdesc_callPrivileged">"允许应用程序在没有您干预的情况下呼叫任何电话号码(包括紧急电话号码)。恶意应用程序可借此对紧急服务拨打骚扰电话和非法电话。"</string>
+ <string name="permlab_locationUpdates">"控制位置更新通知"</string>
+ <string name="permdesc_locationUpdates">"允许启用/停用收音机的位置更新通知。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_checkinProperties">"访问检入属性"</string>
+ <string name="permdesc_checkinProperties">"允许对检入服务上传的属性进行读/写访问。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_bindGadget">"选择窗口小部件"</string>
+ <string name="permdesc_bindGadget">"允许应用程序告诉系统哪个应用程序可以使用哪些窗口小部件。具有该权限的应用程序可以允许其他应用程序访问个人数据。普通应用程序不适合使用此权限。"</string>
+ <string name="permlab_modifyPhoneState">"修改手机状态"</string>
+ <string name="permdesc_modifyPhoneState">"允许应用程序控制设备的手机功能。具有此权限的应用程序可切换网络、打开和关闭手机收音机等,而不通知您。"</string>
+ <string name="permlab_readPhoneState">"读取手机状态"</string>
+ <string name="permdesc_readPhoneState">"允许应用程序访问设备的手机功能。具有此权限的应用程序可确定此手机的号码、是否在通话以及通话对方的号码等。"</string>
+ <string name="permlab_wakeLock">"防止手机休眠"</string>
+ <string name="permdesc_wakeLock">"允许应用程序防止手机进入休眠状态。"</string>
+ <string name="permlab_devicePower">"开机或关机"</string>
+ <string name="permdesc_devicePower">"允许应用程序打开或关闭手机。"</string>
+ <string name="permlab_factoryTest">"在出厂测试模式下运行"</string>
+ <string name="permdesc_factoryTest">"作为低级别制造商测试运行,以允许完全访问手机硬件。此权限只有当手机在制造商测试模式下运行时才可用。"</string>
+ <string name="permlab_setWallpaper">"设置壁纸"</string>
+ <string name="permdesc_setWallpaper">"允许应用程序设置系统壁纸。"</string>
+ <string name="permlab_setWallpaperHints">"设置壁纸大小提示"</string>
+ <string name="permdesc_setWallpaperHints">"允许应用程序设置系统壁纸大小提示。"</string>
+ <string name="permlab_masterClear">"将系统重置为出厂时的默认设置"</string>
+ <string name="permdesc_masterClear">"允许应用程序将系统完全重置为出厂设置,即清除所有数据、配置和安装的应用程序。"</string>
+ <string name="permlab_setTimeZone">"设置时区"</string>
+ <string name="permdesc_setTimeZone">"允许应用程序更改手机的时区。"</string>
+ <string name="permlab_getAccounts">"发现已知帐户"</string>
+ <string name="permdesc_getAccounts">"允许应用程序获取手机已知的帐户列表。"</string>
+ <string name="permlab_accessNetworkState">"查看网络状态"</string>
+ <string name="permdesc_accessNetworkState">"允许应用程序查看所有网络的状态。"</string>
+ <string name="permlab_createNetworkSockets">"不受限制的互联网访问权限"</string>
+ <string name="permdesc_createNetworkSockets">"允许应用程序创建网络套接字。"</string>
+ <string name="permlab_writeApnSettings">"写入接入点名称设置"</string>
+ <string name="permdesc_writeApnSettings">"允许应用程序修改 APN 设置,例如任何 APN 的代理和端口。"</string>
+ <string name="permlab_changeNetworkState">"更改网络连接"</string>
+ <string name="permdesc_changeNetworkState">"允许应用程序更改网络连接状态。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"更改背景数据使用设置"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"允许应用程序更改背景数据使用设置。"</string>
+ <string name="permlab_accessWifiState">"查看 Wi-Fi 状态"</string>
+ <string name="permdesc_accessWifiState">"允许应用程序查看有关 Wi-Fi 状态的信息。"</string>
+ <string name="permlab_changeWifiState">"更改 Wi-Fi 状态"</string>
+ <string name="permdesc_changeWifiState">"允许应用程序连接到 Wi-Fi 接入点以及与 Wi-Fi 接入点断开连接,并对配置的 Wi-Fi 网络进行更改。"</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"蓝牙管理"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"允许应用程序配置本地蓝牙手机,以及查找远程设备并与之配对。"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"创建蓝牙连接"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"允许应用程序查看本地蓝牙手机的配置,以及建立和接受与配对设备的连接。"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"停用键锁"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"允许应用程序停用键锁和任何关联的密码安全设置。这种情况的一个恰当示例就是这样一个手机:在接听来电时停用键锁,在通话结束后重新启用键锁。"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"允许应用程序读取同步设置,例如是否针对联系人启用同步。"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"写入同步设置"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"允许应用程序修改同步设置,例如是否针对联系人启用同步。"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"读取同步统计信息"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"允许应用程序读取同步统计信息;例如已发生的同步历史记录。"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"读取订阅的供稿"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"允许应用程序获取有关当前同步的供稿的详细信息。"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"写入订阅的供稿"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"允许应用程序修改您当前同步的供稿。恶意应用程序可借此更改您同步的供稿。"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"读取用户定义的词典"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"允许应用程序读取用户在用户词典中存储的任意私有字词、名称和短语。"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"写入用户定义的词典"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"允许应用程序向用户词典中写入新词。"</string>
+ <string name="permlab_bluetoothAdmin">"蓝牙管理"</string>
+ <string name="permdesc_bluetoothAdmin">"允许应用程序配置本地蓝牙手机,以及查找远程设备并与之配对。"</string>
+ <string name="permlab_bluetooth">"创建蓝牙连接"</string>
+ <string name="permdesc_bluetooth">"允许应用程序查看本地蓝牙手机的配置,以及建立和接受与配对设备的连接。"</string>
+ <string name="permlab_disableKeyguard">"停用键锁"</string>
+ <string name="permdesc_disableKeyguard">"允许应用程序停用键锁和任何关联的密码安全设置。这种情况的一个恰当示例就是这样一个手机:在接听来电时停用键锁,在通话结束后重新启用键锁。"</string>
+ <string name="permlab_readSyncSettings">"读取同步设置"</string>
+ <string name="permdesc_readSyncSettings">"允许应用程序读取同步设置,例如是否针对联系人启用同步。"</string>
+ <string name="permlab_writeSyncSettings">"写入同步设置"</string>
+ <string name="permdesc_writeSyncSettings">"允许应用程序修改同步设置,例如是否针对联系人启用同步。"</string>
+ <string name="permlab_readSyncStats">"读取同步统计信息"</string>
+ <string name="permdesc_readSyncStats">"允许应用程序读取同步统计信息;例如已发生的同步历史记录。"</string>
+ <string name="permlab_subscribedFeedsRead">"读取订阅的供稿"</string>
+ <string name="permdesc_subscribedFeedsRead">"允许应用程序获取有关当前同步的供稿的详细信息。"</string>
+ <string name="permlab_subscribedFeedsWrite">"写入订阅的供稿"</string>
+ <string name="permdesc_subscribedFeedsWrite">"允许应用程序修改您当前同步的供稿。恶意应用程序可借此更改您同步的供稿。"</string>
+ <string name="permlab_readDictionary">"读取用户定义的词典"</string>
+ <string name="permdesc_readDictionary">"允许应用程序读取用户在用户词典中存储的任意私有字词、名称和短语。"</string>
+ <string name="permlab_writeDictionary">"写入用户定义的词典"</string>
+ <string name="permdesc_writeDictionary">"允许应用程序向用户词典中写入新词。"</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"住宅电话"</item>
- <item msgid="869923650527136615">"手机"</item>
- <item msgid="7897544654242874543">"单位电话"</item>
- <item msgid="1103601433382158155">"单位传真"</item>
- <item msgid="1735177144948329370">"住宅传真"</item>
- <item msgid="603878674477207394">"寻呼机"</item>
- <item msgid="1650824275177931637">"其他电话"</item>
- <item msgid="9192514806975898961">"自定义电话"</item>
+ <item>"住宅电话"</item>
+ <item>"手机"</item>
+ <item>"单位电话"</item>
+ <item>"单位传真"</item>
+ <item>"住宅传真"</item>
+ <item>"寻呼机"</item>
+ <item>"其他电话"</item>
+ <item>"自定义电话"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"主要邮箱"</item>
- <item msgid="7084237356602625604">"单位邮箱"</item>
- <item msgid="1112044410659011023">"其他邮箱"</item>
- <item msgid="2374913952870110618">"自定义邮箱"</item>
+ <item>"住宅邮箱"</item>
+ <item>"单位邮箱"</item>
+ <item>"其他邮箱"</item>
+ <item>"自定义邮箱"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"手机"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"住宅地址"</item>
- <item msgid="5629153956045109251">"单位地址"</item>
- <item msgid="4966604264500343469">"其他地址"</item>
- <item msgid="4932682847595299369">"自定义地址"</item>
+ <item>"住宅地址"</item>
+ <item>"单位地址"</item>
+ <item>"其他地址"</item>
+ <item>"自定义地址"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"住宅聊天工具"</item>
- <item msgid="1359644565647383708">"单位聊天工具"</item>
- <item msgid="7868549401053615677">"其他聊天工具"</item>
- <item msgid="3145118944639869809">"自定义聊天工具"</item>
+ <item>"住宅聊天工具"</item>
+ <item>"单位聊天工具"</item>
+ <item>"其他聊天工具"</item>
+ <item>"自定义聊天工具"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"单位"</item>
- <item msgid="4378074129049520373">"其他组织"</item>
- <item msgid="3455047468583965104">"自定义组织"</item>
+ <item>"单位"</item>
+ <item>"其他组织"</item>
+ <item>"自定义组织"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"中国雅虎"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"中国雅虎"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"输入 PIN 码"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN 码不正确!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"紧急电话号码"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(无服务)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"屏幕已锁定。"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按 MENU 解锁或拨打紧急电话。"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按 MENU 解锁。"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"绘制解锁图案"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"紧急呼叫"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"正确!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"很抱歉,请重试"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"正在充电 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"输入 PIN 码"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 码不正确!"</string>
+ <string name="keyguard_label_text">"要解锁,请先按 MENU 再按 0。"</string>
+ <string name="emergency_call_dialog_number_for_display">"紧急电话号码"</string>
+ <string name="lockscreen_carrier_default">"(无服务)"</string>
+ <string name="lockscreen_screen_locked">"屏幕已锁定。"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"按 MENU 解锁或拨打紧急电话。"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"按 MENU 解锁。"</string>
+ <string name="lockscreen_pattern_instructions">"绘制解锁图案"</string>
+ <string name="lockscreen_emergency_call">"紧急呼叫"</string>
+ <string name="lockscreen_pattern_correct">"正确!"</string>
+ <string name="lockscreen_pattern_wrong">"很抱歉,请重试"</string>
+ <string name="lockscreen_plugged_in">"正在充电 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"连接您的充电器。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"没有 SIM 卡。"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"手机中无 SIM 卡。"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"请插入 SIM 卡。"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已锁定"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 卡被 PUK 锁定。"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"请参阅《用户指南》或联系客服人员。"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡被锁定。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"正在解锁 SIM 卡..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统会要求您使用自己的 Google 登录信息解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘记了图案?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"图案尝试次数过多!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"要解除锁定,请使用您的 Google 帐户登录"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"用户名(电子邮件)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密码"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登录"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"用户名或密码无效。"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="AMPM">%P</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="AMPM">%p</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
+ <string name="lockscreen_low_battery">"连接您的充电器。"</string>
+ <string name="lockscreen_missing_sim_message_short">"没有 SIM 卡。"</string>
+ <string name="lockscreen_missing_sim_message">"手机中无 SIM 卡。"</string>
+ <string name="lockscreen_missing_sim_instructions">"请插入 SIM 卡。"</string>
+ <string name="lockscreen_network_locked_message">"网络已锁定"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM 卡被 PUK 锁定。"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"请参阅《用户指南》或联系客服人员。"</string>
+ <string name="lockscreen_sim_locked_message">"SIM 卡被锁定。"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"正在解锁 SIM 卡..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统会要求您使用自己的 Google 登录信息解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"忘记了图案?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"图案尝试次数过多!"</string>
+ <string name="lockscreen_glogin_instructions">"要解除锁定,请使用您的 Google 帐户登录"</string>
+ <string name="lockscreen_glogin_username_hint">"用户名(电子邮件)"</string>
+ <string name="lockscreen_glogin_password_hint">"密码"</string>
+ <string name="lockscreen_glogin_submit_button">"登录"</string>
+ <string name="lockscreen_glogin_invalid_input">"用户名或密码无效。"</string>
+ <string name="hour_ampm">"<xliff:g id="AMPM">%P</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="AMPM">%p</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"正在充电..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"请连接充电器"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"电量在减少:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"剩余电量不足 <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
+ <string name="status_bar_no_notifications_title">"无通知"</string>
+ <string name="status_bar_ongoing_events_title">"正在进行"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"正在充电..."</string>
+ <string name="battery_low_title">"请连接充电器"</string>
+ <string name="battery_low_subtitle">"电量在减少:"</string>
+ <string name="battery_low_percent_format">"剩余电量不足 <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"出厂测试失败"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"只有 /system/app 中安装的包支持 FACTORY_TEST 操作。"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"未发现支持 FACTORY_TEST 操作的包。"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"重新启动"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"“<xliff:g id="TITLE">%s</xliff:g>”处的页面表明:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"是否从该页面导航至它处?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定”继续,或选择“取消”留在当前页面。"</string>
- <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
+ <string name="factorytest_failed">"出厂测试失败"</string>
+ <string name="factorytest_not_system">"只有 /system/app 中安装的包支持 FACTORY_TEST 操作。"</string>
+ <string name="factorytest_no_action">"未发现支持 FACTORY_TEST 操作的包。"</string>
+ <string name="factorytest_reboot">"重新启动"</string>
+ <string name="js_dialog_title">"“<xliff:g id="TITLE">%s</xliff:g>”处的页面表明:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"是否从该页面导航至它处?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定”继续,或选择“取消”留在当前页面。"</string>
+ <string name="save_password_label">"确认"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"此时不保存密码"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
- <string name="save_password_never" msgid="8274330296785855105">"从不"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"您无权打开此网页。"</string>
- <string name="text_copied" msgid="4985729524670131385">"文字已复制到剪贴板。"</string>
- <string name="more_item_label" msgid="4650918923083320495">"更多"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"空格"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter 键"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"删除"</string>
- <string name="search_go" msgid="8298016669822141719">"搜索"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月前"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月前"</string>
+ <string name="save_password_message">"是否希望浏览器记住此密码?"</string>
+ <string name="save_password_notnow">"此时不保存密码"</string>
+ <string name="save_password_remember">"记住"</string>
+ <string name="save_password_never">"从不"</string>
+ <string name="open_permission_deny">"您无权打开此网页。"</string>
+ <string name="text_copied">"文字已复制到剪贴板。"</string>
+ <string name="more_item_label">"更多"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"空格"</string>
+ <string name="menu_enter_shortcut_label">"Enter 键"</string>
+ <string name="menu_delete_shortcut_label">"删除"</string>
+ <string name="search_go">"搜索"</string>
+ <string name="oneMonthDurationPast">"1 个月前"</string>
+ <string name="beforeOneMonthDurationPast">"1 个月前"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
+ <item quantity="one">"1 秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分钟前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分钟前"</item>
+ <item quantity="one">"1 分钟前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟前"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 小时前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小时前"</item>
+ <item quantity="one">"1 小时前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时前"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒后"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> 秒后"</item>
+ <item quantity="one">"1 秒后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒后"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分钟后"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> 分钟后"</item>
+ <item quantity="one">"1 分钟后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟后"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 小时后"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小时后"</item>
+ <item quantity="one">"1 小时后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时后"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
+ <item quantity="one">"1 秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分钟前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分钟前"</item>
+ <item quantity="one">"1 分钟前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟前"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 小时前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小时前"</item>
+ <item quantity="one">"1 小时前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时前"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒后"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒后"</item>
+ <item quantity="one">"1 秒后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒后"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分钟后"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分钟后"</item>
+ <item quantity="one">"1 分钟后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟后"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 小时后"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小时后"</item>
+ <item quantity="one">"1 小时后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时后"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"在 %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"在%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s 年"</string>
- <string name="day" msgid="8144195776058119424">"天"</string>
- <string name="days" msgid="4774547661021344602">"天"</string>
- <string name="hour" msgid="2126771916426189481">"小时"</string>
- <string name="hours" msgid="894424005266852993">"小时"</string>
- <string name="minute" msgid="9148878657703769868">"分钟"</string>
- <string name="minutes" msgid="5646001005827034509">"分钟"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"周"</string>
- <string name="weeks" msgid="6509623834583944518">"周"</string>
- <string name="year" msgid="4001118221013892076">"年"</string>
- <string name="years" msgid="6881577717993213522">"年"</string>
- <string name="every_weekday" msgid="8777593878457748503">"每个工作日(周一至周五)"</string>
- <string name="daily" msgid="5738949095624133403">"每天"</string>
- <string name="weekly" msgid="983428358394268344">"每周的<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"每月"</string>
- <string name="yearly" msgid="1519577999407493836">"每年"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"无法播放视频"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"抱歉,该视频不适合在此设备上播放。"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"很抱歉,无法播放此视频。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"确定"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"中午"</string>
- <string name="Noon" msgid="3342127745230013127">"中午"</string>
- <string name="midnight" msgid="7166259508850457595">"午夜"</string>
- <string name="Midnight" msgid="5630806906897892201">"午夜"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"全选"</string>
- <string name="selectText" msgid="3889149123626888637">"选择文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"停止选择文字"</string>
- <string name="cut" msgid="3092569408438626261">"剪切"</string>
- <string name="cutAll" msgid="2436383270024931639">"全部剪切"</string>
- <string name="copy" msgid="2681946229533511987">"复制"</string>
- <string name="copyAll" msgid="2590829068100113057">"全部复制"</string>
- <string name="paste" msgid="5629880836805036433">"粘贴"</string>
- <string name="copyUrl" msgid="2538211579596067402">"复制网址"</string>
- <string name="inputMethod" msgid="7673923508389094672">"输入法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"将“%s”添加到词典"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"编辑文字"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"空间不足"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"手机存储空间正在减少。"</string>
- <string name="ok" msgid="5970060430562524910">"确定"</string>
- <string name="cancel" msgid="6442560571259935130">"取消"</string>
- <string name="yes" msgid="5362982303337969312">"确定"</string>
- <string name="no" msgid="5141531044935541497">"取消"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"注意事项"</string>
- <string name="capital_on" msgid="1544682755514494298">"开启"</string>
- <string name="capital_off" msgid="6815870386972805832">"关闭"</string>
- <string name="whichApplication" msgid="4533185947064773386">"使用以下内容完成操作"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"默认用于执行此操作。"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除“主屏幕设置”>“应用程序”>“管理应用程序”中的默认设置。"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"选择一项操作"</string>
- <string name="noApplications" msgid="1691104391758345586">"没有应用程序可执行此操作。"</string>
- <string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程序(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)意外停止,请重试。"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程意外停止,请重试。"</string>
- <string name="anr_title" msgid="3100070910664756057">"很抱歉!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在<xliff:g id="APPLICATION">%2$s</xliff:g>应用程序中)无响应。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在 <xliff:g id="PROCESS">%2$s</xliff:g> 进程中)无响应。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程序(在 <xliff:g id="PROCESS">%2$s</xliff:g> 进程中)无响应。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程无响应。"</string>
- <string name="force_close" msgid="3653416315450806396">"强行关闭"</string>
+ <string name="preposition_for_date">"在 %s"</string>
+ <string name="preposition_for_time">"在%s"</string>
+ <string name="preposition_for_year">"%s 年"</string>
+ <string name="day">"天"</string>
+ <string name="days">"天"</string>
+ <string name="hour">"小时"</string>
+ <string name="hours">"小时"</string>
+ <string name="minute">"分钟"</string>
+ <string name="minutes">"分钟"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"周"</string>
+ <string name="weeks">"周"</string>
+ <string name="year">"年"</string>
+ <string name="years">"年"</string>
+ <string name="every_weekday">"每个工作日(周一至周五)"</string>
+ <string name="daily">"每天"</string>
+ <string name="weekly">"每周的<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"每月"</string>
+ <string name="yearly">"每年"</string>
+ <string name="VideoView_error_title">"无法播放视频"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"抱歉,该视频不适合在此设备上播放。"</string>
+ <string name="VideoView_error_text_unknown">"很抱歉,无法播放此视频。"</string>
+ <string name="VideoView_error_button">"确定"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"中午"</string>
+ <string name="Noon">"中午"</string>
+ <string name="midnight">"午夜"</string>
+ <string name="Midnight">"午夜"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"全选"</string>
+ <string name="selectText">"选择文字"</string>
+ <string name="stopSelectingText">"停止选择文字"</string>
+ <string name="cut">"剪切"</string>
+ <string name="cutAll">"全部剪切"</string>
+ <string name="copy">"复制"</string>
+ <string name="copyAll">"全部复制"</string>
+ <string name="paste">"粘贴"</string>
+ <string name="copyUrl">"复制网址"</string>
+ <string name="inputMethod">"输入法"</string>
+ <string name="addToDictionary">"将“%s”添加到词典"</string>
+ <string name="editTextMenuTitle">"编辑文字"</string>
+ <string name="low_internal_storage_view_title">"空间不足"</string>
+ <string name="low_internal_storage_view_text">"手机存储空间正在减少。"</string>
+ <string name="ok">"确定"</string>
+ <string name="cancel">"取消"</string>
+ <string name="yes">"确定"</string>
+ <string name="no">"取消"</string>
+ <string name="dialog_alert_title">"注意事项"</string>
+ <string name="capital_on">"开启"</string>
+ <string name="capital_off">"关闭"</string>
+ <string name="whichApplication">"使用以下内容完成操作"</string>
+ <string name="alwaysUse">"默认用于执行此操作。"</string>
+ <string name="clearDefaultHintMsg">"清除“主屏幕设置”>“应用程序”>“管理应用程序”中的默认设置。"</string>
+ <string name="chooseActivity">"选择一项操作"</string>
+ <string name="noApplications">"没有应用程序可执行此操作。"</string>
+ <string name="aerr_title">"很抱歉!"</string>
+ <string name="aerr_application">"应用程序<xliff:g id="APPLICATION">%1$s</xliff:g>(进程 <xliff:g id="PROCESS">%2$s</xliff:g>)意外停止,请重试。"</string>
+ <string name="aerr_process">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 已意外停止,请重试。"</string>
+ <string name="anr_title">"很抱歉!"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在 <xliff:g id="APPLICATION">%2$s</xliff:g>应用程序中)无响应。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在<xliff:g id="PROCESS">%2$s</xliff:g>进程中)无响应。"</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程序(在<xliff:g id="PROCESS">%2$s</xliff:g>进程中)无响应。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>进程无响应。"</string>
+ <string name="force_close">"强行关闭"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"等待"</string>
- <string name="debug" msgid="9103374629678531849">"调试"</string>
- <string name="sendText" msgid="5132506121645618310">"选择要对文字执行的操作"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"铃声音量"</string>
- <string name="volume_music" msgid="5421651157138628171">"媒体音量"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"通过蓝牙播放"</string>
- <string name="volume_call" msgid="3941680041282788711">"通话音量"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"使用蓝牙时的通话音量"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"闹钟音量"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音量"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音量"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"默认铃声"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"静音"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"铃声"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"未知铃声"</string>
+ <string name="wait">"等待"</string>
+ <string name="debug">"调试"</string>
+ <string name="sendText">"选择要对文字执行的操作"</string>
+ <string name="volume_ringtone">"铃声音量"</string>
+ <string name="volume_music">"媒体音量"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"通过蓝牙播放"</string>
+ <string name="volume_call">"通话音量"</string>
+ <string name="volume_bluetooth_call">"使用蓝牙时的通话音量"</string>
+ <string name="volume_alarm">"闹钟音量"</string>
+ <string name="volume_notification">"通知音量"</string>
+ <string name="volume_unknown">"音量"</string>
+ <string name="ringtone_default">"默认铃声"</string>
+ <string name="ringtone_default_with_actual">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"静音"</string>
+ <string name="ringtone_picker_title">"铃声"</string>
+ <string name="ringtone_unknown">"未知铃声"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"有可用的 Wi-Fi 网络"</item>
- <item quantity="other" msgid="4192424489168397386">"有可用的 Wi-Fi 网络"</item>
+ <item quantity="one">"有可用的 Wi-Fi 网络"</item>
+ <item quantity="other">"有可用的 Wi-Fi 网络"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"打开可用的 Wi-Fi 网络"</item>
- <item quantity="other" msgid="7915895323644292768">"打开可用的 Wi-Fi 网络"</item>
+ <item quantity="one">"打开可用的 Wi-Fi 网络"</item>
+ <item quantity="other">"打开可用的 Wi-Fi 网络"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"插入字符"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"未知的应用程序"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"正在发送大量短信。选择“确定”继续,或选择“取消”停止发送。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"确定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
- <string name="date_time_set" msgid="5777075614321087758">"设置"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"默认"</string>
- <string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"隐藏"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"全部显示"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"正在载入..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB 已连接"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"您已通过 USB 将手机连接至计算机。如果要在计算机和手机的 SD 卡之间复制文件,请选择“安装”。"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"安装"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"不安装"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"使用 SD 卡进行 USB 存储时出现问题。"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 已连接"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"选择以将文件复制到计算机/从计算机复制文件。"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"关闭 USB 存储设备"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"选中以关闭 USB 存储设备。"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"关闭 USB 存储设备"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"在关闭 USB 存储设备前,请确保您已卸载了 USB 主设备。选择“关闭”关闭 USB 存储设备。"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"关闭"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"取消"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"关闭 USB 存储设备时遇到问题。请检查是否卸载了 USB 主设备,然后重试。"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"格式化 SD 卡"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"您确定要格式化 SD 卡?卡上的所有数据都会丢失。"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"格式化"</string>
+ <string name="select_character">"插入字符"</string>
+ <string name="sms_control_default_app_name">"未知的应用程序"</string>
+ <string name="sms_control_title">"正在发送短信"</string>
+ <string name="sms_control_message">"正在发送大量短信。选择“确定”继续,或选择“取消”停止发送。"</string>
+ <string name="sms_control_yes">"确定"</string>
+ <string name="sms_control_no">"取消"</string>
+ <string name="date_time_set">"设置"</string>
+ <string name="default_permission_group">"默认"</string>
+ <string name="no_permissions">"不需要任何权限"</string>
+ <string name="perms_hide"><b>"隐藏"</b></string>
+ <string name="perms_show_all"><b>"全部显示"</b></string>
+ <string name="googlewebcontenthelper_loading">"正在载入..."</string>
+ <string name="usb_storage_title">"USB 已连接"</string>
+ <string name="usb_storage_message">"您已通过 USB 将手机连接至计算机。如果要在计算机和手机的 SD 卡之间复制文件,请选择“安装”。"</string>
+ <string name="usb_storage_button_mount">"安装"</string>
+ <string name="usb_storage_button_unmount">"不安装"</string>
+ <string name="usb_storage_error_message">"使用 SD 卡进行 USB 存储时出现问题。"</string>
+ <string name="usb_storage_notification_title">"USB 已连接"</string>
+ <string name="usb_storage_notification_message">"选择以将文件复制到计算机/从计算机复制文件。"</string>
+ <string name="usb_storage_stop_notification_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_notification_message">"选中以关闭 USB 存储设备。"</string>
+ <string name="usb_storage_stop_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_message">"在关闭 USB 存储设备前,请确保您已卸载了 USB 主设备。选择“关闭”关闭 USB 存储设备。"</string>
+ <string name="usb_storage_stop_button_mount">"关闭"</string>
+ <string name="usb_storage_stop_button_unmount">"取消"</string>
+ <string name="usb_storage_stop_error_message">"关闭 USB 存储设备时遇到问题。请检查是否卸载了 USB 主设备,然后重试。"</string>
+ <string name="extmedia_format_title">"格式化 SD 卡"</string>
+ <string name="extmedia_format_message">"您确定要格式化 SD 卡?卡上的所有数据都会丢失。"</string>
+ <string name="extmedia_format_button_format">"格式化"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"选择输入法"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"正在准备 SD 卡"</string>
+ <string name="select_input_method">"选择输入法"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候选"</u></string>
+ <string name="ext_media_checking_notification_title">"正在准备 SD 卡"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"空 SD 卡"</string>
+ <string name="ext_media_nofs_notification_title">"空 SD 卡"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"SD 卡受损"</string>
+ <string name="ext_media_unmountable_notification_title">"SD 卡受损"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD 卡被意外拔除"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"先卸载 SD 卡再拔除,以避免数据丢失。"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD 卡已安全移除"</string>
+ <string name="ext_media_badremoval_notification_title">"SD 卡被意外拔除"</string>
+ <string name="ext_media_badremoval_notification_message">"先卸载 SD 卡再拔除,以避免数据丢失。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD 卡已安全移除"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"已移除 SD 卡"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD 卡"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"找不到匹配的活动"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"更新组件使用情况统计"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"允许修改收集的组件使用情况统计。普通应用程序不能使用此权限。"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"双击可以进行缩放控制"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"放大窗口小部件时出错"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"开始"</string>
- <string name="ime_action_search" msgid="658110271822807811">"搜索"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"发送"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"下一步"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完成"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"执行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"拨打电话"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"创建电话号码为"\n"<xliff:g id="NUMBER">%s</xliff:g> 的联系人"</string>
+ <string name="activity_list_empty">"找不到匹配的活动"</string>
+ <string name="permlab_pkgUsageStats">"更新组件使用情况统计"</string>
+ <string name="permdesc_pkgUsageStats">"允许修改收集的组件使用情况统计。普通应用程序不能使用此权限。"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"双击可以进行缩放控制"</string>
+ <string name="gadget_host_error_inflating">"放大窗口小部件时出错"</string>
+ <string name="ime_action_go">"开始"</string>
+ <string name="ime_action_search">"搜索"</string>
+ <string name="ime_action_send">"发送"</string>
+ <string name="ime_action_next">"下一步"</string>
+ <string name="ime_action_done">"完成"</string>
+ <string name="ime_action_default">"执行"</string>
+ <string name="dial_number_using">"拨打电话"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"创建电话号码为"\n"<xliff:g id="NUMBER">%s</xliff:g> 的联系人"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d0126ab..f355a71 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -15,697 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"位元組"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"(未命名)"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(沒有電話號碼)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(未知的)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"語音留言"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"連線發生問題或錯誤的 MMI 碼。"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"服務已啟用。"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"已啟用服務:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"服務已停用。"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"註冊成功。"</string>
- <string name="serviceErased" msgid="1288584695297200972">"清除成功。"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"密碼錯誤。"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 完成。"</string>
- <string name="badPin" msgid="5085454289896032547">"您輸入的舊 PIN 不正確。"</string>
- <string name="badPuk" msgid="5702522162746042460">"您輸入的 PUK 不正確。"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"您輸入的 PIN 不符合。"</string>
- <string name="invalidPin" msgid="3850018445187475377">"輸入 4~8 個數字的 PIN。"</string>
- <string name="needPuk" msgid="919668385956251611">"SIM 卡的 PUK 已鎖定。請輸入 PUK 碼解除鎖定。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"請輸入 PUK2 以解鎖 SIM 卡。"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"來電顯示"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"本機號碼"</string>
- <string name="CfMmi" msgid="5123218989141573515">"來電轉接"</string>
- <string name="CwMmi" msgid="9129678056795016867">"來電待接"</string>
- <string name="BaMmi" msgid="455193067926770581">"通話限制"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"變更密碼"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN 已變更"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"顯示來電號碼"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"隱藏發話號碼"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"三方通話"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"拒接不想接聽的騷擾電話"</string>
- <string name="CndMmi" msgid="3116446237081575808">"顯示發話號碼"</string>
- <string name="DndMmi" msgid="1265478932418334331">"勿干擾"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"預設不顯示本機號碼,下一通電話也不顯示。"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"預設不顯示本機號碼,但下一通電話顯示。"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"預設顯示本機號碼,但下一通電話不顯示。"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"預設顯示本機號碼,下一通電話也繼續顯示。"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"無法提供此服務。"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"本機號碼顯示設定無法變更。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"受限存取已變更"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"已封鎖資料傳輸服務。"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"已封鎖緊急服務。"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"已封鎖語音/SMS 服務。"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"已封鎖所有語音/SMS 服務。"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"語音"</string>
- <string name="serviceClassData" msgid="872456782077937893">"資料"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"傳真"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"非同步"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"同步處理"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"封包"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"按鍵"</string>
- <string name="roamingText0" msgid="7170335472198694945">"漫遊指示開啟"</string>
- <string name="roamingText1" msgid="5314861519752538922">"漫遊指示關閉"</string>
- <string name="roamingText2" msgid="8969929049081268115">"漫遊指示閃爍"</string>
- <string name="roamingText3" msgid="5148255027043943317">"超出鄰近範圍"</string>
- <string name="roamingText4" msgid="8808456682550796530">"超出建築物範圍"</string>
- <string name="roamingText5" msgid="7604063252850354350">"漫遊 - 偏好系統"</string>
- <string name="roamingText6" msgid="2059440825782871513">"漫遊 - 可用系統"</string>
- <string name="roamingText7" msgid="7112078724097233605">"漫遊 - 聯盟合作夥伴"</string>
- <string name="roamingText8" msgid="5989569778604089291">"漫遊 - Google Premium 合作夥伴"</string>
- <string name="roamingText9" msgid="7969296811355152491">"漫遊 - 完整服務功能"</string>
- <string name="roamingText10" msgid="3992906999815316417">"漫遊 - 部份服務功能"</string>
- <string name="roamingText11" msgid="4154476854426920970">"漫遊橫幅開啟"</string>
- <string name="roamingText12" msgid="1189071119992726320">"漫遊橫幅關閉"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"正在搜尋服務"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="fcComplete" msgid="3118848230966886575">"功能碼輸入完成。"</string>
- <string name="fcError" msgid="3327560126588500777">"連線發生問題或功能碼無效。"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"確定"</string>
- <string name="httpError" msgid="2567300624552921790">"網頁內容錯誤。"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"找不到網址。"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"不支援此網站驗證機制。"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"驗證失敗。"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"透過 proxy 伺服器驗證失敗。"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"連線到伺服器失敗。"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"無法與伺服器溝通,請稍後再試一次 。"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"連線到伺服器逾時。"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"此網頁包含太多伺服器轉址。"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"不支援此通訊協定。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"無法建立安全連線。"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"由於網址錯誤,無法開啟此網頁。"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"無法存取此檔案。"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"找不到要求的檔案。"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"太多執行要求。請稍後再試一次。"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"同步處理"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步處理"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
- <string name="low_memory" msgid="6632412458436461203">"手機儲存空間已滿!請刪除一些檔案增加空間。"</string>
- <string name="me" msgid="6545696007631404292">"我"</string>
- <string name="power_dialog" msgid="1319919075463988638">"電話選項"</string>
- <string name="silent_mode" msgid="7167703389802618663">"靜音模式"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"開啟無線網路"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"關閉無線網路"</string>
- <string name="screen_lock" msgid="799094655496098153">"螢幕鎖定"</string>
- <string name="power_off" msgid="4266614107412865048">"關機"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"關機中..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"手機即將關機。"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"最近沒有存取應用程式。"</string>
- <string name="global_actions" msgid="2406416831541615258">"電話選項"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"靜音模式"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"音效已關閉"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"音效已開啟"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
- <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要額外費用的服務。"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"若您允許應用程式執行此操作,可能需要支付一些費用。"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"讀取編輯 SMS、電子郵件與其他簡訊。"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"您的個人資訊"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"直接存取手機上的聯絡人與日曆。"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"您的位置"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"監視實際位置"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"網路通訊"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"允許應用程式存取多項網路功能。"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"您的 Google 帳戶"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"存取可用 Google 帳戶。"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬體控制"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"在免持設備上直接存取硬體。"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"撥打電話"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"監控、記錄與進行通話。"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"系統工具"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"系統低階存取與控制。"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"開發工具"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"只有開發者需要此功能。"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"儲存"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"存取 SD 卡。"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"停用或變更狀態列"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"允許應用程式停用狀態列或新增、移除系統圖示。"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"展開/收攏狀態列"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"允許應用程式展開或收攏狀態列。"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"攔截撥出電話"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"允許應用程式處理撥出電話及變更撥號。請注意:惡意程式可能藉以監控,轉接或阻擋電話撥出。"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"接收 SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"允許應用程式接收、處理 SMS 簡訊。請注意:惡意程式可能使用此功能監控簡訊或在您讀取前擅自刪除。"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"接收 MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"允許應用程式接收、處理 MMS 簡訊。請注意:惡意程式可能使用此功能監控簡訊或在您讀取前擅自刪除。"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"傳送 SMS 簡訊"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"允許應用程式傳送 SMS 簡訊。請注意:惡意程式可能會擅自傳送簡訊,增加您的支出。"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"讀取 SMS 或 MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"允許應用程式讀取手機或 SIM 卡上的 SMS 簡訊。請注意:惡意程式可能會利用此功能讀取您的機密簡訊。"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"編輯 SMS 或 MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"允許應用程式編輯 SMS 簡訊,存入手機或 SIM 卡。請注意:惡意程式可能會刪除您的簡訊。"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"接收 WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可能利用此功能終止其他應用程式。"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"取得執行中應用程式"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"允許應用程式取得最近執行任務的資訊。請注意:惡意程式可能利用此功能找出其他應用程式的隱私資訊。"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"重新安排執行中的應用程式"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程式偵錯"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"允許應用程式變更目前設定,例如:地區設定或字型大小。"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"重新啟動其他應用程式"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"允許應用程式強制重新啟動其他應用程式。"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"強制關閉應用程式"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"允許應用程式強制關閉在前端運作的活動並返回。一般應用程式不需要此功能。"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"接收系統內部狀態"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"允許應用程式取得系統內部狀態。請注意:惡意程式可能利用此功能,不當取得私人或安全性資料。"</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"防止使用者切換到其他應用程式。"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"監視控制所有應用程式啟動狀態。"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"允許應用程式監控管理系統啟動活動。請注意:惡意程式可能因此癱瘓整個系統。此權限只在開發時需要,一般手機使用不需要此權限。"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳送程式已移除廣播"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"允許應用程式在其他應用程式被移除時發送通知。請注意:惡意程式可能利用此功能,關閉其他執行中的程式。"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"傳送已接收 SMS 廣播"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"允許應用程式在收到 SMS 簡訊時發出通知。請注意:惡意程式可能利用此功能偽造 SMS 簡訊。"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"送出「WAP PUSH 已接收」廣播"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"允許應用程式在收到 WAP PUSH 簡訊時發送通知。請注意:惡意程式可能利用此功能,偽造 MMS 簡訊回條或秘密更換網頁內容。"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序限制數"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"允許應用程式控制可使用的最大執行緒。一般應用程式不需要此功能。"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"關閉所有背景程式"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"允許應用程式控制哪些活動在被移到背景執行時,儘速結束。一般應用程式不需要此功能。"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"編輯電池狀態"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"允許修改電池狀態。一般應用程式不會使用此功能。"</string>
- <string name="permlab_backup" msgid="470013022865453920">"控制系統備份與還原"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"允許應用程式控制系統備份與還原機制,但一般應用程式不會使用此功能。"</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允許內部系統使用介面建立視窗。一般應用程式不會使用此功能。"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"顯示系統警示"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"允許應用程式顯示系統警告視窗。請注意:惡意程式可使用此功能接管手機螢幕。"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"編輯全域動畫速度"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"允許應用程式變更全域動畫速度 (更快或更慢)。"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"管理應用程式 token"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"允許應用程式略過一般 Z-ordering,建立與管理自己的 token。一般應用程式不需要此功能。"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"按鍵及控制按鈕"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"允許應用程式發送輸入事件 (按鍵等) 給其他應用程式。請注意:惡意程式可能使用此功能接管手機。"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"記錄您的輸入內容與操作"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"允許應用程式在使用者操作其他程式時 (例如:輸入密碼),仍可監看輸入的按鍵。一般應用程式應不需要此功能。"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"連結至輸入法"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"允許擁有人連結至輸入法的最頂層介面。一般應用程式不需使用此選項。"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"允許應用程式隨時變更螢幕顯示方向。一般應用程式不需要此功能。"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"傳送 Linux 訊號到應用程式"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允許應用程式要求將支援的訊號傳送到所有持續的程序。"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"設定應用程式持續執行"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"允許應用程式持續執行,避免系統將它應用到其他程式。"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"刪除應用程式"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"允許應用程式刪除 Android 程式。請注意:惡意程式可能利用此功能刪除重要應用程式。"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"刪除其他應用程式資料"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"允許應用程式清除使用者資料。"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"刪除其他應用程式快取"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"允許應用程式刪除快取檔案。"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"估算應用程式占用的儲存空間"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"允許應用程式取得程式碼、資料與快取大小"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"直接安裝應用程式"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"允許應用程式安裝新的 Android 程式或更新。請注意:惡意程式可能利用此功能新增具有極高權限的程式。"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"刪除所有應用程式快取資料。"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"允許應用程式刪除快取目錄裡的檔案,釋放儲存空間。此操作通常受到系統程序嚴格限制。"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"讀取系統記錄檔"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"允許應用程式讀取系統記錄檔。此項操作可讓應用程式了解目前手機操作狀態,但內容應不含任何個人或隱私資訊。"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"允許應用程式讀寫 diag 群組的資源;例如:/dev 裡的檔案。這可能會影響系統穩定性與安全性。此功能僅供製造商或技術人員用於硬體規格偵測。"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"啟用或停用應用程式元件"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"允許應用程式變更是否啟用其他元件或應用程式。請注意:惡意程式可能利用此功能,停用重要的手機功能。由於此功能可能導致應用程式元件無法使用、不一致或不穩定,請小心斟酌授權。"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"設定喜好的應用程式"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"允許應用程式修改您偏好的應用程式。請注意:惡意程式可能藉以秘密竄改執行的程式,或偽造已存在的程式以收集私人資料。"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"編輯全域系統設定"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"允許應用程式修改系統設定。請注意:惡意程式可能使用此功能損毀系統設定。"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"編輯安全系統設定"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"允許應用程式修改系統的安全設定資料。一般應用程式不會使用此功能。"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"修改 Google 服務地圖"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"允許應用程式修改 Google 服務地圖。一般應用程式不會使用此功能。"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"開機時自動啟用"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"允許應用程式在開機後盡快啟動。此項設定會讓開機時間拉長,並允許應用程式持續執行,因此拖慢手機速度。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"傳送附屬廣播"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"允許應用程式傳送持久的廣播。請注意:惡意程式可能利用此功能來佔據過多記憶體,讓手機速度變慢或不穩定。"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"讀取聯絡人資料"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"允許應用程式讀取手機上所有聯絡人 (地址)。請注意:惡意程式可能利用此功能將您的資料傳送給其他人。"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"輸入聯絡人資料"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"允許應用程式更改聯絡資訊 (地址)。請注意:惡意程式可能利用此功能,清除或修改聯絡資料。"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"寫入持有者的資料"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"允許應用程式更改手機持有者的資料。請注意:惡意程式可能利用此功能,清除或修改持有者的資料。"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"讀取持有者的資料"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"允許應用程式讀取手機持有者資料。請注意:惡意程式可能利用此功能讀取持有者的資料。"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"讀取日曆資料"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"允許應用程式讀取手機上所有日曆資料。請注意:惡意程式可能利用此功能將您的日曆資料傳送給其他人。"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"寫入日曆資料"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"允許應用程式編輯日曆資料。請注意:惡意程式可能利用此功能,清除或修改您的日曆資料。"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"模擬位置來源以供測試"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"建立模擬位置來源以供測試。請注意:惡意程式可能利用此功能覆寫 GPS 或電信業者傳回的位置及/或狀態。"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收額外的位置提供者指令"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"存取額外位置提供者命令。請注意:惡意程式可能利用此功能干擾 GPS 或其他位置來源。"</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"准許安裝位置提供者"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"建立虛構的位置來源以供測試。請注意:惡意應用程式可能利用此選項覆寫由真實位置來源 (例如 GPS 或網路供應商) 所傳回的位置及/或狀態,或者監控您的位置並將之提供給外部來源。"</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"精確定位 (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"接收精確的位置來源 (例如:手機 GPS)。請注意:惡意程式可能使用此功能得知您的位置,並可能消耗額外電源。"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"約略位置 (以網路為基準)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"接收約略的位置來源 (例如:行動網路資料庫),計算出目前大概位置。請注意:惡意程式可能使用此功能得知您的所在地。"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"存取 SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"允許應用程式使用 SurfaceFlinger 低階功能。"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"讀取框架緩衝"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"允許應用程式讀取框架緩衝的內容。"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"變更音訊設定"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"允許應用程式編輯全域音訊設定,例如音量與路由。"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"錄製音訊"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"允許應用程式存取音訊錄製路徑。"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"照相"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"允許應用程式使用相機拍照。此功能可讓應用程式隨時透過相機拍攝照片。"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"永久停用電話"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"允許應用程式永久停用手機。此項操作非常危險。"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"強制重開機"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"允許應用程式強制重開機。"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"掛載/卸載檔案系統"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"允許應用程式掛載/卸載抽取式儲存設備的檔案系統。"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"將外接式儲存裝置格式化"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"允許應用程式將可移除式儲存裝置格式化。"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"控制震動"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"允許應用程式控制震動。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"允許應用程式控制閃光燈。"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"測試硬體"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"允許應用程式控制各種週邊設備,以供測試用。"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"允許應用程式自行撥打電話。請注意:惡意程式可能任意撥打電話,造成預期外的支出。但此選項並不允許應用程式撥打緊急電話號碼。"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"直接撥打任何電話號碼"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"允許應用程式自行撥打任何電話號碼,包括緊急電話號碼。請注意:惡意程式可能利用此功能濫用緊急服務,撥打不必要或違法的電話。"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"存取登機選項"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"選擇小工具"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"允許應用程式告知系統哪個應用程式可以使用哪些小工具。開啟此權限後,應用程式會讓其他程式使用個人資料,但一般應用程式不適合使用此功能。"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手機狀態"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"允許應用程式控制電話功能。擁有此權限的程式可自行切換網路、開關無線通訊功能。"</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"防止手機進入待命狀態"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"允許應用程式防止手機進入待命。"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"開啟或關閉電源"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"允許應用程式開啟或關閉電話。"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"在出廠測試模式下執行"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"執行低階製造商測試,允許完全存取手機硬體。此功能只能在手機是製造商測試模式下才可執行。"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"設定桌布"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"允許應用程式設定系統桌布。"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"設定桌布大小提示"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"允許應用程式設定系統桌布大小提示。"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"將系統還原至出廠預設值"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"允許應用程式將手機完全重設至出廠設定,清除所有資料、設定與已安裝程式。"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"設定時區"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"允許應用程式變更時區。"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"發現已知帳戶。"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"允許應用程式取得手機上的帳戶清單。"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"檢視網路狀態"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"允許應用程式檢視網路狀態。"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"網際網路完整存取"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"允許應用程式建立網路設定。"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"輸入存取點名稱設定"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"允許應用程式修改 APN 設定,例如:Proxy 及 APN 的連接埠。"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"變更網路連線"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"允許應用程式變更網路連線狀態。"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"變更背景資料使用設定"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"允許應用程式變更背景資料使用設定。"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"檢視 Wi-Fi 狀態"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"允許應用程式檢視 Wi-Fi 狀態資訊。"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"變更 Wi-Fi 狀態"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"允許應用程式與 Wi-Fi 存取點連線或中斷連線,並可變更 Wi-Fi 網路設定。"</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"允許接收 Wi-Fi 多點傳播封包"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"允許應用程式接收並非指定傳送給您裝置的封包,這在您發現附近有服務可使用時很有用,但消耗的電力比非多點傳播模式還要多。"</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"藍牙管理"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"允許應用程式設定本機藍牙電話,以及偵測與配對其他遠端裝置。"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"建立藍牙連線"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"允許應用程式檢視本機藍牙電話設定,並與其他配對裝置連線。"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"停用按鍵鎖定"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"允許應用程式停用按鍵鎖定以及其他相關的密碼安全性。例如:收到來電時解除按鍵鎖定,通話結束後重新啟動按鍵鎖定。"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"允許應用程式讀取同步處理設定,例如:是否同步處理 [聯絡人]。"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"編輯同步處理設定"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"允許應用程式修改同步處理設定,例如:是否要同步處理 [聯絡人]。"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"讀取同步處理狀態"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"允許應用程式讀取同步處理狀態;例如:同步處理記錄。"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"讀取訂閱資訊提供"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"允許應用程式取得目前已同步處理的資訊提供。"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"寫入訂閱資訊提供"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"允許應用程式修改已同步處理的資訊提供。請注意:惡意程式可能使用此功能變更已同步處理的資訊提供。"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"讀取使用者定義的字典"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"允許應用程式讀取使用者儲存在使用者字典內的任何私人字詞、名稱和詞組。"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"寫入使用者定義的字典"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"允許應用程式將新字詞寫入使用者的字典。"</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"修改/刪除 SD 卡的內容"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"允許應用程式寫入 SD 卡。"</string>
+ <string name="byteShort">"位元組"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"(未命名)"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(沒有電話號碼)"</string>
+ <string name="unknownName">"(未知的)"</string>
+ <string name="defaultVoiceMailAlphaTag">"語音留言"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"連線發生問題或錯誤的 MMI 碼。"</string>
+ <string name="serviceEnabled">"服務已啟用。"</string>
+ <string name="serviceEnabledFor">"已啟用服務:"</string>
+ <string name="serviceDisabled">"服務已停用。"</string>
+ <string name="serviceRegistered">"註冊成功。"</string>
+ <string name="serviceErased">"清除成功。"</string>
+ <string name="passwordIncorrect">"密碼錯誤。"</string>
+ <string name="mmiComplete">"MMI 完成。"</string>
+ <string name="badPin">"您輸入的舊 PIN 不正確。"</string>
+ <string name="badPuk">"您輸入的 PUK 不正確。"</string>
+ <string name="mismatchPin">"您輸入的 PIN 不符合。"</string>
+ <string name="invalidPin">"輸入 4~8 個數字的 PIN。"</string>
+ <string name="needPuk">"SIM 卡的 PUK 已鎖定。請輸入 PUK 碼解除鎖定。"</string>
+ <string name="needPuk2">"請輸入 PUK2 以解鎖 SIM 卡。"</string>
+ <string name="ClipMmi">"來電顯示"</string>
+ <string name="ClirMmi">"本機號碼"</string>
+ <string name="CfMmi">"來電轉接"</string>
+ <string name="CwMmi">"來電待接"</string>
+ <string name="BaMmi">"通話限制"</string>
+ <string name="PwdMmi">"變更密碼"</string>
+ <string name="PinMmi">"PIN 已變更"</string>
+ <string name="CnipMmi">"顯示來電號碼"</string>
+ <string name="CnirMmi">"隱藏發話號碼"</string>
+ <string name="ThreeWCMmi">"三方通話"</string>
+ <string name="RuacMmi">"拒接不想接聽的騷擾電話"</string>
+ <string name="CndMmi">"顯示發話號碼"</string>
+ <string name="DndMmi">"勿干擾"</string>
+ <string name="CLIRDefaultOnNextCallOn">"預設不顯示本機號碼,下一通電話也不顯示。"</string>
+ <string name="CLIRDefaultOnNextCallOff">"預設不顯示本機號碼,但下一通電話顯示。"</string>
+ <string name="CLIRDefaultOffNextCallOn">"預設顯示本機號碼,但下一通電話不顯示。"</string>
+ <string name="CLIRDefaultOffNextCallOff">"預設顯示本機號碼,下一通電話也繼續顯示。"</string>
+ <string name="serviceNotProvisioned">"無法提供此服務。"</string>
+ <string name="CLIRPermanent">"本機號碼顯示設定無法變更。"</string>
+ <string name="RestrictedChangedTitle">"受限存取已變更"</string>
+ <string name="RestrictedOnData">"已封鎖資料傳輸服務。"</string>
+ <string name="RestrictedOnEmergency">"已封鎖緊急服務。"</string>
+ <string name="RestrictedOnNormal">"已封鎖語音/SMS 服務。"</string>
+ <string name="RestrictedOnAll">"已封鎖所有語音/SMS 服務。"</string>
+ <string name="serviceClassVoice">"語音"</string>
+ <string name="serviceClassData">"資料"</string>
+ <string name="serviceClassFAX">"傳真"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"非同步"</string>
+ <string name="serviceClassDataSync">"同步處理"</string>
+ <string name="serviceClassPacket">"封包"</string>
+ <string name="serviceClassPAD">"按鍵"</string>
+ <string name="roamingText0">"漫遊指示開啟"</string>
+ <string name="roamingText1">"漫遊指示關閉"</string>
+ <string name="roamingText2">"漫遊指示閃爍"</string>
+ <string name="roamingText3">"超出鄰近範圍"</string>
+ <string name="roamingText4">"超出建築物範圍"</string>
+ <string name="roamingText5">"漫遊 - 偏好系統"</string>
+ <string name="roamingText6">"漫遊 - 可用系統"</string>
+ <string name="roamingText7">"漫遊 - 聯盟合作夥伴"</string>
+ <string name="roamingText8">"漫遊 - Google Premium 合作夥伴"</string>
+ <string name="roamingText9">"漫遊 - 完整服務功能"</string>
+ <string name="roamingText10">"漫遊 - 部份服務功能"</string>
+ <string name="roamingText11">"漫遊橫幅開啟"</string>
+ <string name="roamingText12">"漫遊橫幅關閉"</string>
+ <string name="roamingTextSearching">"正在搜尋服務"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="fcComplete">"功能碼輸入完成。"</string>
+ <string name="fcError">"連線發生問題或功能碼無效。"</string>
+ <string name="httpErrorOk">"確定"</string>
+ <string name="httpError">"網頁內容錯誤。"</string>
+ <string name="httpErrorLookup">"找不到網址。"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"不支援此網站驗證機制。"</string>
+ <string name="httpErrorAuth">"驗證失敗。"</string>
+ <string name="httpErrorProxyAuth">"透過 proxy 伺服器驗證失敗。"</string>
+ <string name="httpErrorConnect">"連線到伺服器失敗。"</string>
+ <string name="httpErrorIO">"無法與伺服器溝通,請稍後再試一次 。"</string>
+ <string name="httpErrorTimeout">"連線到伺服器逾時。"</string>
+ <string name="httpErrorRedirectLoop">"此網頁包含太多伺服器轉址。"</string>
+ <string name="httpErrorUnsupportedScheme">"不支援此通訊協定。"</string>
+ <string name="httpErrorFailedSslHandshake">"無法建立安全連線。"</string>
+ <string name="httpErrorBadUrl">"由於網址錯誤,無法開啟此網頁。"</string>
+ <string name="httpErrorFile">"無法存取此檔案。"</string>
+ <string name="httpErrorFileNotFound">"找不到要求的檔案。"</string>
+ <string name="httpErrorTooManyRequests">"太多執行要求。請稍後再試一次。"</string>
+ <string name="contentServiceSync">"同步處理"</string>
+ <string name="contentServiceSyncNotificationTitle">"同步處理"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
+ <string name="low_memory">"手機儲存空間已滿!請刪除一些檔案增加空間。"</string>
+ <string name="me">"我"</string>
+ <string name="power_dialog">"電話選項"</string>
+ <string name="silent_mode">"靜音模式"</string>
+ <string name="turn_on_radio">"開啟無線網路"</string>
+ <string name="turn_off_radio">"關閉無線網路"</string>
+ <string name="screen_lock">"螢幕鎖定"</string>
+ <string name="power_off">"關機"</string>
+ <string name="shutdown_progress">"關機中..."</string>
+ <string name="shutdown_confirm">"手機即將關機。"</string>
+ <string name="no_recent_tasks">"最近沒有存取應用程式。"</string>
+ <string name="global_actions">"電話選項"</string>
+ <string name="global_action_lock">"螢幕鎖定"</string>
+ <string name="global_action_power_off">"關機"</string>
+ <string name="global_action_toggle_silent_mode">"靜音模式"</string>
+ <string name="global_action_silent_mode_on_status">"音效已關閉"</string>
+ <string name="global_action_silent_mode_off_status">"音效已開啟"</string>
+ <string name="global_actions_toggle_airplane_mode">"飛航模式"</string>
+ <string name="global_actions_airplane_mode_on_status">"飛航模式為 [開啟]"</string>
+ <string name="global_actions_airplane_mode_off_status">"飛航模式為 [關閉]"</string>
+ <string name="safeMode">"安全模式"</string>
+ <string name="android_system_label">"Android 系統"</string>
+ <string name="permgrouplab_costMoney">"需要額外費用的服務。"</string>
+ <string name="permgroupdesc_costMoney">"若您允許應用程式執行此操作,可能需要支付一些費用。"</string>
+ <string name="permgrouplab_messages">"您的簡訊"</string>
+ <string name="permgroupdesc_messages">"讀取編輯 SMS、電子郵件與其他簡訊。"</string>
+ <string name="permgrouplab_personalInfo">"您的個人資訊"</string>
+ <string name="permgroupdesc_personalInfo">"直接存取手機上的聯絡人與日曆。"</string>
+ <string name="permgrouplab_location">"您的位置"</string>
+ <string name="permgroupdesc_location">"監視實際位置"</string>
+ <string name="permgrouplab_network">"網路通訊"</string>
+ <string name="permgroupdesc_network">"允許應用程式存取多項網路功能。"</string>
+ <string name="permgrouplab_accounts">"您的 Google 帳戶"</string>
+ <string name="permgroupdesc_accounts">"存取可用 Google 帳戶。"</string>
+ <string name="permgrouplab_hardwareControls">"硬體控制"</string>
+ <string name="permgroupdesc_hardwareControls">"在免持設備上直接存取硬體。"</string>
+ <string name="permgrouplab_phoneCalls">"撥打電話"</string>
+ <string name="permgroupdesc_phoneCalls">"監控、記錄與進行通話。"</string>
+ <string name="permgrouplab_systemTools">"系統工具"</string>
+ <string name="permgroupdesc_systemTools">"系統低階存取與控制。"</string>
+ <string name="permgrouplab_developmentTools">"開發工具"</string>
+ <string name="permgroupdesc_developmentTools">"只有開發者需要此功能。"</string>
+ <string name="permgrouplab_storage">"儲存"</string>
+ <string name="permgroupdesc_storage">"存取 SD 卡。"</string>
+ <string name="permlab_statusBar">"停用或變更狀態列"</string>
+ <string name="permdesc_statusBar">"允許應用程式停用狀態列或新增、移除系統圖示。"</string>
+ <string name="permlab_expandStatusBar">"展開/收攏狀態列"</string>
+ <string name="permdesc_expandStatusBar">"允許應用程式展開或收攏狀態列。"</string>
+ <string name="permlab_processOutgoingCalls">"攔截撥出電話"</string>
+ <string name="permdesc_processOutgoingCalls">"允許應用程式處理撥出電話及變更撥號。請注意:惡意程式可能藉以監控,轉接或阻擋電話撥出。"</string>
+ <string name="permlab_receiveSms">"接收 SMS"</string>
+ <string name="permdesc_receiveSms">"允許應用程式接收、處理 SMS 簡訊。請注意:惡意程式可能使用此功能監控簡訊或在您讀取前擅自刪除。"</string>
+ <string name="permlab_receiveMms">"接收 MMS"</string>
+ <string name="permdesc_receiveMms">"允許應用程式接收、處理 MMS 簡訊。請注意:惡意程式可能使用此功能監控簡訊或在您讀取前擅自刪除。"</string>
+ <string name="permlab_sendSms">"傳送 SMS 簡訊"</string>
+ <string name="permdesc_sendSms">"允許應用程式傳送 SMS 簡訊。請注意:惡意程式可能會擅自傳送簡訊,增加您的支出。"</string>
+ <string name="permlab_readSms">"讀取 SMS 或 MMS"</string>
+ <string name="permdesc_readSms">"允許應用程式讀取手機或 SIM 卡上的 SMS 簡訊。請注意:惡意程式可能會利用此功能讀取您的機密簡訊。"</string>
+ <string name="permlab_writeSms">"編輯 SMS 或 MMS"</string>
+ <string name="permdesc_writeSms">"允許應用程式編輯 SMS 簡訊,存入手機或 SIM 卡。請注意:惡意程式可能會刪除您的簡訊。"</string>
+ <string name="permlab_receiveWapPush">"接收 WAP"</string>
+ <string name="permdesc_receiveWapPush">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可能利用此功能終止其他應用程式。"</string>
+ <string name="permlab_getTasks">"取得執行中應用程式"</string>
+ <string name="permdesc_getTasks">"允許應用程式取得最近執行任務的資訊。請注意:惡意程式可能利用此功能找出其他應用程式的隱私資訊。"</string>
+ <string name="permlab_reorderTasks">"重新安排執行中的應用程式"</string>
+ <string name="permdesc_reorderTasks">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
+ <string name="permlab_setDebugApp">"啟用應用程式偵錯"</string>
+ <string name="permdesc_setDebugApp">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
+ <string name="permlab_changeConfiguration">"變更介面設定"</string>
+ <string name="permdesc_changeConfiguration">"允許應用程式變更目前設定,例如:地區設定或字型大小。"</string>
+ <string name="permlab_restartPackages">"重新啟動其他應用程式"</string>
+ <string name="permdesc_restartPackages">"允許應用程式強制重新啟動其他應用程式。"</string>
+ <string name="permlab_forceBack">"強制關閉應用程式"</string>
+ <string name="permdesc_forceBack">"允許應用程式強制關閉在前端運作的活動並返回。一般應用程式不需要此功能。"</string>
+ <string name="permlab_dump">"接收系統內部狀態"</string>
+ <string name="permdesc_dump">"允許應用程式取得系統內部狀態。請注意:惡意程式可能利用此功能,不當取得私人或安全性資料。"</string>
+ <string name="permlab_shutdown">"部分關機"</string>
+ <string name="permdesc_shutdown">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
+ <string name="permlab_stopAppSwitches">"防止切換應用程式"</string>
+ <string name="permdesc_stopAppSwitches">"防止使用者切換到其他應用程式。"</string>
+ <string name="permlab_runSetActivityWatcher">"監視控制所有應用程式啟動狀態。"</string>
+ <string name="permdesc_runSetActivityWatcher">"允許應用程式監控管理系統啟動活動。請注意:惡意程式可能因此癱瘓整個系統。此權限只在開發時需要,一般手機使用不需要此權限。"</string>
+ <string name="permlab_broadcastPackageRemoved">"傳送程式已移除廣播"</string>
+ <string name="permdesc_broadcastPackageRemoved">"允許應用程式在其他應用程式被移除時發送通知。請注意:惡意程式可能利用此功能,關閉其他執行中的程式。"</string>
+ <string name="permlab_broadcastSmsReceived">"傳送已接收 SMS 廣播"</string>
+ <string name="permdesc_broadcastSmsReceived">"允許應用程式在收到 SMS 簡訊時發出通知。請注意:惡意程式可能利用此功能偽造 SMS 簡訊。"</string>
+ <string name="permlab_broadcastWapPush">"送出「WAP PUSH 已接收」廣播"</string>
+ <string name="permdesc_broadcastWapPush">"允許應用程式在收到 WAP PUSH 簡訊時發送通知。請注意:惡意程式可能利用此功能,偽造 MMS 簡訊回條或秘密更換網頁內容。"</string>
+ <string name="permlab_setProcessLimit">"執行程序限制數"</string>
+ <string name="permdesc_setProcessLimit">"允許應用程式控制可使用的最大執行緒。一般應用程式不需要此功能。"</string>
+ <string name="permlab_setAlwaysFinish">"關閉所有背景程式"</string>
+ <string name="permdesc_setAlwaysFinish">"允許應用程式控制哪些活動在被移到背景執行時,儘速結束。一般應用程式不需要此功能。"</string>
+ <string name="permlab_batteryStats">"編輯電池狀態"</string>
+ <string name="permdesc_batteryStats">"允許修改電池狀態。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_backup">"控制系統備份與還原"</string>
+ <string name="permdesc_backup">"允許應用程式控制系統備份與還原機制,但一般應用程式不會使用此功能。"</string>
+ <string name="permlab_internalSystemWindow">"顯示未授權視窗"</string>
+ <string name="permdesc_internalSystemWindow">"允許內部系統使用介面建立視窗。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_systemAlertWindow">"顯示系統警示"</string>
+ <string name="permdesc_systemAlertWindow">"允許應用程式顯示系統警告視窗。請注意:惡意程式可使用此功能接管手機螢幕。"</string>
+ <string name="permlab_setAnimationScale">"編輯全域動畫速度"</string>
+ <string name="permdesc_setAnimationScale">"允許應用程式變更全域動畫速度 (更快或更慢)。"</string>
+ <string name="permlab_manageAppTokens">"管理應用程式 token"</string>
+ <string name="permdesc_manageAppTokens">"允許應用程式略過一般 Z-ordering,建立與管理自己的 token。一般應用程式不需要此功能。"</string>
+ <string name="permlab_injectEvents">"按鍵及控制按鈕"</string>
+ <string name="permdesc_injectEvents">"允許應用程式發送輸入事件 (按鍵等) 給其他應用程式。請注意:惡意程式可能使用此功能接管手機。"</string>
+ <string name="permlab_readInputState">"記錄您的輸入內容與操作"</string>
+ <string name="permdesc_readInputState">"允許應用程式在使用者操作其他程式時 (例如:輸入密碼),仍可監看輸入的按鍵。一般應用程式應不需要此功能。"</string>
+ <string name="permlab_bindInputMethod">"連結至輸入法"</string>
+ <string name="permdesc_bindInputMethod">"允許擁有人連結至輸入法的最頂層介面。一般應用程式不需使用此選項。"</string>
+ <string name="permlab_setOrientation">"變更螢幕顯示方向"</string>
+ <string name="permdesc_setOrientation">"允許應用程式隨時變更螢幕顯示方向。一般應用程式不需要此功能。"</string>
+ <string name="permlab_signalPersistentProcesses">"傳送 Linux 訊號到應用程式"</string>
+ <string name="permdesc_signalPersistentProcesses">"允許應用程式要求將支援的訊號傳送到所有持續的程序。"</string>
+ <string name="permlab_persistentActivity">"設定應用程式持續執行"</string>
+ <string name="permdesc_persistentActivity">"允許應用程式持續執行,避免系統將它應用到其他程式。"</string>
+ <string name="permlab_deletePackages">"刪除應用程式"</string>
+ <string name="permdesc_deletePackages">"允許應用程式刪除 Android 程式。請注意:惡意程式可能利用此功能刪除重要應用程式。"</string>
+ <string name="permlab_clearAppUserData">"刪除其他應用程式資料"</string>
+ <string name="permdesc_clearAppUserData">"允許應用程式清除使用者資料。"</string>
+ <string name="permlab_deleteCacheFiles">"刪除其他應用程式快取"</string>
+ <string name="permdesc_deleteCacheFiles">"允許應用程式刪除快取檔案。"</string>
+ <string name="permlab_getPackageSize">"估算應用程式占用的儲存空間"</string>
+ <string name="permdesc_getPackageSize">"允許應用程式取得程式碼、資料與快取大小"</string>
+ <string name="permlab_installPackages">"直接安裝應用程式"</string>
+ <string name="permdesc_installPackages">"允許應用程式安裝新的 Android 程式或更新。請注意:惡意程式可能利用此功能新增具有極高權限的程式。"</string>
+ <string name="permlab_clearAppCache">"刪除所有應用程式快取資料。"</string>
+ <string name="permdesc_clearAppCache">"允許應用程式刪除快取目錄裡的檔案,釋放儲存空間。此操作通常受到系統程序嚴格限制。"</string>
+ <string name="permlab_readLogs">"讀取系統記錄檔"</string>
+ <string name="permdesc_readLogs">"允許應用程式讀取系統記錄檔。此項操作可讓應用程式了解目前手機操作狀態,但內容應不含任何個人或隱私資訊。"</string>
+ <string name="permlab_diagnostic">"讀寫 diag 擁有的資源"</string>
+ <string name="permdesc_diagnostic">"允許應用程式讀寫 diag 群組的資源;例如:/dev 裡的檔案。這可能會影響系統穩定性與安全性。此功能僅供製造商或技術人員用於硬體規格偵測。"</string>
+ <string name="permlab_changeComponentState">"啟用或停用應用程式元件"</string>
+ <string name="permdesc_changeComponentState">"允許應用程式變更是否啟用其他元件或應用程式。請注意:惡意程式可能利用此功能,停用重要的手機功能。由於此功能可能導致應用程式元件無法使用、不一致或不穩定,請小心斟酌授權。"</string>
+ <string name="permlab_setPreferredApplications">"設定喜好的應用程式"</string>
+ <string name="permdesc_setPreferredApplications">"允許應用程式修改您偏好的應用程式。請注意:惡意程式可能藉以秘密竄改執行的程式,或偽造已存在的程式以收集私人資料。"</string>
+ <string name="permlab_writeSettings">"編輯全域系統設定"</string>
+ <string name="permdesc_writeSettings">"允許應用程式修改系統設定。請注意:惡意程式可能使用此功能損毀系統設定。"</string>
+ <string name="permlab_writeSecureSettings">"編輯安全系統設定"</string>
+ <string name="permdesc_writeSecureSettings">"允許應用程式修改系統的安全設定資料。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_writeGservices">"修改 Google 服務地圖"</string>
+ <string name="permdesc_writeGservices">"允許應用程式修改 Google 服務地圖。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_receiveBootCompleted">"開機時自動啟用"</string>
+ <string name="permdesc_receiveBootCompleted">"允許應用程式在開機後盡快啟動。此項設定會讓開機時間拉長,並允許應用程式持續執行,因此拖慢手機速度。"</string>
+ <string name="permlab_broadcastSticky">"傳送附屬廣播"</string>
+ <string name="permdesc_broadcastSticky">"允許應用程式傳送持久的廣播。請注意:惡意程式可能利用此功能來佔據過多記憶體,讓手機速度變慢或不穩定。"</string>
+ <string name="permlab_readContacts">"讀取聯絡人資料"</string>
+ <string name="permdesc_readContacts">"允許應用程式讀取手機上所有聯絡人 (地址)。請注意:惡意程式可能利用此功能將您的資料傳送給其他人。"</string>
+ <string name="permlab_writeContacts">"輸入聯絡人資料"</string>
+ <string name="permdesc_writeContacts">"允許應用程式更改聯絡資訊 (地址)。請注意:惡意程式可能利用此功能,清除或修改聯絡資料。"</string>
+ <string name="permlab_writeOwnerData">"寫入持有者的資料"</string>
+ <string name="permdesc_writeOwnerData">"允許應用程式更改手機持有者的資料。請注意:惡意程式可能利用此功能,清除或修改持有者的資料。"</string>
+ <string name="permlab_readOwnerData">"讀取持有者的資料"</string>
+ <string name="permdesc_readOwnerData">"允許應用程式讀取手機持有者資料。請注意:惡意程式可能利用此功能讀取持有者的資料。"</string>
+ <string name="permlab_readCalendar">"讀取日曆資料"</string>
+ <string name="permdesc_readCalendar">"允許應用程式讀取手機上所有日曆資料。請注意:惡意程式可能利用此功能將您的日曆資料傳送給其他人。"</string>
+ <string name="permlab_writeCalendar">"寫入日曆資料"</string>
+ <string name="permdesc_writeCalendar">"允許應用程式編輯日曆資料。請注意:惡意程式可能利用此功能,清除或修改您的日曆資料。"</string>
+ <string name="permlab_accessMockLocation">"模擬位置來源以供測試"</string>
+ <string name="permdesc_accessMockLocation">"建立模擬位置來源以供測試。請注意:惡意程式可能利用此功能覆寫 GPS 或電信業者傳回的位置及/或狀態。"</string>
+ <string name="permlab_accessLocationExtraCommands">"接收額外的位置提供者指令"</string>
+ <string name="permdesc_accessLocationExtraCommands">"存取額外位置提供者命令。請注意:惡意程式可能利用此功能干擾 GPS 或其他位置來源。"</string>
+ <string name="permlab_installLocationProvider">"准許安裝位置提供者"</string>
+ <string name="permdesc_installLocationProvider">"建立虛構的位置來源以供測試。請注意:惡意應用程式可能利用此選項覆寫由真實位置來源 (例如 GPS 或網路供應商) 所傳回的位置及/或狀態,或者監控您的位置並將之提供給外部來源。"</string>
+ <string name="permlab_accessFineLocation">"精確定位 (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"接收精確的位置來源 (例如:手機 GPS)。請注意:惡意程式可能使用此功能得知您的位置,並可能消耗額外電源。"</string>
+ <string name="permlab_accessCoarseLocation">"約略位置 (以網路為基準)"</string>
+ <string name="permdesc_accessCoarseLocation">"接收約略的位置來源 (例如:行動網路資料庫),計算出目前大概位置。請注意:惡意程式可能使用此功能得知您的所在地。"</string>
+ <string name="permlab_accessSurfaceFlinger">"存取 SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"允許應用程式使用 SurfaceFlinger 低階功能。"</string>
+ <string name="permlab_readFrameBuffer">"讀取框架緩衝"</string>
+ <string name="permdesc_readFrameBuffer">"允許應用程式讀取框架緩衝的內容。"</string>
+ <string name="permlab_modifyAudioSettings">"變更音訊設定"</string>
+ <string name="permdesc_modifyAudioSettings">"允許應用程式編輯全域音訊設定,例如音量與路由。"</string>
+ <string name="permlab_recordAudio">"錄製音訊"</string>
+ <string name="permdesc_recordAudio">"允許應用程式存取音訊錄製路徑。"</string>
+ <string name="permlab_camera">"照相"</string>
+ <string name="permdesc_camera">"允許應用程式使用相機拍照。此功能可讓應用程式隨時透過相機拍攝照片。"</string>
+ <string name="permlab_brick">"永久停用電話"</string>
+ <string name="permdesc_brick">"允許應用程式永久停用手機。此項操作非常危險。"</string>
+ <string name="permlab_reboot">"強制重開機"</string>
+ <string name="permdesc_reboot">"允許應用程式強制重開機。"</string>
+ <string name="permlab_mount_unmount_filesystems">"掛載/卸載檔案系統"</string>
+ <string name="permdesc_mount_unmount_filesystems">"允許應用程式掛載/卸載抽取式儲存設備的檔案系統。"</string>
+ <string name="permlab_mount_format_filesystems">"將外接式儲存裝置格式化"</string>
+ <string name="permdesc_mount_format_filesystems">"允許應用程式將可移除式儲存裝置格式化。"</string>
+ <string name="permlab_vibrate">"控制震動"</string>
+ <string name="permdesc_vibrate">"允許應用程式控制震動。"</string>
+ <string name="permlab_flashlight">"控制閃光燈"</string>
+ <string name="permdesc_flashlight">"允許應用程式控制閃光燈。"</string>
+ <string name="permlab_hardware_test">"測試硬體"</string>
+ <string name="permdesc_hardware_test">"允許應用程式控制各種週邊設備,以供測試用。"</string>
+ <string name="permlab_callPhone">"直接撥打電話號碼"</string>
+ <string name="permdesc_callPhone">"允許應用程式自行撥打電話。請注意:惡意程式可能任意撥打電話,造成預期外的支出。但此選項並不允許應用程式撥打緊急電話號碼。"</string>
+ <string name="permlab_callPrivileged">"直接撥打任何電話號碼"</string>
+ <string name="permdesc_callPrivileged">"允許應用程式自行撥打任何電話號碼,包括緊急電話號碼。請注意:惡意程式可能利用此功能濫用緊急服務,撥打不必要或違法的電話。"</string>
+ <string name="permlab_locationUpdates">"控制位置更新通知"</string>
+ <string name="permdesc_locationUpdates">"允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_checkinProperties">"存取登機選項"</string>
+ <string name="permdesc_checkinProperties">"允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_bindGadget">"選擇小工具"</string>
+ <string name="permdesc_bindGadget">"允許應用程式告知系統哪個應用程式可以使用哪些小工具。開啟此權限後,應用程式會讓其他程式使用個人資料,但一般應用程式不適合使用此功能。"</string>
+ <string name="permlab_modifyPhoneState">"修改手機狀態"</string>
+ <string name="permdesc_modifyPhoneState">"允許應用程式控制電話功能。擁有此權限的程式可自行切換網路、開關無線通訊功能。"</string>
+ <string name="permlab_readPhoneState">"讀取手機狀態"</string>
+ <string name="permdesc_readPhoneState">"允許應用程式存取裝置的電話功能。有此權限的應用程式可取得手機的號碼、是否在通話中,以及通話另一方的電話號碼等資料。"</string>
+ <string name="permlab_wakeLock">"防止手機進入待命狀態"</string>
+ <string name="permdesc_wakeLock">"允許應用程式防止手機進入待命。"</string>
+ <string name="permlab_devicePower">"開啟或關閉電源"</string>
+ <string name="permdesc_devicePower">"允許應用程式開啟或關閉電話。"</string>
+ <string name="permlab_factoryTest">"在出廠測試模式下執行"</string>
+ <string name="permdesc_factoryTest">"執行低階製造商測試,允許完全存取手機硬體。此功能只能在手機是製造商測試模式下才可執行。"</string>
+ <string name="permlab_setWallpaper">"設定桌布"</string>
+ <string name="permdesc_setWallpaper">"允許應用程式設定系統桌布。"</string>
+ <string name="permlab_setWallpaperHints">"設定桌布大小提示"</string>
+ <string name="permdesc_setWallpaperHints">"允許應用程式設定系統桌布大小提示。"</string>
+ <string name="permlab_masterClear">"將系統還原至出廠預設值"</string>
+ <string name="permdesc_masterClear">"允許應用程式將手機完全重設至出廠設定,清除所有資料、設定與已安裝程式。"</string>
+ <string name="permlab_setTimeZone">"設定時區"</string>
+ <string name="permdesc_setTimeZone">"允許應用程式變更時區。"</string>
+ <string name="permlab_getAccounts">"發現已知帳戶。"</string>
+ <string name="permdesc_getAccounts">"允許應用程式取得手機上的帳戶清單。"</string>
+ <string name="permlab_accessNetworkState">"檢視網路狀態"</string>
+ <string name="permdesc_accessNetworkState">"允許應用程式檢視網路狀態。"</string>
+ <string name="permlab_createNetworkSockets">"網際網路完整存取"</string>
+ <string name="permdesc_createNetworkSockets">"允許應用程式建立網路設定。"</string>
+ <string name="permlab_writeApnSettings">"輸入存取點名稱設定"</string>
+ <string name="permdesc_writeApnSettings">"允許應用程式修改 APN 設定,例如:Proxy 及 APN 的連接埠。"</string>
+ <string name="permlab_changeNetworkState">"變更網路連線"</string>
+ <string name="permdesc_changeNetworkState">"允許應用程式變更網路連線狀態。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"變更背景資料使用設定"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"允許應用程式變更背景資料使用設定。"</string>
+ <string name="permlab_accessWifiState">"檢視 Wi-Fi 狀態"</string>
+ <string name="permdesc_accessWifiState">"允許應用程式檢視 Wi-Fi 狀態資訊。"</string>
+ <string name="permlab_changeWifiState">"變更 Wi-Fi 狀態"</string>
+ <string name="permdesc_changeWifiState">"允許應用程式與 Wi-Fi 存取點連線或中斷連線,並可變更 Wi-Fi 網路設定。"</string>
+ <string name="permlab_changeWifiMulticastState">"允許接收 Wi-Fi 多點傳播封包"</string>
+ <string name="permdesc_changeWifiMulticastState">"允許應用程式接收並非指定傳送給您裝置的封包,這在您發現附近有服務可使用時很有用,但消耗的電力比非多點傳播模式還要多。"</string>
+ <string name="permlab_bluetoothAdmin">"藍牙管理"</string>
+ <string name="permdesc_bluetoothAdmin">"允許應用程式設定本機藍牙電話,以及偵測與配對其他遠端裝置。"</string>
+ <string name="permlab_bluetooth">"建立藍牙連線"</string>
+ <string name="permdesc_bluetooth">"允許應用程式檢視本機藍牙電話設定,並與其他配對裝置連線。"</string>
+ <string name="permlab_disableKeyguard">"停用按鍵鎖定"</string>
+ <string name="permdesc_disableKeyguard">"允許應用程式停用按鍵鎖定以及其他相關的密碼安全性。例如:收到來電時解除按鍵鎖定,通話結束後重新啟動按鍵鎖定。"</string>
+ <string name="permlab_readSyncSettings">"讀取同步處理設定"</string>
+ <string name="permdesc_readSyncSettings">"允許應用程式讀取同步處理設定,例如:是否同步處理 [聯絡人]。"</string>
+ <string name="permlab_writeSyncSettings">"編輯同步處理設定"</string>
+ <string name="permdesc_writeSyncSettings">"允許應用程式修改同步處理設定,例如:是否要同步處理 [聯絡人]。"</string>
+ <string name="permlab_readSyncStats">"讀取同步處理狀態"</string>
+ <string name="permdesc_readSyncStats">"允許應用程式讀取同步處理狀態;例如:同步處理記錄。"</string>
+ <string name="permlab_subscribedFeedsRead">"讀取訂閱資訊提供"</string>
+ <string name="permdesc_subscribedFeedsRead">"允許應用程式取得目前已同步處理的資訊提供。"</string>
+ <string name="permlab_subscribedFeedsWrite">"寫入訂閱資訊提供"</string>
+ <string name="permdesc_subscribedFeedsWrite">"允許應用程式修改已同步處理的資訊提供。請注意:惡意程式可能使用此功能變更已同步處理的資訊提供。"</string>
+ <string name="permlab_readDictionary">"讀取使用者定義的字典"</string>
+ <string name="permdesc_readDictionary">"允許應用程式讀取使用者儲存在使用者字典內的任何私人字詞、名稱和詞組。"</string>
+ <string name="permlab_writeDictionary">"寫入使用者定義的字典"</string>
+ <string name="permdesc_writeDictionary">"允許應用程式將新字詞寫入使用者的字典。"</string>
+ <string name="permlab_sdcardWrite">"修改/刪除 SD 卡的內容"</string>
+ <string name="permdesc_sdcardWrite">"允許應用程式寫入 SD 卡。"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"住家電話"</item>
- <item msgid="869923650527136615">"行動電話"</item>
- <item msgid="7897544654242874543">"公司電話"</item>
- <item msgid="1103601433382158155">"公司傳真"</item>
- <item msgid="1735177144948329370">"住家傳真"</item>
- <item msgid="603878674477207394">"呼叫器"</item>
- <item msgid="1650824275177931637">"其他"</item>
- <item msgid="9192514806975898961">"自訂"</item>
+ <item>"住家電話"</item>
+ <item>"行動電話"</item>
+ <item>"公司電話"</item>
+ <item>"公司傳真"</item>
+ <item>"住家傳真"</item>
+ <item>"呼叫器"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"主要信箱"</item>
- <item msgid="7084237356602625604">"公司信箱"</item>
- <item msgid="1112044410659011023">"其他信箱"</item>
- <item msgid="2374913952870110618">"自訂"</item>
+ <item>"主要信箱"</item>
+ <item>"公司信箱"</item>
+ <item>"其他信箱"</item>
+ <item>"自訂"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"行動裝置"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"住家"</item>
- <item msgid="5629153956045109251">"公司"</item>
- <item msgid="4966604264500343469">"其他"</item>
- <item msgid="4932682847595299369">"自訂"</item>
+ <item>"住家"</item>
+ <item>"公司"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"住家"</item>
- <item msgid="1359644565647383708">"工作"</item>
- <item msgid="7868549401053615677">"其他"</item>
- <item msgid="3145118944639869809">"自訂"</item>
+ <item>"住家"</item>
+ <item>"工作"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"工作"</item>
- <item msgid="4378074129049520373">"其他"</item>
- <item msgid="3455047468583965104">"自訂"</item>
+ <item>"工作"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"輸入 PIN 碼"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN 碼錯誤!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按 Menu 鍵,然後按 0。"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急電話號碼"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(沒有服務)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"螢幕已鎖定。"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按下 [選單] 解鎖或撥打緊急電話。"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按下 Menu 鍵解鎖。"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"畫出解鎖圖形"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"緊急電話"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"正確!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"很抱歉,請再試一次"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"正在充電 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"充電完成。"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"請連接充電器。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"沒有 SIM 卡。"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"手機未插入 SIM 卡。"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"請插入 SIM 卡。"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"網路已鎖定"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 的 PUK 已鎖定。"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"請參閱《使用者指南》或聯絡客戶服務中心。"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡已鎖定。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"解鎖 SIM 卡中..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n" 請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再嘗試。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。再錯誤 <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會要求使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘記解鎖圖形?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"解鎖圖形出錯次數過多!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"如要解除鎖定,請使用 Google 帳戶登入"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"使用者名稱 (電子郵件)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密碼"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登入"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"使用者名稱或密碼錯誤。"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"充電中"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"請連接充電器"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"電池電量即將不足:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"電池電量不到 <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
- <string name="battery_low_why" msgid="7655196144309694753">"原因"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"出廠測試失敗"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"只有安裝在 /system/app 裡的程式才能支援 FACTORY_TEST 操作。"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"找不到提供 FACTORY_TEST 的程式。"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"重新開機"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"「<xliff:g id="TITLE">%s</xliff:g>」的網頁指出:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"離開此頁?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" 選取 [確定] 離開此頁;或 [取消] 留在此頁。"</string>
- <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"讀取瀏覽器的記錄與書籤"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"允許應用程式讀取瀏覽器曾經造訪過的所有網址,以及瀏覽器的所有書籤。"</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"寫入瀏覽器的記錄與書籤"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"允許應用程式修改儲存在電話上的瀏覽記錄或書籤。請注意:惡意應用程式可能會使用此選項來清除或修改您瀏覽器的資料。"</string>
- <string name="save_password_message" msgid="767344687139195790">"是否記憶此密碼?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"記住"</string>
- <string name="save_password_never" msgid="8274330296785855105">"從不"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"您沒有開啟此頁的權限。"</string>
- <string name="text_copied" msgid="4985729524670131385">"文字已複製到剪貼簿。"</string>
- <string name="more_item_label" msgid="4650918923083320495">"更多"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"[選單] +"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"空白鍵"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"輸入"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"刪除"</string>
- <string name="search_go" msgid="8298016669822141719">"搜尋"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以前"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
+ <string name="keyguard_password_enter_pin_code">"輸入 PIN 碼"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 碼錯誤!"</string>
+ <string name="keyguard_label_text">"如要解鎖,請按 Menu 鍵,然後按 0。"</string>
+ <string name="emergency_call_dialog_number_for_display">"緊急電話號碼"</string>
+ <string name="lockscreen_carrier_default">"(沒有服務)"</string>
+ <string name="lockscreen_screen_locked">"螢幕已鎖定。"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"按下 [選單] 解鎖或撥打緊急電話。"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"按下 Menu 鍵解鎖。"</string>
+ <string name="lockscreen_pattern_instructions">"畫出解鎖圖形"</string>
+ <string name="lockscreen_emergency_call">"緊急電話"</string>
+ <string name="lockscreen_pattern_correct">"正確!"</string>
+ <string name="lockscreen_pattern_wrong">"很抱歉,請再試一次"</string>
+ <string name="lockscreen_plugged_in">"正在充電 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"請連接充電器。"</string>
+ <string name="lockscreen_missing_sim_message_short">"沒有 SIM 卡。"</string>
+ <string name="lockscreen_missing_sim_message">"手機未插入 SIM 卡。"</string>
+ <string name="lockscreen_missing_sim_instructions">"請插入 SIM 卡。"</string>
+ <string name="lockscreen_network_locked_message">"網路已鎖定"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM 的 PUK 已鎖定。"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"請參閱《使用者指南》或聯絡客戶服務中心。"</string>
+ <string name="lockscreen_sim_locked_message">"SIM 卡已鎖定。"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"解鎖 SIM 卡中..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n" 請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再嘗試。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。再錯誤 <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會要求使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"忘記解鎖圖形?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"解鎖圖形出錯次數過多!"</string>
+ <string name="lockscreen_glogin_instructions">"如要解除鎖定,請使用 Google 帳戶登入"</string>
+ <string name="lockscreen_glogin_username_hint">"使用者名稱 (電子郵件)"</string>
+ <string name="lockscreen_glogin_password_hint">"密碼"</string>
+ <string name="lockscreen_glogin_submit_button">"登入"</string>
+ <string name="lockscreen_glogin_invalid_input">"使用者名稱或密碼錯誤。"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"沒有通知"</string>
+ <string name="status_bar_ongoing_events_title">"進行中"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"充電中"</string>
+ <string name="battery_low_title">"請連接充電器"</string>
+ <string name="battery_low_subtitle">"電池電量即將不足:"</string>
+ <string name="battery_low_percent_format">"電池電量不到 <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
+ <string name="battery_low_why">"原因"</string>
+ <string name="factorytest_failed">"出廠測試失敗"</string>
+ <string name="factorytest_not_system">"只有安裝在 /system/app 裡的程式才能支援 FACTORY_TEST 操作。"</string>
+ <string name="factorytest_no_action">"找不到提供 FACTORY_TEST 的程式。"</string>
+ <string name="factorytest_reboot">"重新開機"</string>
+ <string name="js_dialog_title">"「<xliff:g id="TITLE">%s</xliff:g>」的網頁指出:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"離開此頁?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" 選取 [確定] 離開此頁;或 [取消] 留在此頁。"</string>
+ <string name="save_password_label">"確認"</string>
+ <string name="permlab_readHistoryBookmarks">"讀取瀏覽器的記錄與書籤"</string>
+ <string name="permdesc_readHistoryBookmarks">"允許應用程式讀取瀏覽器曾經造訪過的所有網址,以及瀏覽器的所有書籤。"</string>
+ <string name="permlab_writeHistoryBookmarks">"寫入瀏覽器的記錄與書籤"</string>
+ <string name="permdesc_writeHistoryBookmarks">"允許應用程式修改儲存在電話上的瀏覽記錄或書籤。請注意:惡意應用程式可能會使用此選項來清除或修改您瀏覽器的資料。"</string>
+ <string name="save_password_message">"是否記憶此密碼?"</string>
+ <string name="save_password_notnow">"現在不要"</string>
+ <string name="save_password_remember">"記住"</string>
+ <string name="save_password_never">"從不"</string>
+ <string name="open_permission_deny">"您沒有開啟此頁的權限。"</string>
+ <string name="text_copied">"文字已複製到剪貼簿。"</string>
+ <string name="more_item_label">"更多"</string>
+ <string name="prepend_shortcut_label">"[選單] +"</string>
+ <string name="menu_space_shortcut_label">"空白鍵"</string>
+ <string name="menu_enter_shortcut_label">"輸入"</string>
+ <string name="menu_delete_shortcut_label">"刪除"</string>
+ <string name="search_go">"搜尋"</string>
+ <string name="oneMonthDurationPast">"1 個月以前"</string>
+ <string name="beforeOneMonthDurationPast">"1 個月前"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒以前"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
+ <item quantity="one">"1 秒以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
+ <item quantity="one">"1 分鐘以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 小時以前"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
+ <item quantity="one">"1 小時以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
- <item quantity="other" msgid="1241926116443974687">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
+ <item quantity="one">"1 秒內"</item>
+ <item quantity="other">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分鐘內"</item>
- <item quantity="other" msgid="3330713936399448749">"在 <xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
+ <item quantity="one">"1 分鐘內"</item>
+ <item quantity="other">"在 <xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 小時內"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
+ <item quantity="one">"1 小時內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒以前"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
+ <item quantity="one">"1 秒以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分鐘以前"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
+ <item quantity="one">"1 分鐘以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 小時以前"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
+ <item quantity="one">"1 小時以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
+ <item quantity="one">"1 秒內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分鐘內"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
+ <item quantity="one">"1 分鐘內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 小時內"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
+ <item quantity="one">"1 小時內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"天"</string>
- <string name="days" msgid="4774547661021344602">"天"</string>
- <string name="hour" msgid="2126771916426189481">"小時"</string>
- <string name="hours" msgid="894424005266852993">"小時"</string>
- <string name="minute" msgid="9148878657703769868">"分鐘"</string>
- <string name="minutes" msgid="5646001005827034509">"分鐘"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"週"</string>
- <string name="weeks" msgid="6509623834583944518">"週"</string>
- <string name="year" msgid="4001118221013892076">"年"</string>
- <string name="years" msgid="6881577717993213522">"年"</string>
- <string name="every_weekday" msgid="8777593878457748503">"每天 (週一至週五)"</string>
- <string name="daily" msgid="5738949095624133403">"每天"</string>
- <string name="weekly" msgid="983428358394268344">"每週<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"每月"</string>
- <string name="yearly" msgid="1519577999407493836">"每年"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"無法播放影片"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"很抱歉,影片格式無效,裝置無法進行串流處理。"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"很抱歉,此影片無法播放。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"確定"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"中午"</string>
- <string name="Noon" msgid="3342127745230013127">"中午"</string>
- <string name="midnight" msgid="7166259508850457595">"午夜"</string>
- <string name="Midnight" msgid="5630806906897892201">"午夜"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"全部選取"</string>
- <string name="selectText" msgid="3889149123626888637">"選取文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"停止選取文字"</string>
- <string name="cut" msgid="3092569408438626261">"剪下"</string>
- <string name="cutAll" msgid="2436383270024931639">"全部剪下"</string>
- <string name="copy" msgid="2681946229533511987">"複製"</string>
- <string name="copyAll" msgid="2590829068100113057">"全部複製"</string>
- <string name="paste" msgid="5629880836805036433">"貼上"</string>
- <string name="copyUrl" msgid="2538211579596067402">"複製網址"</string>
- <string name="inputMethod" msgid="7673923508389094672">"輸入法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"將「%s」新增到字典"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"編輯文字"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"儲存空間即將不足"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"手機儲存空間即將不足。"</string>
- <string name="ok" msgid="5970060430562524910">"確定"</string>
- <string name="cancel" msgid="6442560571259935130">"取消"</string>
- <string name="yes" msgid="5362982303337969312">"確定"</string>
- <string name="no" msgid="5141531044935541497">"取消"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"請注意"</string>
- <string name="capital_on" msgid="1544682755514494298">"開啟"</string>
- <string name="capital_off" msgid="6815870386972805832">"關閉"</string>
- <string name="whichApplication" msgid="4533185947064773386">"完成操作需使用"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"以此為本操作預設值。"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除首頁設定 (應用程式) 管理應用程式的預設值。"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"選取一項操作"</string>
- <string name="noApplications" msgid="1691104391758345586">"沒有應用程式可執行此項操作。"</string>
- <string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式 (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請再試一次。"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 異常終止。請再試一次。"</string>
- <string name="anr_title" msgid="3100070910664756057">"很抱歉!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (應用程式:<xliff:g id="APPLICATION">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 程序無回應。"</string>
- <string name="force_close" msgid="3653416315450806396">"強制關閉"</string>
- <string name="report" msgid="4060218260984795706">"回報"</string>
- <string name="wait" msgid="7147118217226317732">"等待"</string>
- <string name="debug" msgid="9103374629678531849">"偵錯"</string>
- <string name="sendText" msgid="5132506121645618310">"訊息傳送方式"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string>
- <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"透過藍牙播放"</string>
- <string name="volume_call" msgid="3941680041282788711">"來電音量"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"藍牙通話音量"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"鬧鐘音量"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音量"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音量"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"預設鈴聲"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"預設鈴聲 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"靜音"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"未知的鈴聲"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"天"</string>
+ <string name="days">"天"</string>
+ <string name="hour">"小時"</string>
+ <string name="hours">"小時"</string>
+ <string name="minute">"分鐘"</string>
+ <string name="minutes">"分鐘"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"週"</string>
+ <string name="weeks">"週"</string>
+ <string name="year">"年"</string>
+ <string name="years">"年"</string>
+ <string name="every_weekday">"每天 (週一至週五)"</string>
+ <string name="daily">"每天"</string>
+ <string name="weekly">"每週<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"每月"</string>
+ <string name="yearly">"每年"</string>
+ <string name="VideoView_error_title">"無法播放影片"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"很抱歉,影片格式無效,裝置無法進行串流處理。"</string>
+ <string name="VideoView_error_text_unknown">"很抱歉,此影片無法播放。"</string>
+ <string name="VideoView_error_button">"確定"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"中午"</string>
+ <string name="Noon">"中午"</string>
+ <string name="midnight">"午夜"</string>
+ <string name="Midnight">"午夜"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"全部選取"</string>
+ <string name="selectText">"選取文字"</string>
+ <string name="stopSelectingText">"停止選取文字"</string>
+ <string name="cut">"剪下"</string>
+ <string name="cutAll">"全部剪下"</string>
+ <string name="copy">"複製"</string>
+ <string name="copyAll">"全部複製"</string>
+ <string name="paste">"貼上"</string>
+ <string name="copyUrl">"複製網址"</string>
+ <string name="inputMethod">"輸入法"</string>
+ <string name="addToDictionary">"將「%s」新增到字典"</string>
+ <string name="editTextMenuTitle">"編輯文字"</string>
+ <string name="low_internal_storage_view_title">"儲存空間即將不足"</string>
+ <string name="low_internal_storage_view_text">"手機儲存空間即將不足。"</string>
+ <string name="ok">"確定"</string>
+ <string name="cancel">"取消"</string>
+ <string name="yes">"確定"</string>
+ <string name="no">"取消"</string>
+ <string name="dialog_alert_title">"請注意"</string>
+ <string name="capital_on">"開啟"</string>
+ <string name="capital_off">"關閉"</string>
+ <string name="whichApplication">"完成操作需使用"</string>
+ <string name="alwaysUse">"以此為本操作預設值。"</string>
+ <string name="clearDefaultHintMsg">"清除首頁設定 (應用程式) 管理應用程式的預設值。"</string>
+ <string name="chooseActivity">"選取一項操作"</string>
+ <string name="noApplications">"沒有應用程式可執行此項操作。"</string>
+ <string name="aerr_title">"很抱歉!"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式 (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請再試一次。"</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 異常終止。請再試一次。"</string>
+ <string name="anr_title">"很抱歉!"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (應用程式:<xliff:g id="APPLICATION">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_application_process">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 程序無回應。"</string>
+ <string name="force_close">"強制關閉"</string>
+ <string name="report">"回報"</string>
+ <string name="wait">"等待"</string>
+ <string name="debug">"偵錯"</string>
+ <string name="sendText">"訊息傳送方式"</string>
+ <string name="volume_ringtone">"鈴聲音量"</string>
+ <string name="volume_music">"媒體音量"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"透過藍牙播放"</string>
+ <string name="volume_call">"來電音量"</string>
+ <string name="volume_bluetooth_call">"藍牙通話音量"</string>
+ <string name="volume_alarm">"鬧鐘音量"</string>
+ <string name="volume_notification">"通知音量"</string>
+ <string name="volume_unknown">"音量"</string>
+ <string name="ringtone_default">"預設鈴聲"</string>
+ <string name="ringtone_default_with_actual">"預設鈴聲 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"靜音"</string>
+ <string name="ringtone_picker_title">"鈴聲"</string>
+ <string name="ringtone_unknown">"未知的鈴聲"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"已偵測到 Wi-Fi 網路"</item>
- <item quantity="other" msgid="4192424489168397386">"已偵測到 Wi-Fi 網路"</item>
+ <item quantity="one">"已偵測到 Wi-Fi 網路"</item>
+ <item quantity="other">"已偵測到 Wi-Fi 網路"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"開啟可用 Wi-Fi 網路"</item>
- <item quantity="other" msgid="7915895323644292768">"開啟可用 Wi-Fi 網路"</item>
+ <item quantity="one">"開啟可用 Wi-Fi 網路"</item>
+ <item quantity="other">"開啟可用 Wi-Fi 網路"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"插入字元"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"未知的應用程式"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"即將傳送大量 SMS 簡訊。選取 [確定] 繼續或 [取消] 停止傳送。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"確定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
- <string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"預設值"</string>
- <string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>" 隱藏"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"顯示全部"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"載入中..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB 已連接"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"已透過 USB 連接手機與電腦。如要從電腦或 SD 卡複製檔案,請選取 [掛載]。"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"掛載"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"不要掛載"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"把 SD 卡當成 USB 儲存裝置時發生問題。"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 已連接"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"選取此項將檔案複製到電腦,或從電腦複製。"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"關閉 USB 儲存裝置"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"選取此處關閉 USB 儲存裝置。"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"關閉 USB 儲存裝置"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"關閉 USB 儲存裝置之前,請確定先從 USB Host 卸載。選取 [關閉] 即可關閉 USB 儲存裝置。"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"關閉"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"取消"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"關閉 USB 儲存裝置時發生問題。請檢查確認您是否已卸載 USB Host,然後再試一次。"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"將 SD 卡格式化"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"確定要將 SD 卡格式化嗎?該 SD 卡中的所有資料將會遺失。"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"格式化"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 偵錯模式已啟用"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"您的手機已連接至電腦。"</string>
- <string name="select_input_method" msgid="2086499663193509436">"選取輸入法"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"正在準備 SD 卡"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"正在檢查錯誤。"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"SD 卡為空白"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD 卡內無檔案系統,或檔案系統不受支援。"</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"SD 卡已損壞"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SD 卡已毀損,您可能必須予以重新格式化。"</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD 卡未正常移除"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"請先卸載 SD 卡,再將其移除,以免資料遺失。"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"可安全移除 SD 卡"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"您現在可以安全地移除 SD 卡。"</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"已移除 SD 卡"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD 卡已移除,請插入新的 SD 卡。"</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"找不到符合的活動"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"更新元件使用統計資料"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"允許修改收集到的元件使用統計資料。一般應用程式不會使用此功能。"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"點兩下以進行縮放控制"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"擴大小工具時發生錯誤"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"開始"</string>
- <string name="ime_action_search" msgid="658110271822807811">"搜尋"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"傳送"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"下一步"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完成"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"執行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"使用 <xliff:g id="NUMBER">%s</xliff:g>"\n"撥號"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>"\n"的聯絡人"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"已勾選"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"未勾選"</string>
+ <string name="select_character">"插入字元"</string>
+ <string name="sms_control_default_app_name">"未知的應用程式"</string>
+ <string name="sms_control_title">"傳送 SMS 簡訊"</string>
+ <string name="sms_control_message">"即將傳送大量 SMS 簡訊。選取 [確定] 繼續或 [取消] 停止傳送。"</string>
+ <string name="sms_control_yes">"確定"</string>
+ <string name="sms_control_no">"取消"</string>
+ <string name="date_time_set">"設定"</string>
+ <string name="default_permission_group">"預設值"</string>
+ <string name="no_permissions">"無須許可"</string>
+ <string name="perms_hide"><b>" 隱藏"</b></string>
+ <string name="perms_show_all"><b>"顯示全部"</b></string>
+ <string name="googlewebcontenthelper_loading">"載入中..."</string>
+ <string name="usb_storage_title">"USB 已連接"</string>
+ <string name="usb_storage_message">"已透過 USB 連接手機與電腦。如要從電腦或 SD 卡複製檔案,請選取 [掛載]。"</string>
+ <string name="usb_storage_button_mount">"掛載"</string>
+ <string name="usb_storage_button_unmount">"不要掛載"</string>
+ <string name="usb_storage_error_message">"把 SD 卡當成 USB 儲存裝置時發生問題。"</string>
+ <string name="usb_storage_notification_title">"USB 已連接"</string>
+ <string name="usb_storage_notification_message">"選取此項將檔案複製到電腦,或從電腦複製。"</string>
+ <string name="usb_storage_stop_notification_title">"關閉 USB 儲存裝置"</string>
+ <string name="usb_storage_stop_notification_message">"選取此處關閉 USB 儲存裝置。"</string>
+ <string name="usb_storage_stop_title">"關閉 USB 儲存裝置"</string>
+ <string name="usb_storage_stop_message">"關閉 USB 儲存裝置之前,請確定先從 USB Host 卸載。選取 [關閉] 即可關閉 USB 儲存裝置。"</string>
+ <string name="usb_storage_stop_button_mount">"關閉"</string>
+ <string name="usb_storage_stop_button_unmount">"取消"</string>
+ <string name="usb_storage_stop_error_message">"關閉 USB 儲存裝置時發生問題。請檢查確認您是否已卸載 USB Host,然後再試一次。"</string>
+ <string name="extmedia_format_title">"將 SD 卡格式化"</string>
+ <string name="extmedia_format_message">"確定要將 SD 卡格式化嗎?該 SD 卡中的所有資料將會遺失。"</string>
+ <string name="extmedia_format_button_format">"格式化"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"選取輸入法"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"待選項目"</u></string>
+ <string name="ext_media_checking_notification_title">"正在準備 SD 卡"</string>
+ <string name="ext_media_checking_notification_message">"正在檢查錯誤。"</string>
+ <string name="ext_media_nofs_notification_title">"SD 卡為空白"</string>
+ <string name="ext_media_nofs_notification_message">"SD 卡內無檔案系統,或檔案系統不受支援。"</string>
+ <string name="ext_media_unmountable_notification_title">"SD 卡已損壞"</string>
+ <string name="ext_media_unmountable_notification_message">"SD 卡已毀損,您可能必須予以重新格式化。"</string>
+ <string name="ext_media_badremoval_notification_title">"SD 卡未正常移除"</string>
+ <string name="ext_media_badremoval_notification_message">"請先卸載 SD 卡,再將其移除,以免資料遺失。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"可安全移除 SD 卡"</string>
+ <string name="ext_media_safe_unmount_notification_message">"您現在可以安全地移除 SD 卡。"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD 卡"</string>
+ <string name="ext_media_nomedia_notification_message">"SD 卡已移除,請插入新的 SD 卡。"</string>
+ <string name="activity_list_empty">"找不到符合的活動"</string>
+ <string name="permlab_pkgUsageStats">"更新元件使用統計資料"</string>
+ <string name="permdesc_pkgUsageStats">"允許修改收集到的元件使用統計資料。一般應用程式不會使用此功能。"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"點兩下以進行縮放控制"</string>
+ <string name="gadget_host_error_inflating">"擴大小工具時發生錯誤"</string>
+ <string name="ime_action_go">"開始"</string>
+ <string name="ime_action_search">"搜尋"</string>
+ <string name="ime_action_send">"傳送"</string>
+ <string name="ime_action_next">"下一步"</string>
+ <string name="ime_action_done">"完成"</string>
+ <string name="ime_action_default">"執行"</string>
+ <string name="dial_number_using">"使用 <xliff:g id="NUMBER">%s</xliff:g>"\n"撥號"</string>
+ <string name="create_contact_using">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>"\n"的聯絡人"</string>
+ <string name="accessibility_compound_button_selected">"已勾選"</string>
+ <string name="accessibility_compound_button_unselected">"未勾選"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fd78f83..01253d3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -215,6 +215,9 @@
<attr name="windowIsFloating" format="boolean" />
<!-- Flag indicating whether this is a translucent window. -->
<attr name="windowIsTranslucent" format="boolean" />
+ <!-- Flag indicating that this window's background should be the
+ user's current wallpaper. -->
+ <attr name="windowShowWallpaper" format="boolean" />
<!-- This Drawable is overlaid over the foreground of the Window's content area, usually
to place a shadow below the title. -->
<attr name="windowContentOverlay" format="reference" />
@@ -598,7 +601,7 @@
<flag name="time" value="0x00000024" />
</attr>
- <!-- Additional features you can enable in an IME associated with an editor,
+ <!-- Additional features you can enable in an IME associated with an editor
to improve the integration with your application. The constants
here correspond to those defined by
{@link android.view.inputmethod.EditorInfo#imeOptions}. -->
@@ -682,7 +685,7 @@
<attr name="y" format="dimension" />
<!-- Specifies how to place the content of an object, both
- on the x and y axis, within the object itself. -->
+ on the x- and y-axis, within the object itself. -->
<attr name="gravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
@@ -738,7 +741,7 @@
<attr name="entries" format="reference" />
<!-- Standard gravity constant that a child can supply to its parent.
- Defines how to place the view, both its x and y axis, within its parent view group. -->
+ Defines how to place the view, both its x- and y-axis, within its parent view group. -->
<attr name="layout_gravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
@@ -900,6 +903,7 @@
<attr name="windowFullscreen" />
<attr name="windowIsFloating" />
<attr name="windowIsTranslucent" />
+ <attr name="windowShowWallpaper" />
<attr name="windowAnimationStyle" />
<attr name="windowSoftInputMode" />
<attr name="windowDisablePreview" />
@@ -1817,7 +1821,7 @@
<attr name="minEms" format="integer" min="0" />
<!-- Makes the TextView be at least this many pixels wide -->
<attr name="minWidth" />
- <!-- Specifies how to align the text by the view's x and/or y axis
+ <!-- Specifies how to align the text by the view's x- and/or y-axis
when the text is smaller than the view. -->
<attr name="gravity" />
<!-- Whether the text is allowed to be wider than the view (and
@@ -3328,6 +3332,47 @@
<attr name="configure" format="string" />
</declare-styleable>
+ <!-- =============================== -->
+ <!-- Accounts package class attributes -->
+ <!-- =============================== -->
+
+ <!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
+ describes an account authenticator.
+ -->
+ <declare-styleable name="AccountAuthenticator">
+ <!-- the account type this authenticator handles. -->
+ <attr name="accountType" format="string"/>
+ <!-- the user-visible name of the authenticator. -->
+ <attr name="label"/>
+ <!-- the icon of the authenticator. -->
+ <attr name="icon"/>
+ </declare-styleable>
+
+ <!-- =============================== -->
+ <!-- Accounts package class attributes -->
+ <!-- =============================== -->
+
+ <!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
+ describes an account authenticator.
+ -->
+ <declare-styleable name="SyncAdapter">
+ <!-- the authority of a content provider. -->
+ <attr name="contentAuthority" format="string"/>
+ <attr name="accountType"/>
+ </declare-styleable>
+
+ <!-- =============================== -->
+ <!-- Contacts meta-data attributes -->
+ <!-- =============================== -->
+
+ <declare-styleable name="Icon">
+ <attr name="icon" />
+ <attr name="mimeType" />
+ </declare-styleable>
+
+ <declare-styleable name="IconDefault">
+ <attr name="icon" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7215685..92c776c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -36,6 +36,25 @@
<integer name="config_longAnimTime">300</integer>
<!-- Flag indicating whether Last Name comes before First Name.
- This becomes true in Japan, for example.-->
+ 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">
+ <item>"default,wifi,0"</item>
+ <item>"default,mobile,0"</item>
+ <item>"mms,mobile,1"</item>
+ <item>"supl,mobile,1"</item>
+ <item>"dun,mobile,1"</item>
+ <item>"hipri,mobile,2"</item>
+ </string-array>
+
+ <!-- This string array should be overridden by the device to present a list of radio attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardware -->
+ <!-- An Array of "[radio-name],[priority] -->
+ <!-- [# simultaneous connection types]" -->
+ <string-array translatable="false" name="radioAttributes">
+ <item>"wifi,1,1"</item>
+ <item>"mobile,0,1"</item>
+ </string-array>
</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 c92cf51..d51b439 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -5,16 +5,16 @@
***************************************************************
IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
READ THIS BEFORE YOU MAKE ANY CHANGES
-
+
This file defines the binary compatibility for resources. As such,
you must be very careful when making changes here, or you will
completely break backwards compatibility with old applications.
-
+
To avoid breaking compatibility, all new resources must be placed
at the end of the list of resources of the same type. Placing a resource
in the middle of type will cause all following resources to be
assigned new resource numbers, breaking compatibility.
-
+
***************************************************************
*************************************************************** -->
<resources>
@@ -22,7 +22,7 @@
<!-- We don't want to publish private symbols in android.R as part of the
SDK. Instead, put them here. -->
<private-symbols package="com.android.internal" />
-
+
<!-- AndroidManifest.xml attributes. -->
<eat-comment />
@@ -569,10 +569,10 @@
<public type="attr" name="lineSpacingExtra" id="0x01010217" />
<public type="attr" name="lineSpacingMultiplier" id="0x01010218" />
<public type="attr" name="listChoiceIndicatorSingle" id="0x01010219" />
- <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
+ <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
<public type="attr" name="versionCode" id="0x0101021b" />
<public type="attr" name="versionName" id="0x0101021c" />
-
+
<public type="id" name="background" id="0x01020000" />
<public type="id" name="checkbox" id="0x01020001" />
<public type="id" name="content" id="0x01020002" />
@@ -601,7 +601,7 @@
<public type="id" name="button1" id="0x01020019" />
<public type="id" name="button2" id="0x0102001a" />
<public type="id" name="button3" id="0x0102001b" />
-
+
<public type="style" name="Animation" id="0x01030000" />
<public type="style" name="Animation.Activity" id="0x01030001" />
<public type="style" name="Animation.Dialog" id="0x01030002" />
@@ -748,7 +748,7 @@
<public type="drawable" name="btn_plus" id="0x01080008" />
<public type="drawable" name="btn_radio" id="0x01080009" />
<public type="drawable" name="btn_star" id="0x0108000a" />
- <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
+ <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
<public type="drawable" name="btn_star_big_on" id="0x0108000c" />
<public type="drawable" name="button_onoff_indicator_on" id="0x0108000d" />
<public type="drawable" name="button_onoff_indicator_off" id="0x0108000e" />
@@ -916,7 +916,7 @@
<public type="layout" name="select_dialog_item" id="0x01090011" />
<public type="layout" name="select_dialog_singlechoice" id="0x01090012" />
<public type="layout" name="select_dialog_multichoice" id="0x01090013" />
-
+
<public type="anim" name="fade_in" id="0x010a0000" />
<public type="anim" name="fade_out" id="0x010a0001" />
<public type="anim" name="slide_in_left" id="0x010a0002" />
@@ -929,9 +929,9 @@
Resources added in version 2 of the platform.
=============================================================== -->
<eat-comment />
-
+
<public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
-
+
<!-- ===============================================================
Resources added in version 3 of the platform.
=============================================================== -->
@@ -1062,7 +1062,7 @@
<public type="id" name="stopSelectingText" id="0x01020029" />
<!-- Menu ID to perform a "add to dictionary" operation. -->
<public type="id" name="addToDictionary" id="0x0102002a" />
-
+
<public type="style" name="Theme.InputMethod" id="0x01030054" />
<public type="style" name="Theme.NoDisplay" id="0x01030055" />
<public type="style" name="Animation.InputMethod" id="0x01030056" />
@@ -1070,7 +1070,7 @@
<public type="style" name="ButtonBar" id="0x01030058" />
<public type="style" name="Theme.Panel" id="0x01030059" />
<public type="style" name="Theme.Light.Panel" id="0x0103005a" />
-
+
<public type="string" name="dialog_alert_title" id="0x01040014" />
<public type="string" name="VideoView_error_text_invalid_progressive_playback" id="0x01040015" />
@@ -1081,7 +1081,7 @@
<!-- Drawable to use as a background for a taller version of the titlebar -->
<public type="drawable" name="title_bar_tall" id="0x010800a6" />
-
+
<public type="integer" name="config_shortAnimTime" id="0x010e0000" />
<public type="integer" name="config_mediumAnimTime" id="0x010e0001" />
<public type="integer" name="config_longAnimTime" id="0x010e0002" />
@@ -1140,4 +1140,18 @@
<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.
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="accountType" />
+ <public type="attr" name="contentAuthority" />
+ <public type="attr" name="windowShowWallpaper" />
+
+ <public type="style" name="Theme.Wallpaper" />
+ <public type="style" name="Theme.Wallpaper.NoTitleBar" />
+ <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aaaebbb..22f9136 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -134,7 +134,7 @@
<string name="RestrictedOnNormal">Voice/SMS service is blocked.</string>
<!-- Displayed to tell the user that all voice service is blocked by access control. -->
<string name="RestrictedOnAll">All voice/SMS services are blocked.</string>
-
+
<!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
<!-- Example: Service was enabled for: Voice, Data -->
<string name="serviceClassVoice">Voice</string>
@@ -229,6 +229,13 @@
<!-- Displayed when a request failed because there are too many requests right now. -->
<string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
+ <!-- Account notifications --> <skip />
+ <!-- A notification is shown when the AccountManager is unable to
+ supply an auth token without prompting the user to re-enter the
+ password. This is the text that will scroll through the
+ notification bar (will be seen by the user as he uses another application). -->
+ <string name="notification_title">Sign-in error</string>
+
<!-- Sync notifications --> <skip />
<!-- A notification is shown when there is a sync error. This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
<string name="contentServiceSync">Sync</string>
@@ -299,7 +306,7 @@
<!-- Label for the Android system components when they are shown to the user. -->
<string name="android_system_label">Android System</string>
-
+
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -545,6 +552,11 @@
<string name="permdesc_backup">Allows the application to control the system's backup and restore mechanism. Not for use by normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_backup_data">back up and restore the application's data</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_backup_data">Allows the application to participate in the system's backup and restore mechanism.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_internalSystemWindow">display unauthorized windows</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_internalSystemWindow">Allows the creation of
@@ -592,6 +604,12 @@
interface of an input method. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindWallpaper">bind to a wallpaper</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
+ interface of a wallpaper. Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setOrientation">change screen orientation</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_setOrientation">Allows an application to change
@@ -800,7 +818,7 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readFrameBuffer">read frame buffer</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_readFrameBuffer">Allows application to use
+ <string name="permdesc_readFrameBuffer">Allows application to
read the content of the frame buffer.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -961,12 +979,40 @@
the phone\'s time zone.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_accountManagerService">act as the AccountManagerService</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_accountManagerService">Allows an
+ application to make calls to AccountAuthenticators</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_getAccounts">discover known accounts</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_getAccounts">Allows an application to get
the list of accounts known by the phone.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_authenticateAccounts">act as an account authenticator</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_authenticateAccounts">Allows an application
+ to use the account authenticator capabilities of the
+ AccountManager, including creating accounts and getting and
+ setting their passwords.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageAccounts">manage the accounts list</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_manageAccounts">Allows an application to
+ perform operations like adding, and removing accounts and deleting
+ their password.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_useCredentials">use the authentication
+ credentials of an account</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_useCredentials">Allows an application to
+ request authentication tokens.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessNetworkState">view network state</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_accessNetworkState">Allows an application to view
@@ -1109,9 +1155,6 @@
<item>Custom</item>
</string-array>
- <!-- String which means the type "mobile phone". -->
- <string name="mobileEmailTypeName">Mobile</string>
-
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Postal address types from android.provider.Contacts. This could be used when adding a new address for a contact, for example. -->
<string-array name="postalAddressTypes">
@@ -1322,7 +1365,7 @@
<!-- Do not translate. WebView User Agent string -->
<string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android %s)
- AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1</xliff:g></string>
+ AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17</xliff:g></string>
<!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
<string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
@@ -1378,8 +1421,8 @@
<string name="menu_delete_shortcut_label">delete</string>
<!-- Strings used for search bar --><skip />
-
- <!-- This is the default button label in the system-wide search UI.
+
+ <!-- This is the default button label in the system-wide search UI.
It is also used by the home screen's search "widget". It should be short -->
<string name="search_go">Search</string>
@@ -1435,7 +1478,7 @@
<item quantity="one">tomorrow</item>
<item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
</plurals>
-
+
<!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
<plurals name="abbrev_num_seconds_ago">
<item quantity="one">1 sec ago</item>
@@ -1677,6 +1720,8 @@
<string name="volume_music">Media volume</string>
<!-- Hint shown in the volume toast to inform the user that the media audio is playing through Bluetooth. -->
<string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+ <!-- Hint shown in the volume toast to inform the user that the current ringtone is the silent ringtone. -->
+ <string name="volume_music_hint_silent_ringtone_selected">Silent ringtone selected</string>
<!-- Title of the dialog where the user is adjusting the phone call volume -->
<string name="volume_call">In-call volume</string>
<!-- Title of the dialog where the user is adjusting the phone call volume when connected on bluetooth-->
@@ -1754,7 +1799,7 @@
<string name="usb_storage_button_mount">Mount</string>
<!-- See USB_STORAGE. This is the button text to ignore the plugging in of the phone.. -->
<string name="usb_storage_button_unmount">Don\'t mount</string>
- <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
+ <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
<string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
<!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
<string name="usb_storage_notification_title">USB connected</string>
@@ -1775,7 +1820,7 @@
<string name="usb_storage_stop_button_mount">Turn Off</string>
<!-- See USB_STORAGE_STOP. This is the button text to cancel stoping usb storage. -->
<string name="usb_storage_stop_button_unmount">Cancel</string>
- <!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
+ <!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
<string name="usb_storage_stop_error_message">We've encountered a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
<!-- External media format dialog strings -->
@@ -1791,7 +1836,7 @@
<string name="adb_active_notification_title">USB debugging connected</string>
<!-- Message of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_message">A computer is connected to your phone.</string>
-
+
<!-- Used to replace %s in urls retreived from the signin server with locales. For Some -->
<!-- devices we don't support all the locales we ship to and need to replace the '%s' with a -->
<!-- locale string based on mcc values. By default (0-length string) we don't replace the %s -->
@@ -1801,10 +1846,10 @@
<!-- Title of the pop-up dialog in which the user switches input method components. -->
<string name="select_input_method">Select Input Method</string>
-
+
<string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
-
+
<string name="candidates_style"><u>candidates</u></string>
<!-- External media notification strings -->
@@ -1851,23 +1896,23 @@
<!-- Long label for a button on a full-screen input method for the "Go" action. -->
<string name="ime_action_go">Go</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Search" action. -->
<string name="ime_action_search">Search</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Send" action. -->
<string name="ime_action_send">Send</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Next" action. -->
<string name="ime_action_next">Next</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Done" action. -->
<string name="ime_action_done">Done</string>
-
+
<!-- Long label for a button on a full-screen input method for an unknown action. -->
<string name="ime_action_default">Execute</string>
-
- <!-- Strings for search suggestions. These are going here because they are referenced by both
+
+ <!-- Strings for search suggestions. These are going here because they are referenced by both
ContactsProvider and GoogleContactsProvider -->
<skip />
@@ -1878,8 +1923,11 @@
<!-- 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>
- <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale pairs. This is used at startup to set a default locale by checking the system property ro.carrier for the carrier-id and searching through this array -->
- <string-array translatable="false" name="carrier_locales">
+ <!-- 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] -->
+ <!-- [default-wifi-allowed-channels]] -->
+ <string-array translatable="false" name="carrier_properties">
</string-array>
<!-- Title for the selected state of a CompoundButton. -->
@@ -1888,4 +1936,19 @@
<!-- Title for the unselected state of a CompoundButton. -->
<string name="accessibility_compound_button_unselected">not checked</string>
+ <string name="grant_credentials_permission_message_desc">The
+ listed applications are requesting permission to access the login credentials for account %s from
+ %s. Do you wish to grant this permission? If so then your answer will be remembered and you will not be prompted
+ again.</string>
+
+ <string name="grant_credentials_permission_message_with_authtokenlabel_desc">The
+ listed applications are requesting permission to access the %s login credentials for account %s from
+ %s. Do you wish to grant this permission? If so then your answer will be remembered and you will not be prompted
+ again.</string>
+
+ <string name="allow">Allow</string>
+ <string name="deny">Deny</string>
+ <string name="permission_request_notification_title">Permission Requested</string>
+ <string name="permission_request_notification_subtitle">for account %s</string>
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 8eda12e..4aa4210 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -659,12 +659,12 @@
</style>
<style name="Preference.PreferenceScreen">
- <item name="android:widgetLayout">@android:layout/preferences</item>
</style>
<style name="Preference.DialogPreference">
<item name="android:positiveButtonText">@android:string/ok</item>
<item name="android:negativeButtonText">@android:string/cancel</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<style name="Preference.DialogPreference.YesNoPreference">
@@ -680,6 +680,7 @@
<item name="android:ringtoneType">ringtone</item>
<item name="android:showSilent">true</item>
<item name="android:showDefault">true</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<!-- Other Misc Styles -->
@@ -687,8 +688,8 @@
<style name="MediaButton">
<item name="android:background">@android:drawable/media_button_background</item>
- <item name="android:layout_width">71px</item>
- <item name="android:layout_height">52px</item>
+ <item name="android:layout_width">71dip</item>
+ <item name="android:layout_height">52dip</item>
</style>
<style name="MediaButton.Previous">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e3fffb7..bfdce1e 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -112,6 +112,7 @@
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>
+ <item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle</item>
<item name="windowTitleSize">25dip</item>
<item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
@@ -280,6 +281,25 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Default theme for windows that want to have the user's selected
+ wallpaper appear behind them. -->
+ <style name="Theme.Wallpaper">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowShowWallpaper">true</item>
+ </style>
+
+ <!-- Variant of the translucent theme with no title bar -->
+ <style name="Theme.Wallpaper.NoTitleBar">
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of the translucent theme that has no title bar and
+ fills the entire screen -->
+ <style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Default theme for translucent activities, that is windows that allow you
to see through them to the windows behind. This sets up the translucent
flag and appropriate animations for your windows. -->
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a3579c7..20aa6e7 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -133,6 +133,7 @@
<assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
<assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
<assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
+ <assign-permission name="android.permission.BACKUP" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
@@ -147,5 +148,7 @@
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"/>
</permissions>
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 0f89e75..e88a867 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -56,7 +56,7 @@
to understand the basics of how an Android application works.</p>
<p>You should also take a look at the ApiDemos application and the other sample
-applications included in the SDK, in the <code><sdk>/samples/
+applications included in the SDK, in the <code><sdk>/samples/</code>
folder in the SDK.</p>
<p>Finally, a great way to started with Android development in Eclipse is to
@@ -281,6 +281,15 @@
<pre>//Hide the title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
</pre>
+<p>A better way to achieve the same end is to specify a theme in your Android
+Manifest file:</p>
+<pre><application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
+</pre>
+<p>This is preferable because it tells the system not to show a title bar while
+your application is starting up. With the explicit method call, your application
+will have a title bar visible to the user until <code>onCreate</code> runs.</p>
+<p>(Note that this can be applied to either the <code><application></code>
+tag or to individual <code><activity></code> tags.)</p>
<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
<p>
If you need to refer to your host computer's <em>localhost</em>, such as when you
@@ -427,7 +436,7 @@
<td>Activity</td>
<td>By setting the theme of an activity to
{@link android.R.style#Theme_Dialog
- android:theme="android:style/Theme.Dialog"},
+ android:theme="@android:style/Theme.Dialog"},
your activity will take on
the appearance of a normal dialog, floating on top of whatever was
underneath it. You usually set the theme through the
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index 8051678..2c42e78 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -145,7 +145,7 @@
<code>SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"</code></p>
</li>
<li>Now execute:<br/>
- <code>chmod a+rx /etc/udev/rules.d/50-android.rules</code>
+ <code>chmod a+r /etc/udev/rules.d/50-android.rules</code>
</li>
</ol>
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index b111047..e8c726f 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -313,7 +313,7 @@
<li><code><tty></code> — the tty for PPP stream. For example <code>dev:/dev/omap_csmi_ttyl</code>. </li>
<li><code>[parm]... </code> &mdash zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
-<p>Note that you should not automatically start a PDP connection. </p></td>
+<p>Note that you should not automatically start a PPP connection. </p></td>
<td></td>
</tr>
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/developing/tools/ddms.jd b/docs/html/guide/developing/tools/ddms.jd
index fa04216..f55940d 100644
--- a/docs/html/guide/developing/tools/ddms.jd
+++ b/docs/html/guide/developing/tools/ddms.jd
@@ -1,7 +1,7 @@
-page.title=Using Dalvik Debug Monitor Service (DDMS)
+page.title=Using the Dalvik Debug Monitor
@jd:body
-<p>Android ships with a debugging tool called the Dalvik Debug Monitor Service (DDMS),
+<p>Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS),
which provides port-forwarding services, screen capture on the device, thread
and heap information on the device, logcat, process, and radio state information,
incoming call and SMS spoofing, location data spoofing, and more. This page
@@ -106,7 +106,7 @@
</ul>
</li>
<li> <strong>utime</strong> - cumulative time spent executing user code, in "jiffies" (usually
- 10ms). Only available under Linux. </li>
+ 10ms). </li>
<li> <strong>stime</strong> - cumulative time spent executing system code, in "jiffies" (usually
10ms). </li>
<li> <strong>Name</strong> - the name of the thread</li>
@@ -214,14 +214,15 @@
<h2 id="screen-capture">Screen Capture</h2>
<p>You can capture screen images on the device or emulator by selecting <strong>Device</strong>
- > <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.</p>
+ > <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.
+ Be sure to select a device first.</p>
<h2 id="exploring-processes">Exploring Processes</h2>
<p>You can see the output of <code>ps -x</code> for a specific VM by selecting <strong>Device</strong>
> <strong>Show process status</strong>... in the menu bar.</p>
<h2 id="cause-a-gc-to-occur">Cause a GC to Occur</h2>
-<p>Cause garbage collection to occury by pressing the trash can button on the toolbar. </p>
+<p>Cause garbage collection to occur in the selected application by pressing the trash can button on the toolbar. </p>
<h2 id="running-dumpsys-and-dumpstate">Running Dumpsys and Dumpstate on the Device (logcat)<a name="logcat" id="logcat"></a> </h2>
<ul>
@@ -239,7 +240,7 @@
<h2 id="stop-a-vitrual-machine">Stop a Virtual Machine </h2>
<p>You can stop a virtual machine by selecting <strong>Actions</strong> > <strong>Halt
-VM</strong>. Pressing this button causes the VM to call <code>System.exit(1)</code>.</p>
+VM</strong>. Pressing this button causes the VM to call <code>Runtime.halt(1)</code>.</p>
<h2 id="known-issues" style="color:#FF0000">Known issues with DDMS </h2>
<p>DDMS has the following known limitations:</p>
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index a9d1090..48e598a 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -44,8 +44,11 @@
<dt><a name="package"></a>{@code package}</dt>
<dd>A full Java package name for the application. The name should
-be unique. For example, applications published by Google could have
-names in the form <code>com.google.app.<i>application_name</i></code>.
+be unique. The name may contain uppercase or lowercase letters ('A'
+through 'Z'), numbers, and underscores ('_'). However, individual
+package name parts may only start with letters. For example, applications
+published by Google could have names in the form
+<code>com.google.app.<i>application_name</i></code>.
<p>
The package name serves as a unique identifier for the application.
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index c8bed24..2abb777 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,6 +18,7 @@
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.os.MemoryFile;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -72,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;
@@ -451,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;
}
@@ -486,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.
@@ -506,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
@@ -518,7 +523,20 @@
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
- return nativeDecodeFileDescriptor(fd, outPadding, opts);
+ try {
+ if (MemoryFile.isMemoryFile(fd)) {
+ int mappedlength = MemoryFile.getMappedSize(fd);
+ MemoryFile file = new MemoryFile(fd, mappedlength, "r");
+ InputStream is = file.getInputStream();
+ Bitmap bm = decodeStream(is, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
+ }
+ } catch (IOException ex) {
+ // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
+ return null;
+ }
+ Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
}
/**
@@ -530,7 +548,7 @@
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
- return nativeDecodeFileDescriptor(fd, null, null);
+ return decodeFileDescriptor(fd, null, null);
}
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 3fc391c..5cefaa3 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,6 +16,8 @@
package android.graphics;
+import android.util.MathUtils;
+
import java.util.HashMap;
import java.util.Locale;
@@ -105,6 +107,92 @@
}
/**
+ * Returns the hue component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float hue(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H;
+
+ if (V == temp) {
+ H = 0;
+ } else {
+ final float vtemp = (float) (V - temp);
+ final float cr = (V - r) / vtemp;
+ final float cg = (V - g) / vtemp;
+ final float cb = (V - b) / vtemp;
+
+ if (r == V) {
+ H = cb - cg;
+ } else if (g == V) {
+ H = 2 + cr - cb;
+ } else {
+ H = 4 + cg - cr;
+ }
+
+ H /= 6.f;
+ if (H < 0) {
+ H++;
+ }
+ }
+
+ return H;
+ }
+
+ /**
+ * Returns the saturation component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float saturation(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float S;
+
+ if (V == temp) {
+ S = 0;
+ } else {
+ S = (V - temp) / (float) V;
+ }
+
+ return S;
+ }
+
+ /**
+ * Returns the brightness component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float brightness(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+
+ return (V / 255.f);
+ }
+
+ /**
* Parse the color string, and return the corresponding color-int.
* If the string cannot be parsed, throws an IllegalArgumentException
* exception. Supported formats are:
@@ -134,6 +222,87 @@
}
/**
+ * Convert HSB components to an ARGB color. Alpha set to 0xFF.
+ * hsv[0] is Hue [0 .. 1)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param hsb 3 element array which holds the input HSB components.
+ * @return the resulting argb color
+ *
+ * @hide Pending API council
+ */
+ public static int HSBtoColor(float[] hsb) {
+ return HSBtoColor(hsb[0], hsb[1], hsb[2]);
+ }
+
+ /**
+ * Convert HSB components to an ARGB color. Alpha set to 0xFF.
+ * hsv[0] is Hue [0 .. 1)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param h Hue component
+ * @param s Saturation component
+ * @param b Brightness component
+ * @return the resulting argb color
+ *
+ * @hide Pending API council
+ */
+ public static int HSBtoColor(float h, float s, float b) {
+ h = MathUtils.constrain(h, 0.0f, 1.0f);
+ s = MathUtils.constrain(s, 0.0f, 1.0f);
+ b = MathUtils.constrain(b, 0.0f, 1.0f);
+
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ final float hf = (h - (int) h) * 6.0f;
+ final int ihf = (int) hf;
+ final float f = hf - ihf;
+ final float pv = b * (1.0f - s);
+ final float qv = b * (1.0f - s * f);
+ final float tv = b * (1.0f - s * (1.0f - f));
+
+ switch (ihf) {
+ case 0: // Red is the dominant color
+ red = b;
+ green = tv;
+ blue = pv;
+ break;
+ case 1: // Green is the dominant color
+ red = qv;
+ green = b;
+ blue = pv;
+ break;
+ case 2:
+ red = pv;
+ green = b;
+ blue = tv;
+ break;
+ case 3: // Blue is the dominant color
+ red = pv;
+ green = qv;
+ blue = b;
+ break;
+ case 4:
+ red = tv;
+ green = pv;
+ blue = b;
+ break;
+ case 5: // Red is the dominant color
+ red = b;
+ green = pv;
+ blue = qv;
+ break;
+ }
+
+ return 0xFF000000 | (((int) (red * 255.0f)) << 16) |
+ (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f));
+ }
+
+ /**
* Convert RGB components to HSV.
* hsv[0] is Hue [0 .. 360)
* hsv[1] is Saturation [0...1]
@@ -193,25 +362,24 @@
return nativeHSVToColor(alpha, hsv);
}
- private static native void nativeRGBToHSV(int red, int greed, int blue,
- float hsv[]);
+ private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]);
private static native int nativeHSVToColor(int alpha, float hsv[]);
private static final HashMap<String, Integer> sColorNameMap;
static {
- sColorNameMap = new HashMap();
- sColorNameMap.put("black", Integer.valueOf(BLACK));
- sColorNameMap.put("darkgray", Integer.valueOf(DKGRAY));
- sColorNameMap.put("gray", Integer.valueOf(GRAY));
- sColorNameMap.put("lightgray", Integer.valueOf(LTGRAY));
- sColorNameMap.put("white", Integer.valueOf(WHITE));
- sColorNameMap.put("red", Integer.valueOf(RED));
- sColorNameMap.put("green", Integer.valueOf(GREEN));
- sColorNameMap.put("blue", Integer.valueOf(BLUE));
- sColorNameMap.put("yellow", Integer.valueOf(YELLOW));
- sColorNameMap.put("cyan", Integer.valueOf(CYAN));
- sColorNameMap.put("magenta", Integer.valueOf(MAGENTA));
+ sColorNameMap = new HashMap<String, Integer>();
+ sColorNameMap.put("black", BLACK);
+ sColorNameMap.put("darkgray", DKGRAY);
+ sColorNameMap.put("gray", GRAY);
+ sColorNameMap.put("lightgray", LTGRAY);
+ sColorNameMap.put("white", WHITE);
+ sColorNameMap.put("red", RED);
+ sColorNameMap.put("green", GREEN);
+ sColorNameMap.put("blue", BLUE);
+ sColorNameMap.put("yellow", YELLOW);
+ sColorNameMap.put("cyan", CYAN);
+ sColorNameMap.put("magenta", MAGENTA);
}
}
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/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 0a0e4eb..21b5e39 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -102,7 +102,7 @@
private int[] mStateSet = StateSet.WILD_CARD;
private int mLevel = 0;
private int mChangingConfigurations = 0;
- private Rect mBounds = ZERO_BOUNDS_RECT;
+ private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect()
/*package*/ Callback mCallback = null;
private boolean mVisible = true;
@@ -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/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index dc80cf5..6b50406 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -237,7 +237,7 @@
final int N = mDrawableContainerState.getChildCount();
final Drawable[] drawables = mDrawableContainerState.getChildren();
for (int i = 0; i < N; i++) {
- drawables[i].mutate();
+ if (drawables[i] != null) drawables[i].mutate();
}
mMutated = true;
}
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
new file mode 100644
index 0000000..50d39b7
--- /dev/null
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -0,0 +1,258 @@
+/*
+ * 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.renderscript;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Array;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.renderscript.Type;
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class Allocation extends BaseObj {
+ Type mType;
+
+ Allocation(int id, RenderScript rs, Type t) {
+ super(rs);
+ mID = id;
+ mType = t;
+ }
+
+ public void uploadToTexture(int baseMipLevel) {
+ 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);
+ }
+
+ public void data(float[] d) {
+ mRS.nAllocationData(mID, d);
+ }
+
+ public void subData1D(int off, int count, int[] d) {
+ mRS.nAllocationSubData1D(mID, off, count, d);
+ }
+
+ public void subData1D(int off, int count, float[] d) {
+ mRS.nAllocationSubData1D(mID, off, count, d);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
+ mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
+ mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d);
+ }
+
+ public void readData(int[] d) {
+ mRS.nAllocationRead(mID, d);
+ }
+
+ public void readData(float[] d) {
+ mRS.nAllocationRead(mID, d);
+ }
+
+ public void data(Object o) {
+ mRS.nAllocationDataFromObject(mID, mType, o);
+ }
+
+
+ public class Adapter1D extends BaseObj {
+ Adapter1D(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void destroy() {
+ mRS.nAdapter1DDestroy(mID);
+ mID = 0;
+ }
+
+ public void setConstraint(Dimension dim, int value) {
+ mRS.nAdapter1DSetConstraint(mID, dim.mID, value);
+ }
+
+ public void data(int[] d) {
+ mRS.nAdapter1DData(mID, d);
+ }
+
+ public void data(float[] d) {
+ mRS.nAdapter1DData(mID, d);
+ }
+
+ public void subData(int off, int count, int[] d) {
+ mRS.nAdapter1DSubData(mID, off, count, d);
+ }
+
+ public void subData(int off, int count, float[] d) {
+ mRS.nAdapter1DSubData(mID, off, count, d);
+ }
+ }
+
+ public Adapter1D createAdapter1D() {
+ int id = mRS.nAdapter1DCreate();
+ if (id != 0) {
+ mRS.nAdapter1DBindAllocation(id, mID);
+ }
+ return new Adapter1D(id, mRS);
+ }
+
+
+ public class Adapter2D extends BaseObj {
+ Adapter2D(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void destroy() {
+ mRS.nAdapter2DDestroy(mID);
+ mID = 0;
+ }
+
+ public void setConstraint(Dimension dim, int value) {
+ mRS.nAdapter2DSetConstraint(mID, dim.mID, value);
+ }
+
+ public void data(int[] d) {
+ mRS.nAdapter2DData(mID, d);
+ }
+
+ public void data(float[] d) {
+ mRS.nAdapter2DData(mID, d);
+ }
+
+ public void subData(int xoff, int yoff, int w, int h, int[] d) {
+ mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ }
+
+ public void subData(int xoff, int yoff, int w, int h, float[] d) {
+ mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ }
+ }
+
+ public Adapter2D createAdapter2D() {
+ int id = mRS.nAdapter2DCreate();
+ if (id != 0) {
+ mRS.nAdapter2DBindAllocation(id, mID);
+ }
+ return new Adapter2D(id, mRS);
+ }
+
+
+ // creation
+
+ private static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+ static {
+ mBitmapOptions.inScaled = false;
+ }
+
+ static public Allocation createTyped(RenderScript rs, Type type)
+ throws IllegalArgumentException {
+
+ if(type.mID == 0) {
+ throw new IllegalStateException("Bad Type");
+ }
+ int id = rs.nAllocationCreateTyped(type.mID);
+ return new Allocation(id, rs, type);
+ }
+
+ static public Allocation createSized(RenderScript rs, Element e, int count)
+ throws IllegalArgumentException {
+
+ int id;
+ if(e.mIsPredefined) {
+ id = rs.nAllocationCreatePredefSized(e.mPredefinedID, count);
+ } else {
+ id = rs.nAllocationCreateSized(e.mID, count);
+ if(id == 0) {
+ throw new IllegalStateException("Bad element.");
+ }
+ }
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+ if(!dstFmt.mIsPredefined) {
+ throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+ }
+
+ int id = rs.nAllocationCreateFromBitmap(dstFmt.mPredefinedID, genMips, b);
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+ if(!dstFmt.mIsPredefined) {
+ throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+ }
+
+ int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mPredefinedID, genMips, b);
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+
+ Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
+ return createFromBitmap(rs, b, dstFmt, genMips);
+ }
+
+ static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+
+ Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
+ return createFromBitmapBoxed(rs, b, dstFmt, genMips);
+ }
+/*
+ public static Allocation createFromObject(RenderScript rs, Object o) {
+ Class c = o.getClass();
+ Type t;
+ if(c.isArray()) {
+ t = Type.createFromClass(rs, c, Array.getLength(o));
+ } else {
+ t = Type.createFromClass(rs, c, 1);
+ }
+ 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
new file mode 100644
index 0000000..f760035
--- /dev/null
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -0,0 +1,69 @@
+/*
+ * 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.renderscript;
+
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+class BaseObj {
+
+ BaseObj(RenderScript rs) {
+ mRS = rs;
+ mID = 0;
+ mDestroyed = false;
+ }
+
+ public int getID() {
+ return mID;
+ }
+
+ int mID;
+ boolean mDestroyed;
+ String mName;
+ RenderScript mRS;
+
+ public void setName(String s) throws IllegalStateException, IllegalArgumentException
+ {
+ if(s.length() < 1) {
+ throw new IllegalArgumentException("setName does not accept a zero length string.");
+ }
+ if(mName != null) {
+ throw new IllegalArgumentException("setName object already has a name.");
+ }
+
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ mRS.nAssignName(mID, bytes);
+ mName = s;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void finalize() throws Throwable
+ {
+ if (!mDestroyed) {
+ Log.v(RenderScript.LOG_TAG,
+ "Element finalized without having released the RS reference.");
+ }
+ super.finalize();
+ }
+}
+
diff --git a/graphics/java/android/renderscript/Dimension.java b/graphics/java/android/renderscript/Dimension.java
new file mode 100644
index 0000000..f29057d
--- /dev/null
+++ b/graphics/java/android/renderscript/Dimension.java
@@ -0,0 +1,35 @@
+/*
+ * 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.renderscript;
+
+/**
+ * @hide
+ **/
+public enum Dimension {
+ X (0),
+ Y (1),
+ Z (2),
+ LOD (3),
+ FACE (4),
+ ARRAY_0 (100);
+
+ int mID;
+ Dimension(int id) {
+ mID = id;
+ }
+}
+
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
new file mode 100644
index 0000000..cf181b7
--- /dev/null
+++ b/graphics/java/android/renderscript/Element.java
@@ -0,0 +1,302 @@
+/*
+ * 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.renderscript;
+
+import java.lang.reflect.Field;
+
+/**
+ * @hide
+ *
+ **/
+public class Element extends BaseObj {
+ final int mPredefinedID;
+ final boolean mIsPredefined;
+
+ public static final Element USER_U8 = new Element(0);
+ public static final Element USER_I8 = new Element(1);
+ public static final Element USER_U16 = new Element(2);
+ public static final Element USER_I16 = new Element(3);
+ public static final Element USER_U32 = new Element(4);
+ public static final Element USER_I32 = new Element(5);
+ public static final Element USER_FLOAT = new Element(6);
+
+ public static final Element A_8 = new Element(7);
+ public static final Element RGB_565 = new Element(8);
+ public static final Element RGB_888 = new Element(11);
+ public static final Element RGBA_5551 = new Element(9);
+ public static final Element RGBA_4444 = new Element(10);
+ public static final Element RGBA_8888 = new Element(12);
+
+ public static final Element INDEX_16 = new Element(13);
+ public static final Element INDEX_32 = new Element(14);
+ public static final Element XY_F32 = new Element(15);
+ public static final Element XYZ_F32 = new Element(16);
+ public static final Element ST_XY_F32 = new Element(17);
+ public static final Element ST_XYZ_F32 = new Element(18);
+ public static final Element NORM_XYZ_F32 = new Element(19);
+ public static final Element NORM_ST_XYZ_F32 = new Element(20);
+
+ void initPredef(RenderScript rs) {
+ mID = rs.nElementGetPredefined(mPredefinedID);
+ }
+
+ static void init(RenderScript rs) {
+ USER_U8.initPredef(rs);
+ USER_I8.initPredef(rs);
+ USER_U16.initPredef(rs);
+ USER_I16.initPredef(rs);
+ USER_U32.initPredef(rs);
+ USER_I32.initPredef(rs);
+ USER_FLOAT.initPredef(rs);
+
+ A_8.initPredef(rs);
+ RGB_565.initPredef(rs);
+ RGB_888.initPredef(rs);
+ RGBA_5551.initPredef(rs);
+ RGBA_4444.initPredef(rs);
+ RGBA_8888.initPredef(rs);
+
+ INDEX_16.initPredef(rs);
+ INDEX_32.initPredef(rs);
+ XY_F32.initPredef(rs);
+ XYZ_F32.initPredef(rs);
+ ST_XY_F32.initPredef(rs);
+ ST_XYZ_F32.initPredef(rs);
+ NORM_XYZ_F32.initPredef(rs);
+ NORM_ST_XYZ_F32.initPredef(rs);
+ }
+
+
+ public enum DataType {
+ FLOAT (0),
+ UNSIGNED (1),
+ SIGNED (2);
+
+ int mID;
+ DataType(int id) {
+ mID = id;
+ }
+ }
+
+ public enum DataKind {
+ USER (0),
+ RED (1),
+ GREEN (2),
+ BLUE (3),
+ ALPHA (4),
+ LUMINANCE (5),
+ INTENSITY (6),
+ X (7),
+ Y (8),
+ Z (9),
+ W (10),
+ S (11),
+ T (12),
+ Q (13),
+ R (14),
+ NX (15),
+ NY (16),
+ NZ (17),
+ INDEX (18);
+
+ int mID;
+ DataKind(int id) {
+ mID = id;
+ }
+ }
+
+
+ Element(int predef) {
+ super(null);
+ mID = 0;
+ mPredefinedID = predef;
+ mIsPredefined = true;
+ }
+
+ Element(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ mPredefinedID = 0;
+ mIsPredefined = false;
+ }
+
+ public void destroy() throws IllegalStateException {
+ if(mIsPredefined) {
+ throw new IllegalStateException("Attempting to destroy a predefined Element.");
+ }
+ if(mDestroyed) {
+ throw new IllegalStateException("Object already destroyed.");
+ }
+ mDestroyed = true;
+ mRS.nElementDestroy(mID);
+ }
+
+ public static Element createFromClass(RenderScript rs, Class c) {
+ Field[] fields = c.getFields();
+ Builder b = new Builder(rs);
+
+ for(Field f: fields) {
+ Class fc = f.getType();
+ if(fc == int.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 32, f.getName());
+ } else if(fc == short.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 16, f.getName());
+ } else if(fc == byte.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 8, f.getName());
+ } else if(fc == float.class) {
+ b.add(Element.DataType.FLOAT, Element.DataKind.USER, false, 32, f.getName());
+ } else {
+ throw new IllegalArgumentException("Unkown field type");
+ }
+ }
+ return b.create();
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Entry[] mEntries;
+ int mEntryCount;
+
+ private class Entry {
+ Element mElement;
+ Element.DataType mType;
+ Element.DataKind mKind;
+ boolean mIsNormalized;
+ int mBits;
+ String mName;
+ }
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mEntryCount = 0;
+ mEntries = new Entry[8];
+ }
+
+ void addEntry(Entry e) {
+ if(mEntries.length >= mEntryCount) {
+ Entry[] en = new Entry[mEntryCount + 8];
+ System.arraycopy(mEntries, 0, en, 0, mEntries.length);
+ mEntries = en;
+ }
+ mEntries[mEntryCount] = e;
+ mEntryCount++;
+ }
+
+ public Builder add(Element e) throws IllegalArgumentException {
+ if(!e.mIsPredefined) {
+ throw new IllegalArgumentException("add requires a predefined Element.");
+ }
+ Entry en = new Entry();
+ en.mElement = e;
+ addEntry(en);
+ return this;
+ }
+
+ public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits, String name) {
+ Entry en = new Entry();
+ en.mType = dt;
+ en.mKind = dk;
+ en.mIsNormalized = isNormalized;
+ en.mBits = bits;
+ en.mName = name;
+ addEntry(en);
+ return this;
+ }
+
+ public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits) {
+ add(dt, dk, isNormalized, bits, null);
+ 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 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++) {
+ Entry en = b.mEntries[ct];
+ if(en.mElement != null) {
+ rs.nElementAddPredefined(en.mElement.mPredefinedID);
+ } else {
+ int norm = 0;
+ if (en.mIsNormalized) {
+ norm = 1;
+ }
+ rs.nElementAdd(en.mKind.mID, en.mType.mID, norm, en.mBits, en.mName);
+ }
+ }
+ int id = rs.nElementCreate();
+ return new Element(id, rs);
+ }
+
+ public Element create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Light.java b/graphics/java/android/renderscript/Light.java
new file mode 100644
index 0000000..8067f19
--- /dev/null
+++ b/graphics/java/android/renderscript/Light.java
@@ -0,0 +1,78 @@
+/*
+ * 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.renderscript;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class Light extends BaseObj {
+ Light(int id, RenderScript rs) {
+ super(rs);
+ 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);
+ }
+
+ public void setPosition(float x, float y, float z) {
+ mRS.nLightSetPosition(mID, x, y, z);
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ boolean mIsMono;
+ boolean mIsLocal;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mIsMono = false;
+ mIsLocal = false;
+ }
+
+ public void lightSetIsMono(boolean isMono) {
+ mIsMono = isMono;
+ }
+
+ public void lightSetIsLocal(boolean isLocal) {
+ mIsLocal = isLocal;
+ }
+
+ static synchronized Light internalCreate(RenderScript rs, Builder b) {
+ rs.nSamplerBegin();
+ rs.nLightSetIsMono(b.mIsMono);
+ rs.nLightSetIsLocal(b.mIsLocal);
+ int id = rs.nLightCreate();
+ return new Light(id, rs);
+ }
+
+ public Light create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Matrix.java b/graphics/java/android/renderscript/Matrix.java
new file mode 100644
index 0000000..a266d6b
--- /dev/null
+++ b/graphics/java/android/renderscript/Matrix.java
@@ -0,0 +1,192 @@
+/*
+ * 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.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class Matrix {
+
+ public Matrix() {
+ mMat = new float[16];
+ loadIdentity();
+ }
+
+ public float get(int i, int j) {
+ return mMat[i*4 + j];
+ }
+
+ public void set(int i, int j, float v) {
+ mMat[i*4 + j] = v;
+ }
+
+ public void loadIdentity() {
+ mMat[0] = 1;
+ mMat[1] = 0;
+ mMat[2] = 0;
+ mMat[3] = 0;
+
+ mMat[4] = 0;
+ mMat[5] = 1;
+ mMat[6] = 0;
+ mMat[7] = 0;
+
+ mMat[8] = 0;
+ mMat[9] = 0;
+ mMat[10] = 1;
+ mMat[11] = 0;
+
+ mMat[12] = 0;
+ mMat[13] = 0;
+ mMat[14] = 0;
+ mMat[15] = 1;
+ }
+
+ public void load(Matrix src) {
+ mMat = src.mMat;
+ }
+
+ public void loadRotate(float rot, float x, float y, float z) {
+ float c, s;
+ mMat[3] = 0;
+ mMat[7] = 0;
+ mMat[11]= 0;
+ mMat[12]= 0;
+ mMat[13]= 0;
+ mMat[14]= 0;
+ mMat[15]= 1;
+ rot *= (float)(java.lang.Math.PI / 180.0f);
+ c = (float)java.lang.Math.cos(rot);
+ s = (float)java.lang.Math.sin(rot);
+
+ float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
+ if (!(len != 1)) {
+ float recipLen = 1.f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ float nc = 1.0f - c;
+ float xy = x * y;
+ float yz = y * z;
+ float zx = z * x;
+ float xs = x * s;
+ float ys = y * s;
+ float zs = z * s;
+ mMat[ 0] = x*x*nc + c;
+ mMat[ 4] = xy*nc - zs;
+ mMat[ 8] = zx*nc + ys;
+ mMat[ 1] = xy*nc + zs;
+ mMat[ 5] = y*y*nc + c;
+ mMat[ 9] = yz*nc - xs;
+ mMat[ 2] = zx*nc - ys;
+ mMat[ 6] = yz*nc + xs;
+ mMat[10] = z*z*nc + c;
+ }
+
+ public void loadScale(float x, float y, float z) {
+ loadIdentity();
+ mMat[0] = x;
+ mMat[5] = y;
+ mMat[10] = z;
+ }
+
+ public void loadTranslate(float x, float y, float z) {
+ loadIdentity();
+ mMat[12] = x;
+ mMat[13] = y;
+ mMat[14] = z;
+ }
+
+ public void loadMultiply(Matrix lhs, Matrix rhs) {
+ for (int i=0 ; i<4 ; i++) {
+ float ri0 = 0;
+ float ri1 = 0;
+ float ri2 = 0;
+ float ri3 = 0;
+ for (int j=0 ; j<4 ; j++) {
+ float rhs_ij = rhs.get(i,j);
+ ri0 += lhs.get(j,0) * rhs_ij;
+ ri1 += lhs.get(j,1) * rhs_ij;
+ ri2 += lhs.get(j,2) * rhs_ij;
+ ri3 += lhs.get(j,3) * rhs_ij;
+ }
+ set(i,0, ri0);
+ set(i,1, ri1);
+ set(i,2, ri2);
+ set(i,3, ri3);
+ }
+ }
+
+ public void loadOrtho(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ mMat[0] = 2 / (r - l);
+ mMat[5] = 2 / (t - b);
+ mMat[10]= -2 / (f - n);
+ mMat[12]= -(r + l) / (r - l);
+ mMat[13]= -(t + b) / (t - b);
+ mMat[14]= -(f + n) / (f - n);
+ }
+
+ public void loadFrustum(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ mMat[0] = 2 * n / (r - l);
+ mMat[5] = 2 * n / (t - b);
+ mMat[8] = (r + l) / (r - l);
+ mMat[9] = (t + b) / (t - b);
+ mMat[10]= -(f + n) / (f - n);
+ mMat[11]= -1;
+ mMat[14]= -2*f*n / (f - n);
+ mMat[15]= 0;
+ }
+
+ public void multiply(Matrix rhs) {
+ Matrix tmp = new Matrix();
+ tmp.loadMultiply(this, rhs);
+ load(tmp);
+ }
+ public void rotate(float rot, float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadRotate(rot, x, y, z);
+ multiply(tmp);
+ }
+ public void scale(float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadScale(x, y, z);
+ multiply(tmp);
+ }
+ public void translate(float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadTranslate(x, y, z);
+ multiply(tmp);
+ }
+
+
+
+ float[] mMat;
+
+}
+
+
+
+
+
diff --git a/graphics/java/android/renderscript/Primitive.java b/graphics/java/android/renderscript/Primitive.java
new file mode 100644
index 0000000..7925cac
--- /dev/null
+++ b/graphics/java/android/renderscript/Primitive.java
@@ -0,0 +1,37 @@
+/*
+ * 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.renderscript;
+
+/**
+ * @hide
+ **/
+public enum Primitive {
+ POINT (0),
+ LINE (1),
+ LINE_STRIP (2),
+ TRIANGLE (3),
+ TRIANGLE_STRIP (4),
+ TRIANGLE_FAN (5);
+
+ int mID;
+ Primitive(int id) {
+ mID = id;
+ }
+}
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
new file mode 100644
index 0000000..09c4d9a
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -0,0 +1,164 @@
+/*
+ * 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.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramFragment extends BaseObj {
+ public static final int MAX_SLOT = 2;
+
+ public enum EnvMode {
+ REPLACE (0),
+ MODULATE (1),
+ DECAL (2);
+
+ int mID;
+ EnvMode(int id) {
+ mID = id;
+ }
+ }
+
+
+ ProgramFragment(int id, RenderScript rs) {
+ super(rs);
+ 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)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mRS.nProgramFragmentBindTexture(mID, slot, va.mID);
+ }
+
+ public void bindSampler(Sampler vs, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mRS.nProgramFragmentBindSampler(mID, slot, vs.mID);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+
+ private class Slot {
+ Type mType;
+ EnvMode mEnv;
+ boolean mTexEnable;
+
+ Slot() {
+ mTexEnable = false;
+ }
+ }
+ Slot[] mSlots;
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mSlots = new Slot[MAX_SLOT];
+ for(int ct=0; ct < MAX_SLOT; ct++) {
+ mSlots[ct] = new Slot();
+ }
+ }
+
+ public void setType(int slot, Type t)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mType = t;
+ }
+
+ public void setTexEnable(boolean enable, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mTexEnable = enable;
+ }
+
+ public void setTexEnvMode(EnvMode env, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mEnv = env;
+ }
+
+
+ static synchronized ProgramFragment internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramFragmentBegin(inID, outID);
+ for(int ct=0; ct < MAX_SLOT; ct++) {
+ if(b.mSlots[ct].mTexEnable) {
+ Slot s = b.mSlots[ct];
+ if(s.mType != null) {
+ rs.nProgramFragmentSetType(ct, s.mType.mID);
+ }
+ rs.nProgramFragmentSetTexEnable(ct, true);
+ if(s.mEnv != null) {
+ rs.nProgramFragmentSetEnvMode(ct, s.mEnv.mID);
+ }
+ }
+ }
+
+
+ int id = rs.nProgramFragmentCreate();
+ return new ProgramFragment(id, rs);
+ }
+
+ public ProgramFragment create() {
+ return internalCreate(mRS, this);
+ }
+ }
+}
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
new file mode 100644
index 0000000..f8b59bd
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -0,0 +1,181 @@
+/*
+ * 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.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramStore extends BaseObj {
+ public enum DepthFunc {
+ ALWAYS (0),
+ LESS (1),
+ LEQUAL (2),
+ GREATER (3),
+ GEQUAL (4),
+ EQUAL (5),
+ NOTEQUAL (6);
+
+ int mID;
+ DepthFunc(int id) {
+ mID = id;
+ }
+ }
+
+ public enum BlendSrcFunc {
+ ZERO (0),
+ ONE (1),
+ DST_COLOR (2),
+ ONE_MINUS_DST_COLOR (3),
+ SRC_ALPHA (4),
+ ONE_MINUS_SRC_ALPHA (5),
+ DST_ALPHA (6),
+ ONE_MINUS_DST_ALPA (7),
+ SRC_ALPHA_SATURATE (8);
+
+ int mID;
+ BlendSrcFunc(int id) {
+ mID = id;
+ }
+ }
+
+ public enum BlendDstFunc {
+ ZERO (0),
+ ONE (1),
+ SRC_COLOR (2),
+ ONE_MINUS_SRC_COLOR (3),
+ SRC_ALPHA (4),
+ ONE_MINUS_SRC_ALPHA (5),
+ DST_ALPHA (6),
+ ONE_MINUS_DST_ALPA (7);
+
+ int mID;
+ BlendDstFunc(int id) {
+ mID = id;
+ }
+ }
+
+
+ ProgramStore(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void destroy() {
+ if(mDestroyed) {
+ throw new IllegalStateException("Object already destroyed.");
+ }
+ mDestroyed = true;
+ mRS.nProgramFragmentStoreDestroy(mID);
+ }
+
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+ DepthFunc mDepthFunc;
+ boolean mDepthMask;
+ boolean mColorMaskR;
+ boolean mColorMaskG;
+ boolean mColorMaskB;
+ boolean mColorMaskA;
+ BlendSrcFunc mBlendSrc;
+ BlendDstFunc mBlendDst;
+ boolean mDither;
+
+
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mDepthFunc = DepthFunc.ALWAYS;
+ mDepthMask = false;
+ mColorMaskR = true;
+ mColorMaskG = true;
+ mColorMaskB = true;
+ mColorMaskA = true;
+ mBlendSrc = BlendSrcFunc.ONE;
+ mBlendDst = BlendDstFunc.ZERO;
+
+
+ }
+
+ public void setDepthFunc(DepthFunc func) {
+ mDepthFunc = func;
+ }
+
+ public void setDepthMask(boolean enable) {
+ mDepthMask = enable;
+ }
+
+ public void setColorMask(boolean r, boolean g, boolean b, boolean a) {
+ mColorMaskR = r;
+ mColorMaskG = g;
+ mColorMaskB = b;
+ mColorMaskA = a;
+ }
+
+ public void setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) {
+ mBlendSrc = src;
+ mBlendDst = dst;
+ }
+
+ public void setDitherEnable(boolean enable) {
+ mDither = enable;
+ }
+
+ static synchronized ProgramStore internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramFragmentStoreBegin(inID, outID);
+ rs.nProgramFragmentStoreDepthFunc(b.mDepthFunc.mID);
+ rs.nProgramFragmentStoreDepthMask(b.mDepthMask);
+ rs.nProgramFragmentStoreColorMask(b.mColorMaskR,
+ b.mColorMaskG,
+ b.mColorMaskB,
+ b.mColorMaskA);
+ rs.nProgramFragmentStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID);
+ rs.nProgramFragmentStoreDither(b.mDither);
+
+ int id = rs.nProgramFragmentStoreCreate();
+ return new ProgramStore(id, rs);
+ }
+
+ public ProgramStore create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
new file mode 100644
index 0000000..74c005f
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -0,0 +1,193 @@
+/*
+ * 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.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramVertex extends BaseObj {
+ public static final int MAX_LIGHT = 8;
+
+ ProgramVertex(int id, RenderScript rs) {
+ super(rs);
+ 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);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+ Light[] mLights;
+ int mLightCount;
+ boolean mTextureMatrixEnable;
+
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mLights = new Light[MAX_LIGHT];
+ mLightCount = 0;
+ }
+
+ public void setTextureMatrixEnable(boolean enable) {
+ mTextureMatrixEnable = enable;
+ }
+
+ public void addLight(Light l) throws IllegalStateException {
+ if(mLightCount >= MAX_LIGHT) {
+ throw new IllegalArgumentException("Max light count exceeded.");
+ }
+ mLights[mLightCount] = l;
+ mLightCount++;
+ }
+
+
+
+ static synchronized ProgramVertex internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramVertexBegin(inID, outID);
+ for(int ct=0; ct < b.mLightCount; ct++) {
+ rs.nProgramVertexAddLight(b.mLights[ct].mID);
+ }
+ rs.nProgramVertexSetTextureMatrixEnable(b.mTextureMatrixEnable);
+ int id = rs.nProgramVertexCreate();
+ return new ProgramVertex(id, rs);
+ }
+
+ public ProgramVertex create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+
+
+ public static class MatrixAllocation {
+ static final int MODELVIEW_OFFSET = 0;
+ static final int PROJECTION_OFFSET = 16;
+ static final int TEXTURE_OFFSET = 32;
+
+ Matrix mModel;
+ Matrix mProjection;
+ Matrix mTexture;
+
+ public Allocation mAlloc;
+
+ public MatrixAllocation(RenderScript rs) {
+ mModel = new Matrix();
+ mProjection = new Matrix();
+ mTexture = new Matrix();
+
+ mAlloc = Allocation.createSized(rs, Element.USER_FLOAT, 48);
+ mAlloc.subData1D(MODELVIEW_OFFSET, 16, mModel.mMat);
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ mAlloc.subData1D(TEXTURE_OFFSET, 16, mTexture.mMat);
+ }
+
+ public void destroy() {
+ mAlloc.destroy();
+ mAlloc = null;
+ }
+
+ public void loadModelview(Matrix m) {
+ mModel = m;
+ mAlloc.subData1D(MODELVIEW_OFFSET, 16, m.mMat);
+ }
+
+ public void loadProjection(Matrix m) {
+ mProjection = m;
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, m.mMat);
+ }
+
+ public void loadTexture(Matrix m) {
+ mTexture = m;
+ mAlloc.subData1D(TEXTURE_OFFSET, 16, m.mMat);
+ }
+
+ public void setupOrthoWindow(int w, int h) {
+ mProjection.loadOrtho(0,w, h,0, -1,1);
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ public void setupOrthoNormalized(int w, int h) {
+ // range -1,1 in the narrow axis.
+ if(w > h) {
+ float aspect = ((float)w) / h;
+ mProjection.loadOrtho(-aspect,aspect, -1,1, -1,1);
+ } else {
+ float aspect = ((float)h) / w;
+ mProjection.loadOrtho(-1,1, -aspect,aspect, -1,1);
+ }
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ public void setupProjectionNormalized(int w, int h) {
+ // range -1,1 in the narrow axis at z = 0.
+ Matrix m1 = new Matrix();
+ Matrix m2 = new Matrix();
+
+ if(w > h) {
+ float aspect = ((float)w) / h;
+ m1.loadFrustum(-aspect,aspect, -1,1, 1,100);
+ } else {
+ float aspect = ((float)h) / w;
+ m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
+ }
+
+ m2.loadRotate(180, 0, 1, 0);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadScale(-2, 2, 1);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadTranslate(0, 0, 2);
+ m1.loadMultiply(m1, m2);
+
+ mProjection = m1;
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
new file mode 100644
index 0000000..a4be171
--- /dev/null
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -0,0 +1,157 @@
+/*
+ * 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.renderscript;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * @hide
+ *
+ **/
+public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ private SurfaceHolder mSurfaceHolder;
+
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
+ public RSSurfaceView(Context context) {
+ super(context);
+ init();
+ Log.v(RenderScript.LOG_TAG, "RSSurfaceView");
+ }
+
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
+ public RSSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ Log.v(RenderScript.LOG_TAG, "RSSurfaceView");
+ }
+
+ private void init() {
+ // Install a SurfaceHolder.Callback so we get notified when the
+ // underlying surface is created and destroyed
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(RenderScript.LOG_TAG, "surfaceCreated");
+ mSurfaceHolder = holder;
+ //mGLThread.surfaceCreated();
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ // Surface will be destroyed when we return
+ Log.v(RenderScript.LOG_TAG, "surfaceDestroyed");
+ //mGLThread.surfaceDestroyed();
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ Log.v(RenderScript.LOG_TAG, "surfaceChanged");
+
+ //mGLThread.onWindowResize(w, h);
+ }
+
+ /**
+ * Inform the view that the activity is paused. The owner of this view must
+ * call this method when the activity is paused. Calling this method will
+ * pause the rendering thread.
+ * Must not be called before a renderer has been set.
+ */
+ public void onPause() {
+ Log.v(RenderScript.LOG_TAG, "onPause");
+ //mGLThread.onPause();
+ }
+
+ /**
+ * Inform the view that the activity is resumed. The owner of this view must
+ * call this method when the activity is resumed. Calling this method will
+ * recreate the OpenGL display and resume the rendering
+ * thread.
+ * Must not be called before a renderer has been set.
+ */
+ public void onResume() {
+ Log.v(RenderScript.LOG_TAG, "onResume");
+ //mGLThread.onResume();
+ }
+
+ /**
+ * Queue a runnable to be run on the GL rendering thread. This can be used
+ * to communicate with the Renderer on the rendering thread.
+ * Must not be called before a renderer has been set.
+ * @param r the runnable to be run on the GL rendering thread.
+ */
+ public void queueEvent(Runnable r) {
+ Log.v(RenderScript.LOG_TAG, "queueEvent");
+ //mGLThread.queueEvent(r);
+ }
+
+ /**
+ * This method is used as part of the View class and is not normally
+ * called or subclassed by clients of RSSurfaceView.
+ * Must not be called before a renderer has been set.
+ */
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ //mGLThread.requestExitAndWait();
+ }
+
+ // ----------------------------------------------------------------------
+
+ public RenderScript createRenderScript() {
+ Log.v(RenderScript.LOG_TAG, "createRenderScript 1");
+ 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");
+ return rs;
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
new file mode 100644
index 0000000..ab263ed
--- /dev/null
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -0,0 +1,329 @@
+/*
+ * 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.renderscript;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.renderscript.Type;
+import android.util.Config;
+import android.util.Log;
+import android.view.Surface;
+
+
+/**
+ * @hide
+ *
+ **/
+public class RenderScript {
+ static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+
+
+ /*
+ * We use a class initializer to allow the native code to cache some
+ * field offsets.
+ */
+ private static boolean sInitialized;
+ native private static void _nInit();
+
+
+ static {
+ sInitialized = false;
+ try {
+ System.loadLibrary("rs_jni");
+ _nInit();
+ sInitialized = true;
+ } catch (UnsatisfiedLinkError e) {
+ Log.d(LOG_TAG, "RenderScript JNI library not found!");
+ }
+ }
+
+ native int nDeviceCreate();
+ native void nDeviceDestroy(int dev);
+ native int nContextCreate(int dev, Surface sur, int ver);
+ native void nContextDestroy(int con);
+
+ //void rsContextBindSampler (uint32_t slot, RsSampler sampler);
+ //void rsContextBindRootScript (RsScript sampler);
+ native void nContextBindRootScript(int script);
+ native void nContextBindSampler(int sampler, int slot);
+ native void nContextBindProgramFragmentStore(int pfs);
+ native void nContextBindProgramFragment(int pf);
+ native void nContextBindProgramVertex(int pf);
+ native void nContextAddDefineI32(String name, int value);
+ native void nContextAddDefineF(String name, float value);
+
+ native void nAssignName(int obj, byte[] name);
+ native int nFileOpen(byte[] name);
+
+ native void nElementBegin();
+ native void nElementAddPredefined(int predef);
+ 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);
+
+ native int nAllocationCreateTyped(int type);
+ native int nAllocationCreatePredefSized(int predef, int count);
+ native int nAllocationCreateSized(int elem, int count);
+ native int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+ 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);
+ native void nAllocationSubData1D(int id, int off, int count, float[] d);
+ native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d);
+ native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d);
+ native void nAllocationRead(int id, int[] d);
+ 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);
+ native void nTriangleMeshAddVertex_XY_ST (float x, float y, float s, float t);
+ native void nTriangleMeshAddVertex_XYZ_ST (float x, float y, float z, float s, float t);
+ native void nTriangleMeshAddVertex_XYZ_ST_NORM (float x, float y, float z, float s, float t, float nx, float ny, float nz);
+ 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);
+ native void nAdapter1DData(int ad, float[] d);
+ native void nAdapter1DSubData(int ad, int off, int count, int[] d);
+ 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);
+ native void nAdapter2DData(int ad, float[] d);
+ native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, int[] d);
+ 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, boolean writable, String name, int slot);
+ native void nScriptSetRoot(boolean isRoot);
+
+ native void nScriptCBegin();
+ native void nScriptCSetScript(byte[] script, int offset, int length);
+ native int nScriptCCreate();
+ 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();
+
+ native void nProgramFragmentStoreBegin(int in, int out);
+ native void nProgramFragmentStoreDepthFunc(int func);
+ native void nProgramFragmentStoreDepthMask(boolean enable);
+ native void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
+ 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 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 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);
+ native void nProgramVertexAddLight(int id);
+ native int nProgramVertexCreate();
+
+ native void nLightBegin();
+ 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();
+
+ private int mDev;
+ private int mContext;
+ private Surface mSurface;
+
+ private static boolean mElementsInitialized = false;
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+
+ public RenderScript(Surface sur) {
+ mSurface = sur;
+ mDev = nDeviceCreate();
+ mContext = nContextCreate(mDev, mSurface, 0);
+
+ // TODO: This should be protected by a lock
+ if(!mElementsInitialized) {
+ Element.init(this);
+ mElementsInitialized = true;
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Triangle Mesh
+
+ public class TriangleMesh extends BaseObj {
+ TriangleMesh(int id) {
+ super(RenderScript.this);
+ mID = id;
+ }
+
+ public void destroy() {
+ nTriangleMeshDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void triangleMeshBegin(Element vertex, Element index) {
+ Log.e("rs", "vtx " + vertex.toString() + " " + vertex.mID + " " + vertex.mPredefinedID);
+ nTriangleMeshBegin(vertex.mID, index.mID);
+ }
+
+ public void triangleMeshAddVertex_XY(float x, float y) {
+ nTriangleMeshAddVertex_XY(x, y);
+ }
+
+ public void triangleMeshAddVertex_XYZ(float x, float y, float z) {
+ nTriangleMeshAddVertex_XYZ(x, y, z);
+ }
+
+ public void triangleMeshAddVertex_XY_ST(float x, float y, float s, float t) {
+ nTriangleMeshAddVertex_XY_ST(x, y, s, t);
+ }
+
+ public void triangleMeshAddVertex_XYZ_ST(float x, float y, float z, float s, float t) {
+ nTriangleMeshAddVertex_XYZ_ST(x, y, z, s, t);
+ }
+
+ public void triangleMeshAddVertex_XYZ_ST_NORM(float x, float y, float z, float s, float t, float nx, float ny, float nz) {
+ nTriangleMeshAddVertex_XYZ_ST_NORM(x, y, z, s, t, nx, ny, nz);
+ }
+
+ public void triangleMeshAddTriangle(int i1, int i2, int i3) {
+ nTriangleMeshAddTriangle(i1, i2, i3);
+ }
+
+ public TriangleMesh triangleMeshCreate() {
+ int id = nTriangleMeshCreate();
+ return new TriangleMesh(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // File
+
+ public class File extends BaseObj {
+ File(int id) {
+ super(RenderScript.this);
+ mID = id;
+ }
+
+ public void destroy() {
+ //nLightDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
+ {
+ if(s.length() < 1) {
+ throw new IllegalArgumentException("fileOpen does not accept a zero length string.");
+ }
+
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ int id = nFileOpen(bytes);
+ return new File(id);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Root state
+
+ public void contextBindRootScript(Script s) {
+ nContextBindRootScript(s.mID);
+ }
+
+ //public void contextBindSampler(Sampler s, int slot) {
+ //nContextBindSampler(s.mID);
+ //}
+
+ public void contextBindProgramFragmentStore(ProgramStore pfs) {
+ nContextBindProgramFragmentStore(pfs.mID);
+ }
+
+ public void contextBindProgramFragment(ProgramFragment pf) {
+ nContextBindProgramFragment(pf.mID);
+ }
+
+ public void contextBindProgramVertex(ProgramVertex pf) {
+ nContextBindProgramVertex(pf.mID);
+ }
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
new file mode 100644
index 0000000..dfeac81
--- /dev/null
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -0,0 +1,113 @@
+/*
+ * 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.renderscript;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Config;
+import android.util.Log;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+/**
+ * @hide
+ *
+ **/
+public class Sampler extends BaseObj {
+ public enum Value {
+ NEAREST (0),
+ LINEAR (1),
+ LINEAR_MIP_LINEAR (2),
+ WRAP (3),
+ CLAMP (4);
+
+ int mID;
+ Value(int id) {
+ mID = id;
+ }
+ }
+
+ Sampler(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void destroy() {
+ mRS.nSamplerDestroy(mID);
+ mID = 0;
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ Value mMin;
+ Value mMag;
+ Value mWrapS;
+ Value mWrapT;
+ Value mWrapR;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mMin = Value.NEAREST;
+ mMag = Value.NEAREST;
+ mWrapS = Value.WRAP;
+ mWrapT = Value.WRAP;
+ mWrapR = Value.WRAP;
+ }
+
+ public void setMin(Value v) {
+ mMin = v;
+ }
+
+ public void setMag(Value v) {
+ mMag = v;
+ }
+
+ public void setWrapS(Value v) {
+ mWrapS = v;
+ }
+
+ public void setWrapT(Value v) {
+ mWrapT = v;
+ }
+
+ public void setWrapR(Value v) {
+ mWrapR = v;
+ }
+
+ static synchronized Sampler internalCreate(RenderScript rs, Builder b) {
+ rs.nSamplerBegin();
+ rs.nSamplerSet(0, b.mMin.mID);
+ rs.nSamplerSet(1, b.mMag.mID);
+ rs.nSamplerSet(2, b.mWrapS.mID);
+ rs.nSamplerSet(3, b.mWrapT.mID);
+ rs.nSamplerSet(4, b.mWrapR.mID);
+ int id = rs.nSamplerCreate();
+ return new Sampler(id, rs);
+ }
+
+ public Sampler create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
new file mode 100644
index 0000000..5b9eb55
--- /dev/null
+++ b/graphics/java/android/renderscript/Script.java
@@ -0,0 +1,115 @@
+/*
+ * 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.renderscript;
+
+/**
+ * @hide
+ **/
+public class Script extends BaseObj {
+ public static final int MAX_SLOT = 16;
+
+ 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);
+ }
+
+ public void setClearColor(float r, float g, float b, float a) {
+ mRS.nScriptSetClearColor(mID, r, g, b, a);
+ }
+
+ public void setClearDepth(float d) {
+ mRS.nScriptSetClearDepth(mID, d);
+ }
+
+ public void setClearStencil(int stencil) {
+ mRS.nScriptSetClearStencil(mID, stencil);
+ }
+
+ public void setTimeZone(String timeZone) {
+ try {
+ mRS.nScriptSetTimeZone(mID, timeZone.getBytes("UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ 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) {
+ mTypes[slot] = t;
+ mNames[slot] = null;
+ }
+
+ public void setType(Type t, String name, int slot) {
+ mTypes[slot] = t;
+ 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, mWritable[ct], mNames[ct], ct);
+ }
+ }
+ }
+
+ void transferObject(Script s) {
+ s.mIsRoot = mIsRoot;
+ s.mTypes = mTypes;
+ }
+
+ public void setRoot(boolean r) {
+ mIsRoot = r;
+ }
+
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
new file mode 100644
index 0000000..bb99e23
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -0,0 +1,161 @@
+/*
+ * 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.renderscript;
+
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * @hide
+ **/
+public class ScriptC extends Script {
+ private static final String TAG = "ScriptC";
+
+ ScriptC(int id, RenderScript rs) {
+ super(id, rs);
+ }
+
+ public static class Builder extends Script.Builder {
+ byte[] mProgram;
+ int mProgramLength;
+ HashMap<String,Integer> mIntDefines = new HashMap();
+ HashMap<String,Float> mFloatDefines = new HashMap();
+
+ public Builder(RenderScript rs) {
+ super(rs);
+ }
+
+ public void setScript(String s) {
+ try {
+ mProgram = s.getBytes("UTF-8");
+ mProgramLength = mProgram.length;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setScript(Resources resources, int id) {
+ InputStream is = resources.openRawResource(id);
+ try {
+ try {
+ setScript(is);
+ } finally {
+ is.close();
+ }
+ } catch(IOException e) {
+ throw new Resources.NotFoundException();
+ }
+ }
+
+ public void setScript(InputStream is) throws IOException {
+ byte[] buf = new byte[1024];
+ int currentPos = 0;
+ while(true) {
+ int bytesLeft = buf.length - currentPos;
+ if (bytesLeft == 0) {
+ byte[] buf2 = new byte[buf.length * 2];
+ System.arraycopy(buf, 0, buf2, 0, buf.length);
+ buf = buf2;
+ bytesLeft = buf.length - currentPos;
+ }
+ int bytesRead = is.read(buf, currentPos, bytesLeft);
+ if (bytesRead <= 0) {
+ break;
+ }
+ currentPos += bytesRead;
+ }
+ mProgram = buf;
+ mProgramLength = currentPos;
+ }
+
+ static synchronized ScriptC internalCreate(Builder b) {
+ b.mRS.nScriptCBegin();
+ b.transferCreate();
+
+ for (Entry<String,Integer> e: b.mIntDefines.entrySet()) {
+ b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue());
+ }
+ for (Entry<String,Float> e: b.mFloatDefines.entrySet()) {
+ b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue());
+ }
+
+ b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
+
+ int id = b.mRS.nScriptCCreate();
+ ScriptC obj = new ScriptC(id, b.mRS);
+ b.transferObject(obj);
+
+ return obj;
+ }
+
+ public void addDefine(String name, int value) {
+ mIntDefines.put(name, value);
+ }
+
+ public void addDefine(String name, float value) {
+ mFloatDefines.put(name, value);
+ }
+
+ /**
+ * Takes the all public static final fields for a class, and adds defines
+ * for them, using the name of the field as the name of the define.
+ */
+ public void addDefines(Class cl) {
+ addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null);
+ }
+
+ /**
+ * Takes the all public fields for an object, and adds defines
+ * for them, using the name of the field as the name of the define.
+ */
+ public void addDefines(Object o) {
+ addDefines(o.getClass().getFields(), Modifier.PUBLIC, o);
+ }
+
+ void addDefines(Field[] fields, int mask, Object o) {
+ for (Field f: fields) {
+ try {
+ if ((f.getModifiers() & mask) == mask) {
+ Class t = f.getType();
+ if (t == int.class) {
+ mIntDefines.put(f.getName(), f.getInt(o));
+ }
+ else if (t == float.class) {
+ mFloatDefines.put(f.getName(), f.getFloat(o));
+ }
+ }
+ } catch (IllegalAccessException ex) {
+ // TODO: Do we want this log?
+ Log.d(TAG, "addDefines skipping field " + f.getName());
+ }
+ }
+ }
+
+ public ScriptC create() {
+ return internalCreate(this);
+ }
+ }
+}
+
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
new file mode 100644
index 0000000..484849b
--- /dev/null
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -0,0 +1,179 @@
+/*
+ * 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.renderscript;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class SimpleMesh extends BaseObj {
+ Type[] mVertexTypes;
+ Type mIndexType;
+ //Type mBatcheType;
+ Primitive mPrimitive;
+
+ SimpleMesh(int id, RenderScript rs) {
+ super(rs);
+ 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);
+ }
+
+ public void bindIndexAllocation(Allocation a) {
+ mRS.nSimpleMeshBindIndex(mID, a.mID);
+ }
+
+ public Allocation createVertexAllocation(int slot) {
+ return Allocation.createTyped(mRS, mVertexTypes[slot]);
+ }
+
+ public Allocation createIndexAllocation() {
+ return Allocation.createTyped(mRS, mIndexType);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+
+ class Entry {
+ Type t;
+ Element e;
+ int size;
+ }
+
+ int mVertexTypeCount;
+ Entry[] mVertexTypes;
+ Entry mIndexType;
+ //Entry mBatchType;
+ Primitive mPrimitive;
+
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mVertexTypeCount = 0;
+ mVertexTypes = new Entry[16];
+ mIndexType = new Entry();
+ }
+
+ public int addVertexType(Type t) throws IllegalStateException {
+ if(mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].t = t;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public int addVertexType(Element e, int size) throws IllegalStateException {
+ if(mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].e = e;
+ mVertexTypes[mVertexTypeCount].size = size;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public void setIndexType(Type t) {
+ mIndexType.t = t;
+ mIndexType.e = null;
+ mIndexType.size = 0;
+ }
+
+ public void setIndexType(Element e, int size) {
+ mIndexType.t = null;
+ mIndexType.e = e;
+ mIndexType.size = size;
+ }
+
+ public void setPrimitive(Primitive p) {
+ mPrimitive = p;
+ }
+
+
+ Type newType(Element e, int size) {
+ Type.Builder tb = new Type.Builder(mRS, e);
+ tb.add(Dimension.X, size);
+ return tb.create();
+ }
+
+ static synchronized SimpleMesh internalCreate(RenderScript rs, Builder b) {
+ Type[] toDestroy = new Type[18];
+ int toDestroyCount = 0;
+
+ int indexID = 0;
+ if(b.mIndexType.t != null) {
+ indexID = b.mIndexType.t.mID;
+ } else if(b.mIndexType.size != 0) {
+ b.mIndexType.t = b.newType(b.mIndexType.e, b.mIndexType.size);
+ indexID = b.mIndexType.t.mID;
+ toDestroy[toDestroyCount++] = b.mIndexType.t;
+ }
+
+ int[] IDs = new int[b.mVertexTypeCount];
+ for(int ct=0; ct < b.mVertexTypeCount; ct++) {
+ if(b.mVertexTypes[ct].t != null) {
+ IDs[ct] = b.mVertexTypes[ct].t.mID;
+ } else {
+ b.mVertexTypes[ct].t = b.newType(b.mVertexTypes[ct].e, b.mVertexTypes[ct].size);
+ IDs[ct] = b.mVertexTypes[ct].t.mID;
+ toDestroy[toDestroyCount++] = b.mVertexTypes[ct].t;
+ }
+ }
+
+ int id = rs.nSimpleMeshCreate(0, indexID, IDs, b.mPrimitive.mID);
+ for(int ct=0; ct < toDestroyCount; ct++) {
+ toDestroy[ct].destroy();
+ }
+
+ return new SimpleMesh(id, rs);
+ }
+
+ public SimpleMesh create() {
+ Log.e("rs", "SimpleMesh create");
+ SimpleMesh sm = internalCreate(mRS, this);
+ sm.mVertexTypes = new Type[mVertexTypeCount];
+ for(int ct=0; ct < mVertexTypeCount; ct++) {
+ sm.mVertexTypes[ct] = mVertexTypes[ct].t;
+ }
+ sm.mIndexType = mIndexType.t;
+ sm.mPrimitive = mPrimitive;
+ return sm;
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
new file mode 100644
index 0000000..afb0e60
--- /dev/null
+++ b/graphics/java/android/renderscript/Type.java
@@ -0,0 +1,158 @@
+/*
+ * 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.renderscript;
+
+import java.lang.reflect.Field;
+
+import android.renderscript.Element;
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class Type extends BaseObj {
+ Dimension[] mDimensions;
+ int[] mValues;
+ Element mElement;
+ private int mNativeCache;
+ Class mJavaClass;
+
+
+ Type(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ mNativeCache = 0;
+ }
+
+ protected void finalize() throws Throwable {
+ if(mNativeCache != 0) {
+ mRS.nTypeFinalDestroy(this);
+ mNativeCache = 0;
+ }
+ 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);
+ b.add(Dimension.X, size);
+ Type t = b.create();
+ e.destroy();
+
+ // native fields
+ {
+ Field[] fields = c.getFields();
+ int[] arTypes = new int[fields.length];
+ int[] arBits = new int[fields.length];
+
+ for(int ct=0; ct < fields.length; ct++) {
+ Field f = fields[ct];
+ Class fc = f.getType();
+ if(fc == int.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 32;
+ } else if(fc == short.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 16;
+ } else if(fc == byte.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 8;
+ } else if(fc == float.class) {
+ arTypes[ct] = Element.DataType.FLOAT.mID;
+ arBits[ct] = 32;
+ } else {
+ throw new IllegalArgumentException("Unkown field type");
+ }
+ }
+ rs.nTypeSetupFields(t, arTypes, arBits, fields);
+ }
+ t.mJavaClass = c;
+ return t;
+ }
+
+ public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) {
+ Type t = createFromClass(rs, c, size);
+ t.setName(scriptName);
+ return t;
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Entry[] mEntries;
+ int mEntryCount;
+ Element mElement;
+
+ class Entry {
+ Dimension mDim;
+ int mValue;
+ }
+
+ public Builder(RenderScript rs, Element e) {
+ mRS = rs;
+ mEntries = new Entry[4];
+ mElement = e;
+ }
+
+ 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];
+ }
+ mEntries = en;
+ }
+ mEntries[mEntryCount] = new Entry();
+ mEntries[mEntryCount].mDim = d;
+ mEntries[mEntryCount].mValue = value;
+ mEntryCount++;
+ }
+
+ static synchronized Type internalCreate(RenderScript rs, Builder b) {
+ rs.nTypeBegin(b.mElement.mID);
+ for (int ct=0; ct < b.mEntryCount; ct++) {
+ Entry en = b.mEntries[ct];
+ rs.nTypeAdd(en.mDim.mID, en.mValue);
+ }
+ int id = rs.nTypeCreate();
+ return new Type(id, rs);
+ }
+
+ public Type create() {
+ Type t = internalCreate(mRS, this);
+ t.mElement = mElement;
+ t.mDimensions = new Dimension[mEntryCount];
+ t.mValues = new int[mEntryCount];
+ for(int ct=0; ct < mEntryCount; ct++) {
+ t.mDimensions[ct] = mEntries[ct].mDim;
+ t.mValues[ct] = mEntries[ct].mValue;
+ }
+ return t;
+ }
+ }
+
+}
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
new file mode 100644
index 0000000..799fcbb
--- /dev/null
+++ b/graphics/jni/Android.mk
@@ -0,0 +1,45 @@
+
+# libRS needs libacc, which isn't 64-bit clean, and so can't be built
+# for the simulator on gHardy, and therefore libRS needs to be excluded
+# from the simulator as well, and so in turn librs_jni needs to be
+# excluded.
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ android_renderscript_RenderScript.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libacc \
+ libnativehelper \
+ libRS \
+ libcutils \
+ libskia \
+ libutils \
+ libui
+
+LOCAL_STATIC_LIBRARIES :=
+
+rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(LOCAL_PATH)/../../libs/rs \
+ $(rs_generated_include_dir) \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_CFLAGS +=
+
+LOCAL_LDLIBS := -lpthread
+LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
+LOCAL_MODULE:= librs_jni
+LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := libRS
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif #simulator
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
new file mode 100644
index 0000000..ff997e7
--- /dev/null
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -0,0 +1,1472 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libRS_jni"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <utils/misc.h>
+
+#include <ui/Surface.h>
+
+#include <core/SkBitmap.h>
+
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <RenderScript.h>
+#include <RenderScriptEnv.h>
+
+//#define LOG_API LOGE
+#define LOG_API(...)
+
+using namespace android;
+
+// ---------------------------------------------------------------------------
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+}
+
+static jfieldID gContextId = 0;
+static jfieldID gNativeBitmapID = 0;
+static jfieldID gTypeNativeCache = 0;
+
+static void _nInit(JNIEnv *_env, jclass _this)
+{
+ gContextId = _env->GetFieldID(_this, "mContext", "I");
+
+ jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
+ gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
+
+ jclass typeClass = _env->FindClass("android/renderscript/Type");
+ gTypeNativeCache = _env->GetFieldID(typeClass, "mNativeCache", "I");
+}
+
+
+// ---------------------------------------------------------------------------
+
+static void
+nAssignName(JNIEnv *_env, jobject _this, jint obj, jbyteArray str)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAssignName, con(%p), obj(%p)", con, obj);
+
+ jint len = _env->GetArrayLength(str);
+ jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+ rsAssignName(con, (void *)obj, (const char *)cptr, len);
+ _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
+}
+
+
+static jint
+nFileOpen(JNIEnv *_env, jobject _this, jbyteArray str)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nFileOpen, con(%p)", con);
+
+ jint len = _env->GetArrayLength(str);
+ jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+ jint ret = (jint)rsFileOpen(con, (const char *)cptr, len);
+ _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
+ return ret;
+}
+
+// ---------------------------------------------------------------------------
+
+static jint
+nDeviceCreate(JNIEnv *_env, jobject _this)
+{
+ LOG_API("nDeviceCreate");
+ return (jint)rsDeviceCreate();
+}
+
+static void
+nDeviceDestroy(JNIEnv *_env, jobject _this, jint dev)
+{
+ LOG_API("nDeviceDestroy");
+ return rsDeviceDestroy((RsDevice)dev);
+}
+
+static jint
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver)
+{
+ LOG_API("nContextCreate");
+
+ if (wnd == NULL) {
+ not_valid_surface:
+ doThrow(_env, "java/lang/IllegalArgumentException",
+ "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface");
+ return 0;
+ }
+ jclass surface_class = _env->FindClass("android/view/Surface");
+ jfieldID surfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I");
+ Surface * window = (Surface*)_env->GetIntField(wnd, surfaceFieldID);
+ if (window == NULL)
+ goto not_valid_surface;
+
+ return (jint)rsContextCreate((RsDevice)dev, window, ver);
+}
+
+static void
+nContextDestroy(JNIEnv *_env, jobject _this, jint con)
+{
+ LOG_API("nContextDestroy, con(%p)", (RsContext)con);
+ return rsContextDestroy((RsContext)con);
+}
+
+
+static void
+nElementBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementBegin, con(%p)", con);
+ rsElementBegin(con);
+}
+
+static void
+nElementAddPredefined(JNIEnv *_env, jobject _this, jint predef)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementAddPredefined, con(%p), predef(%i)", con, predef);
+ rsElementAddPredefined(con, (RsElementPredefined)predef);
+}
+
+static void
+nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jint norm, jint bits, jstring name)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = NULL;
+ if (name) {
+ n = _env->GetStringUTFChars(name, NULL);
+ }
+ LOG_API("nElementAdd, con(%p), kind(%i), type(%i), norm(%i), bits(%i)", con, kind, type, norm, bits);
+ rsElementAdd(con, (RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits, n);
+ if (n) {
+ _env->ReleaseStringUTFChars(name, n);
+ }
+}
+
+static jint
+nElementCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementCreate, con(%p)", con);
+ return (jint)rsElementCreate(con);
+}
+
+static jint
+nElementGetPredefined(JNIEnv *_env, jobject _this, jint predef)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementGetPredefined, con(%p) predef(%i)", con, predef);
+ return (jint)rsElementGetPredefined(con, (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(con, (RsElement)e);
+}
+
+// -----------------------------------
+
+static void
+nTypeBegin(JNIEnv *_env, jobject _this, jint eID)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeBegin, con(%p) e(%p)", con, (RsElement)eID);
+ rsTypeBegin(con, (RsElement)eID);
+}
+
+static void
+nTypeAdd(JNIEnv *_env, jobject _this, jint dim, jint val)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeAdd, con(%p) dim(%i), val(%i)", con, dim, val);
+ rsTypeAdd(con, (RsDimension)dim, val);
+}
+
+static jint
+nTypeCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeCreate, con(%p)", con);
+ return (jint)rsTypeCreate(con);
+}
+
+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(con, (RsType)eID);
+}
+
+static void * SF_LoadInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int32_t *)buffer)[0] = _env->GetIntField(_obj, _field);
+ return ((uint8_t *)buffer) + 4;
+}
+
+static void * SF_LoadShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int16_t *)buffer)[0] = _env->GetShortField(_obj, _field);
+ return ((uint8_t *)buffer) + 2;
+}
+
+static void * SF_LoadByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int8_t *)buffer)[0] = _env->GetByteField(_obj, _field);
+ return ((uint8_t *)buffer) + 1;
+}
+
+static void * SF_LoadFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((float *)buffer)[0] = _env->GetFloatField(_obj, _field);
+ return ((uint8_t *)buffer) + 4;
+}
+
+struct TypeFieldCache {
+ jfieldID field;
+ int bits;
+ void * (*ptr)(JNIEnv *, jobject, jfieldID, void *buffer);
+};
+
+struct TypeCache {
+ int fieldCount;
+ int size;
+ TypeFieldCache fields[1];
+};
+
+//{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy },
+static void
+nTypeFinalDestroy(JNIEnv *_env, jobject _this, jobject _type)
+{
+ TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache);
+ free(tc);
+}
+
+// native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
+static void
+nTypeSetupFields(JNIEnv *_env, jobject _this, jobject _type, jintArray _types, jintArray _bits, jobjectArray _IDs)
+{
+ int fieldCount = _env->GetArrayLength(_types);
+ size_t structSize = sizeof(TypeCache) + (sizeof(TypeFieldCache) * (fieldCount-1));
+ TypeCache *tc = (TypeCache *)malloc(structSize);
+ memset(tc, 0, structSize);
+
+ TypeFieldCache *tfc = &tc->fields[0];
+ tc->fieldCount = fieldCount;
+ _env->SetIntField(_type, gTypeNativeCache, (jint)tc);
+
+ jint *fType = _env->GetIntArrayElements(_types, NULL);
+ jint *fBits = _env->GetIntArrayElements(_bits, NULL);
+ for (int ct=0; ct < fieldCount; ct++) {
+ jobject field = _env->GetObjectArrayElement(_IDs, ct);
+ tfc[ct].field = _env->FromReflectedField(field);
+ tfc[ct].bits = fBits[ct];
+
+ switch(fType[ct]) {
+ case RS_TYPE_FLOAT:
+ tfc[ct].ptr = SF_LoadFloat;
+ break;
+ case RS_TYPE_UNSIGNED:
+ case RS_TYPE_SIGNED:
+ switch(tfc[ct].bits) {
+ case 32: tfc[ct].ptr = SF_LoadInt; break;
+ case 16: tfc[ct].ptr = SF_LoadShort; break;
+ case 8: tfc[ct].ptr = SF_LoadByte; break;
+ }
+ break;
+ }
+ tc->size += 4;
+ }
+
+ _env->ReleaseIntArrayElements(_types, fType, JNI_ABORT);
+ _env->ReleaseIntArrayElements(_bits, fBits, JNI_ABORT);
+}
+
+
+// -----------------------------------
+
+static jint
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, jint e)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreateTyped, con(%p), e(%p)", con, (RsElement)e);
+ return (jint) rsAllocationCreateTyped(con, (RsElement)e);
+}
+
+static jint
+nAllocationCreatePredefSized(JNIEnv *_env, jobject _this, jint predef, jint count)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreatePredefSized, con(%p), predef(%i), count(%i)", con, predef, count);
+ return (jint) rsAllocationCreatePredefSized(con, (RsElementPredefined)predef, count);
+}
+
+static jint
+nAllocationCreateSized(JNIEnv *_env, jobject _this, jint e, jint count)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreateSized, con(%p), e(%p), count(%i)", con, (RsElement)e, count);
+ return (jint) rsAllocationCreateSized(con, (RsElement)e, count);
+}
+
+static void
+nAllocationUploadToTexture(JNIEnv *_env, jobject _this, jint a, jint mip)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationUploadToTexture, con(%p), a(%p), mip(%i)", con, (RsAllocation)a, mip);
+ rsAllocationUploadToTexture(con, (RsAllocation)a, mip);
+}
+
+static RsElementPredefined SkBitmapToPredefined(SkBitmap::Config cfg)
+{
+ switch (cfg) {
+ case SkBitmap::kA8_Config:
+ return RS_ELEMENT_A_8;
+ case SkBitmap::kARGB_4444_Config:
+ return RS_ELEMENT_RGBA_4444;
+ case SkBitmap::kARGB_8888_Config:
+ return RS_ELEMENT_RGBA_8888;
+ case SkBitmap::kRGB_565_Config:
+ return RS_ELEMENT_RGB_565;
+
+ default:
+ break;
+ }
+ // If we don't have a conversion mark it as a user type.
+ LOGE("Unsupported bitmap type");
+ return RS_ELEMENT_USER_U8;
+}
+
+static int
+nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElementPredefined e = SkBitmapToPredefined(config);
+
+ if (e != RS_ELEMENT_USER_U8) {
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* ptr = bitmap.getPixels();
+ jint id = (jint)rsAllocationCreateFromBitmap(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+static int
+nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElementPredefined e = SkBitmapToPredefined(config);
+
+ if (e != RS_ELEMENT_USER_U8) {
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* ptr = bitmap.getPixels();
+ jint id = (jint)rsAllocationCreateFromBitmapBoxed(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+
+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(con, (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(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray 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);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAllocationData(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_i(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, offset, count, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_f(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, offset, count, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData2D_i(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData2D_f(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationRead_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_COMMIT);
+}
+
+static void
+nAllocationRead_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_COMMIT);
+}
+
+
+//{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
+static void
+nAllocationDataFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jobject _o)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationDataFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc);
+
+ const TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache);
+
+ void * bufAlloc = malloc(tc->size);
+ void * buf = bufAlloc;
+ for (int ct=0; ct < tc->fieldCount; ct++) {
+ const TypeFieldCache *tfc = &tc->fields[ct];
+ buf = tfc->ptr(_env, _o, tfc->field, buf);
+ }
+ rsAllocationData(con, (RsAllocation)alloc, bufAlloc);
+ const uint32_t * tmp = (const uint32_t *)bufAlloc;
+ free(bufAlloc);
+}
+
+// -----------------------------------
+
+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(con, (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(con, (RsElement)v, (RsElement)i);
+}
+
+static void
+nTriangleMeshAddVertex_XY(JNIEnv *_env, jobject _this, jfloat x, jfloat y)
+{
+ 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(con, v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z)
+{
+ 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(con, v);
+}
+
+static void
+nTriangleMeshAddVertex_XY_ST(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat s, jfloat t)
+{
+ 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(con, v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ_ST(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat s, jfloat t)
+{
+ 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(con, v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ_ST_NORM(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat s, jfloat t, jfloat nx, jfloat ny, jfloat nz)
+{
+ 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(con, v);
+}
+
+static void
+nTriangleMeshAddTriangle(JNIEnv *_env, jobject _this, jint i1, jint i2, jint i3)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddTriangle, con(%p), i1(%i), i2(%i), i3(%i)", con, i1, i2, i3);
+ rsTriangleMeshAddTriangle(con, i1, i2, i3);
+}
+
+static jint
+nTriangleMeshCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshCreate, con(%p)", con);
+ 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(con, (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(con, (RsAdapter1D)adapter, (RsAllocation)alloc);
+}
+
+static void
+nAdapter1DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter1D)adapter, dim, value);
+ rsAdapter1DSetConstraint(con, (RsAdapter1D)adapter, (RsDimension)dim, value);
+}
+
+static void
+nAdapter1DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter1D)adapter, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter1D)adapter, offset, count, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter1D)adapter, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter1D)adapter, offset, count, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static jint
+nAdapter1DCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DCreate, con(%p)", con);
+ 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(con, (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(con, (RsAdapter2D)adapter, (RsAllocation)alloc);
+}
+
+static void
+nAdapter2DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter2DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter2D)adapter, dim, value);
+ rsAdapter2DSetConstraint(con, (RsAdapter2D)adapter, (RsDimension)dim, value);
+}
+
+static void
+nAdapter2DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter2D)adapter, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ 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(con, (RsAdapter2D)adapter, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ 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(con, (RsAdapter2D)adapter, xoff, yoff, w, h, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ 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(con, (RsAdapter1D)adapter, xoff, yoff, w, h, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static jint
+nAdapter2DCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter2DCreate, con(%p)", con);
+ 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(con, (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(con, (RsScript)script, (RsAllocation)alloc, slot);
+}
+
+static void
+nScriptSetClearColor(JNIEnv *_env, jobject _this, jint script, jfloat r, jfloat g, jfloat b, jfloat a)
+{
+ 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(con, (RsScript)script, r, g, b, a);
+}
+
+static void
+nScriptSetClearDepth(JNIEnv *_env, jobject _this, jint script, jfloat d)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearDepth, con(%p), s(%p), depth(%f)", con, script, d);
+ rsScriptSetClearDepth(con, (RsScript)script, d);
+}
+
+static void
+nScriptSetClearStencil(JNIEnv *_env, jobject _this, jint script, jint stencil)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearStencil, con(%p), s(%p), stencil(%i)", con, script, stencil);
+ rsScriptSetClearStencil(con, (RsScript)script, stencil);
+}
+
+static void
+nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetTimeZone, con(%p), s(%p), timeZone(%s)", con, script, timeZone);
+
+ jint length = _env->GetArrayLength(timeZone);
+ jbyte* timeZone_ptr;
+ timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
+
+ rsScriptSetTimeZone(con, (RsScript)script, (const char *)timeZone_ptr, length);
+
+ if (timeZone_ptr) {
+ _env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
+ }
+}
+
+static void
+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), writable(%i), slot(%i)", con, (RsType)type, writable, slot);
+ const char* n = NULL;
+ if (_str) {
+ n = _env->GetStringUTFChars(_str, NULL);
+ }
+ rsScriptSetType(con, (RsType)type, slot, writable, n);
+ if (n) {
+ _env->ReleaseStringUTFChars(_str, n);
+ }
+}
+
+static void
+nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot);
+ rsScriptSetRoot(con, isRoot);
+}
+
+// -----------------------------------
+
+static void
+nScriptCBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCBegin, con(%p)", con);
+ rsScriptCBegin(con);
+}
+
+static void
+nScriptCSetScript(JNIEnv *_env, jobject _this, jbyteArray scriptRef,
+ jint offset, jint length)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("!!! nScriptCSetScript, con(%p)", con);
+ jint _exception = 0;
+ jint remaining;
+ jbyte* script_base = 0;
+ jbyte* script_ptr;
+ if (!scriptRef) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "script == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ if (length < 0) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "length < 0");
+ goto exit;
+ }
+ remaining = _env->GetArrayLength(scriptRef) - offset;
+ if (remaining < length) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "length > script.length - offset");
+ goto exit;
+ }
+ script_base = (jbyte *)
+ _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
+ script_ptr = script_base + offset;
+
+ rsScriptCSetText(con, (const char *)script_ptr, length);
+
+exit:
+ if (script_base) {
+ _env->ReleasePrimitiveArrayCritical(scriptRef, script_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+static jint
+nScriptCCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCCreate, con(%p)", con);
+ return (jint)rsScriptCCreate(con);
+}
+
+static void
+nScriptCAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+ 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(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nScriptCAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+ 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(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramFragmentStoreBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramFragmentStoreBegin(con, (RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramFragmentStoreDepthFunc(JNIEnv *_env, jobject _this, jint func)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDepthFunc, con(%p), func(%i)", con, func);
+ rsProgramFragmentStoreDepthFunc(con, (RsDepthFunc)func);
+}
+
+static void
+nProgramFragmentStoreDepthMask(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDepthMask, con(%p), enable(%i)", con, enable);
+ rsProgramFragmentStoreDepthMask(con, enable);
+}
+
+static void
+nProgramFragmentStoreColorMask(JNIEnv *_env, jobject _this, jboolean r, jboolean g, jboolean b, jboolean a)
+{
+ 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(con, r, g, b, a);
+}
+
+static void
+nProgramFragmentStoreBlendFunc(JNIEnv *_env, jobject _this, int src, int dst)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst);
+ rsProgramFragmentStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
+}
+
+static void
+nProgramFragmentStoreDither(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDither, con(%p), enable(%i)", con, enable);
+ rsProgramFragmentStoreDither(con, enable);
+}
+
+static jint
+nProgramFragmentStoreCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreCreate, con(%p)", con);
+
+ return (jint)rsProgramFragmentStoreCreate(con);
+}
+
+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(con, (RsProgramFragmentStore)pgm);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramFragmentBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramFragmentBegin(con, (RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramFragmentBindTexture(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a)
+{
+ 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(con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
+}
+
+static void
+nProgramFragmentBindSampler(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a)
+{
+ 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(con, (RsProgramFragment)vpf, slot, (RsSampler)a);
+}
+
+static void
+nProgramFragmentSetType(JNIEnv *_env, jobject _this, jint slot, jint vt)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentSetType, con(%p), slot(%i), vt(%p)", con, slot, (RsType)vt);
+ rsProgramFragmentSetType(con, 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(con, 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(con, slot, enable);
+}
+
+static jint
+nProgramFragmentCreate(JNIEnv *_env, jobject _this, jint slot, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentCreate, con(%p)", con);
+ return (jint)rsProgramFragmentCreate(con);
+}
+
+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(con, (RsProgramFragment)pgm);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramVertexBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramVertexBegin(con, (RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramVertexBindAllocation(JNIEnv *_env, jobject _this, jint vpv, jint a)
+{
+ 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(con, (RsProgramFragment)vpv, (RsAllocation)a);
+}
+
+static void
+nProgramVertexSetTextureMatrixEnable(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexSetTextureMatrixEnable, con(%p), enable(%i)", con, enable);
+ rsProgramVertexSetTextureMatrixEnable(con, enable);
+}
+
+static void
+nProgramVertexAddLight(JNIEnv *_env, jobject _this, jint light)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexAddLight, con(%p), light(%p)", con, (RsLight)light);
+ rsProgramVertexAddLight(con, (RsLight)light);
+}
+
+static jint
+nProgramVertexCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexCreate, con(%p)", con);
+ 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(con, (RsProgramFragment)pgm);
+}
+
+
+
+
+// ---------------------------------------------------------------------------
+
+static void
+nContextBindRootScript(JNIEnv *_env, jobject _this, jint script)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindRootScript, con(%p), script(%p)", con, (RsScript)script);
+ rsContextBindRootScript(con, (RsScript)script);
+}
+
+static void
+nContextBindProgramFragmentStore(JNIEnv *_env, jobject _this, jint pfs)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramFragmentStore, con(%p), pfs(%p)", con, (RsProgramFragmentStore)pfs);
+ rsContextBindProgramFragmentStore(con, (RsProgramFragmentStore)pfs);
+}
+
+static void
+nContextBindProgramFragment(JNIEnv *_env, jobject _this, jint pf)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramFragment, con(%p), pf(%p)", con, (RsProgramFragment)pf);
+ rsContextBindProgramFragment(con, (RsProgramFragment)pf);
+}
+
+static void
+nContextBindProgramVertex(JNIEnv *_env, jobject _this, jint pf)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramVertex, con(%p), pf(%p)", con, (RsProgramVertex)pf);
+ rsContextBindProgramVertex(con, (RsProgramVertex)pf);
+}
+
+static void
+nContextAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+ 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(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nContextAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+ 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(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+
+// ---------------------------------------------------------------------------
+
+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(con, (RsSampler)s);
+}
+
+static void
+nSamplerBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerBegin, con(%p)", con);
+ rsSamplerBegin(con);
+}
+
+static void
+nSamplerSet(JNIEnv *_env, jobject _this, jint p, jint v)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerSet, con(%p), param(%i), value(%i)", con, p, v);
+ rsSamplerSet(con, (RsSamplerParam)p, (RsSamplerValue)v);
+}
+
+static jint
+nSamplerCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerCreate, con(%p)", con);
+ return (jint)rsSamplerCreate(con);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nLightBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightBegin, con(%p)", con);
+ rsLightBegin(con);
+}
+
+static void
+nLightSetIsMono(JNIEnv *_env, jobject _this, jboolean isMono)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetIsMono, con(%p), isMono(%i)", con, isMono);
+ rsLightSetMonochromatic(con, isMono);
+}
+
+static void
+nLightSetIsLocal(JNIEnv *_env, jobject _this, jboolean isLocal)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetIsLocal, con(%p), isLocal(%i)", con, isLocal);
+ rsLightSetLocal(con, isLocal);
+}
+
+static jint
+nLightCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightCreate, con(%p)", con);
+ return (jint)rsLightCreate(con);
+}
+
+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(con, (RsLight)light);
+}
+
+static void
+nLightSetColor(JNIEnv *_env, jobject _this, jint light, float r, float g, float b)
+{
+ 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(con, (RsLight)light, r, g, b);
+}
+
+static void
+nLightSetPosition(JNIEnv *_env, jobject _this, jint light, float x, float y, float z)
+{
+ 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(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(con, (RsSimpleMesh)s);
+}
+
+static jint
+nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(vtxIDs);
+ 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(con, (void *)batchID, (void *)indexID, (void **)ptr, len, primID);
+ _env->ReleaseIntArrayElements(vtxIDs, ptr, 0/*JNI_ABORT*/);
+ return id;
+}
+
+static void
+nSimpleMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
+{
+ 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(con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
+}
+
+static void
+nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc);
+ rsSimpleMeshBindIndex(con, (RsSimpleMesh)s, (RsAllocation)alloc);
+}
+
+// ---------------------------------------------------------------------------
+
+
+static const char *classPathName = "android/renderscript/RenderScript";
+
+static JNINativeMethod methods[] = {
+{"_nInit", "()V", (void*)_nInit },
+{"nDeviceCreate", "()I", (void*)nDeviceCreate },
+{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
+{"nContextCreate", "(ILandroid/view/Surface;I)I", (void*)nContextCreate },
+{"nContextDestroy", "(I)V", (void*)nContextDestroy },
+{"nAssignName", "(I[B)V", (void*)nAssignName },
+
+{"nFileOpen", "([B)I", (void*)nFileOpen },
+
+{"nElementBegin", "()V", (void*)nElementBegin },
+{"nElementAddPredefined", "(I)V", (void*)nElementAddPredefined },
+{"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 },
+
+{"nAllocationCreateTyped", "(I)I", (void*)nAllocationCreateTyped },
+{"nAllocationCreatePredefSized", "(II)I", (void*)nAllocationCreatePredefSized },
+{"nAllocationCreateSized", "(II)I", (void*)nAllocationCreateSized },
+{"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 },
+{"nAllocationSubData1D", "(III[F)V", (void*)nAllocationSubData1D_f },
+{"nAllocationSubData2D", "(IIIII[I)V", (void*)nAllocationSubData2D_i },
+{"nAllocationSubData2D", "(IIIII[F)V", (void*)nAllocationSubData2D_f },
+{"nAllocationRead", "(I[I)V", (void*)nAllocationRead_i },
+{"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 },
+{"nTriangleMeshAddVertex_XY_ST", "(FFFF)V", (void*)nTriangleMeshAddVertex_XY_ST },
+{"nTriangleMeshAddVertex_XYZ_ST", "(FFFFF)V", (void*)nTriangleMeshAddVertex_XYZ_ST },
+{"nTriangleMeshAddVertex_XYZ_ST_NORM", "(FFFFFFFF)V", (void*)nTriangleMeshAddVertex_XYZ_ST_NORM },
+{"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 },
+{"nAdapter1DData", "(I[F)V", (void*)nAdapter1DData_f },
+{"nAdapter1DSubData", "(III[I)V", (void*)nAdapter1DSubData_i },
+{"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 },
+{"nAdapter2DData", "(I[F)V", (void*)nAdapter2DData_f },
+{"nAdapter2DSubData", "(IIIII[I)V", (void*)nAdapter2DSubData_i },
+{"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", "(IZLjava/lang/String;I)V", (void*)nScriptSetType },
+{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot },
+
+{"nScriptCBegin", "()V", (void*)nScriptCBegin },
+{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript },
+{"nScriptCCreate", "()I", (void*)nScriptCCreate },
+{"nScriptCAddDefineI32", "(Ljava/lang/String;I)V", (void*)nScriptCAddDefineI32 },
+{"nScriptCAddDefineF", "(Ljava/lang/String;F)V", (void*)nScriptCAddDefineF },
+
+{"nProgramFragmentStoreBegin", "(II)V", (void*)nProgramFragmentStoreBegin },
+{"nProgramFragmentStoreDepthFunc", "(I)V", (void*)nProgramFragmentStoreDepthFunc },
+{"nProgramFragmentStoreDepthMask", "(Z)V", (void*)nProgramFragmentStoreDepthMask },
+{"nProgramFragmentStoreColorMask", "(ZZZZ)V", (void*)nProgramFragmentStoreColorMask },
+{"nProgramFragmentStoreBlendFunc", "(II)V", (void*)nProgramFragmentStoreBlendFunc },
+{"nProgramFragmentStoreDither", "(Z)V", (void*)nProgramFragmentStoreDither },
+{"nProgramFragmentStoreCreate", "()I", (void*)nProgramFragmentStoreCreate },
+{"nProgramFragmentStoreDestroy", "(I)V", (void*)nProgramFragmentStoreDestroy },
+
+{"nProgramFragmentBegin", "(II)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 },
+{"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 },
+{"nProgramVertexAddLight", "(I)V", (void*)nProgramVertexAddLight },
+{"nProgramVertexCreate", "()I", (void*)nProgramVertexCreate },
+
+{"nLightBegin", "()V", (void*)nLightBegin },
+{"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 },
+
+{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript },
+{"nContextBindProgramFragmentStore","(I)V", (void*)nContextBindProgramFragmentStore },
+{"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 },
+
+};
+
+static int registerFuncs(JNIEnv *_env)
+{
+ return android::AndroidRuntime::registerNativeMethods(
+ _env, classPathName, methods, NELEM(methods));
+}
+
+// ---------------------------------------------------------------------------
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("ERROR: GetEnv failed\n");
+ goto bail;
+ }
+ assert(env != NULL);
+
+ if (registerFuncs(env) < 0) {
+ LOGE("ERROR: MediaPlayer native registration failed\n");
+ goto bail;
+ }
+
+ /* success -- return valid version number */
+ result = JNI_VERSION_1_4;
+
+bail:
+ return result;
+}
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 78bef91..99ab2f0 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -20,7 +20,7 @@
#define _RUNTIME_ANDROID_RUNTIME_H
#include <utils/Errors.h>
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -98,6 +98,7 @@
private:
static int startReg(JNIEnv* env);
+ int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
Vector<JavaVMOption> mOptions;
diff --git a/include/binder/Binder.h b/include/binder/Binder.h
new file mode 100644
index 0000000..47b2bb9
--- /dev/null
+++ b/include/binder/Binder.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BINDER_H
+#define ANDROID_BINDER_H
+
+#include <binder/IBinder.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder : public IBinder
+{
+public:
+ BBinder();
+
+ virtual const String16& getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BBinder* localBinder();
+
+protected:
+ virtual ~BBinder();
+
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+private:
+ BBinder(const BBinder& o);
+ BBinder& operator=(const BBinder& o);
+
+ class Extras;
+
+ Extras* mExtras;
+ void* mReserved0;
+ static String16 sEmptyDescriptor;
+};
+
+// ---------------------------------------------------------------------------
+
+class BpRefBase : public virtual RefBase
+{
+protected:
+ BpRefBase(const sp<IBinder>& o);
+ virtual ~BpRefBase();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+ inline IBinder* remote() { return mRemote; }
+ inline IBinder* remote() const { return mRemote; }
+
+private:
+ BpRefBase(const BpRefBase& o);
+ BpRefBase& operator=(const BpRefBase& o);
+
+ IBinder* const mRemote;
+ RefBase::weakref_type* mRefs;
+ volatile int32_t mState;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BINDER_H
diff --git a/include/binder/BpBinder.h b/include/binder/BpBinder.h
new file mode 100644
index 0000000..7ef93aa
--- /dev/null
+++ b/include/binder/BpBinder.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_BPBINDER_H
+#define ANDROID_BPBINDER_H
+
+#include <binder/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BpBinder : public IBinder
+{
+public:
+ BpBinder(int32_t handle);
+
+ inline int32_t handle() const { return mHandle; }
+
+ virtual const String16& getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BpBinder* remoteBinder();
+
+ status_t setConstantData(const void* data, size_t size);
+ void sendObituary();
+
+ class ObjectManager
+ {
+ public:
+ ObjectManager();
+ ~ObjectManager();
+
+ void attach( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ IBinder::object_cleanup_func func);
+ void* find(const void* objectID) const;
+ void detach(const void* objectID);
+
+ void kill();
+
+ private:
+ ObjectManager(const ObjectManager&);
+ ObjectManager& operator=(const ObjectManager&);
+
+ struct entry_t
+ {
+ void* object;
+ void* cleanupCookie;
+ IBinder::object_cleanup_func func;
+ };
+
+ KeyedVector<const void*, entry_t> mObjects;
+ };
+
+protected:
+ virtual ~BpBinder();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+private:
+ const int32_t mHandle;
+
+ struct Obituary {
+ wp<DeathRecipient> recipient;
+ void* cookie;
+ uint32_t flags;
+ };
+
+ void reportOneDeath(const Obituary& obit);
+ bool isDescriptorCached() const;
+
+ mutable Mutex mLock;
+ volatile int32_t mAlive;
+ volatile int32_t mObitsSent;
+ Vector<Obituary>* mObituaries;
+ ObjectManager mObjects;
+ Parcel* mConstantData;
+ mutable String16 mDescriptorCache;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BPBINDER_H
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
new file mode 100644
index 0000000..884b5c1
--- /dev/null
+++ b/include/binder/IBinder.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IBINDER_H
+#define ANDROID_IBINDER_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder;
+class BpBinder;
+class IInterface;
+class Parcel;
+
+/**
+ * Base class and low-level protocol for a remotable object.
+ * You can derive from this class to create an object for which other
+ * processes can hold references to it. Communication between processes
+ * (method calls, property get and set) is down through a low-level
+ * protocol implemented on top of the transact() API.
+ */
+class IBinder : public virtual RefBase
+{
+public:
+ enum {
+ FIRST_CALL_TRANSACTION = 0x00000001,
+ LAST_CALL_TRANSACTION = 0x00ffffff,
+
+ PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
+ DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
+ INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
+
+ // Corresponds to tfOneWay -- an asynchronous call.
+ FLAG_ONEWAY = 0x00000001
+ };
+
+ IBinder();
+
+ /**
+ * Check if this IBinder implements the interface named by
+ * @a descriptor. If it does, the base pointer to it is returned,
+ * which you can safely static_cast<> to the concrete C++ interface.
+ */
+ virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
+
+ /**
+ * Return the canonical name of the interface provided by this IBinder
+ * object.
+ */
+ virtual const String16& getInterfaceDescriptor() const = 0;
+
+ virtual bool isBinderAlive() const = 0;
+ virtual status_t pingBinder() = 0;
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * This method allows you to add data that is transported through
+ * IPC along with your IBinder pointer. When implementing a Binder
+ * object, override it to write your desired data in to @a outData.
+ * You can then call getConstantData() on your IBinder to retrieve
+ * that data, from any process. You MUST return the number of bytes
+ * written in to the parcel (including padding).
+ */
+ class DeathRecipient : public virtual RefBase
+ {
+ public:
+ virtual void binderDied(const wp<IBinder>& who) = 0;
+ };
+
+ /**
+ * Register the @a recipient for a notification if this binder
+ * goes away. If this binder object unexpectedly goes away
+ * (typically because its hosting process has been killed),
+ * then DeathRecipient::binderDied() will be called with a referene
+ * to this.
+ *
+ * The @a cookie is optional -- if non-NULL, it should be a
+ * memory address that you own (that is, you know it is unique).
+ *
+ * @note You will only receive death notifications for remote binders,
+ * as local binders by definition can't die without you dying as well.
+ * Trying to use this function on a local binder will result in an
+ * INVALID_OPERATION code being returned and nothing happening.
+ *
+ * @note This link always holds a weak reference to its recipient.
+ *
+ * @note You will only receive a weak reference to the dead
+ * binder. You should not try to promote this to a strong reference.
+ * (Nor should you need to, as there is nothing useful you can
+ * directly do with it now that it has passed on.)
+ */
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * Remove a previously registered death notification.
+ * The @a recipient will no longer be called if this object
+ * dies. The @a cookie is optional. If non-NULL, you can
+ * supply a NULL @a recipient, and the recipient previously
+ * added with that cookie will be unlinked.
+ */
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL) = 0;
+
+ virtual bool checkSubclass(const void* subclassID) const;
+
+ typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func) = 0;
+ virtual void* findObject(const void* objectID) const = 0;
+ virtual void detachObject(const void* objectID) = 0;
+
+ virtual BBinder* localBinder();
+ virtual BpBinder* remoteBinder();
+
+protected:
+ virtual ~IBinder();
+
+private:
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IBINDER_H
diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h
new file mode 100644
index 0000000..273d922
--- /dev/null
+++ b/include/binder/IInterface.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_IINTERFACE_H
+#define ANDROID_IINTERFACE_H
+
+#include <binder/Binder.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IInterface : public virtual RefBase
+{
+public:
+ IInterface();
+ sp<IBinder> asBinder();
+ sp<const IBinder> asBinder() const;
+
+protected:
+ virtual ~IInterface();
+ virtual IBinder* onAsBinder() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
+{
+ return INTERFACE::asInterface(obj);
+}
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BnInterface : public INTERFACE, public BBinder
+{
+public:
+ virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
+ virtual const String16& getInterfaceDescriptor() const;
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BpInterface : public INTERFACE, public BpRefBase
+{
+public:
+ BpInterface(const sp<IBinder>& remote);
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_META_INTERFACE(INTERFACE) \
+ static const String16 descriptor; \
+ static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
+ virtual const String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
+ const String16 I##INTERFACE::descriptor(NAME); \
+ const String16& I##INTERFACE::getInterfaceDescriptor() const { \
+ return I##INTERFACE::descriptor; \
+ } \
+ sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
+ { \
+ sp<I##INTERFACE> intr; \
+ if (obj != NULL) { \
+ intr = static_cast<I##INTERFACE*>( \
+ obj->queryLocalInterface( \
+ I##INTERFACE::descriptor).get()); \
+ if (intr == NULL) { \
+ intr = new Bp##INTERFACE(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+ I##INTERFACE::I##INTERFACE() { } \
+ I##INTERFACE::~I##INTERFACE() { } \
+
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ if (!data.checkInterface(this)) { return PERMISSION_DENIED; } \
+
+
+// ----------------------------------------------------------------------
+// No user-serviceable parts after this...
+
+template<typename INTERFACE>
+inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
+ const String16& _descriptor)
+{
+ if (_descriptor == INTERFACE::descriptor) return this;
+ return NULL;
+}
+
+template<typename INTERFACE>
+inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
+{
+ return INTERFACE::getInterfaceDescriptor();
+}
+
+template<typename INTERFACE>
+IBinder* BnInterface<INTERFACE>::onAsBinder()
+{
+ return this;
+}
+
+template<typename INTERFACE>
+inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
+ : BpRefBase(remote)
+{
+}
+
+template<typename INTERFACE>
+inline IBinder* BpInterface<INTERFACE>::onAsBinder()
+{
+ return remote();
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IINTERFACE_H
diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h
new file mode 100644
index 0000000..ae042cb
--- /dev/null
+++ b/include/binder/IMemory.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_IMEMORY_H
+#define ANDROID_IMEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IMemoryHeap : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MemoryHeap);
+
+ // flags returned by getFlags()
+ enum {
+ READ_ONLY = 0x00000001,
+ MAP_ONCE = 0x00000002
+ };
+
+ virtual int getHeapID() const = 0;
+ virtual void* getBase() const = 0;
+ virtual size_t getSize() const = 0;
+ virtual uint32_t getFlags() const = 0;
+
+ // these are there just for backward source compatibility
+ int32_t heapID() const { return getHeapID(); }
+ void* base() const { return getBase(); }
+ size_t virtualSize() const { return getSize(); }
+};
+
+class BnMemoryHeap : public BnInterface<IMemoryHeap>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ BnMemoryHeap();
+protected:
+ virtual ~BnMemoryHeap();
+};
+
+// ----------------------------------------------------------------------------
+
+class IMemory : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Memory);
+
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+
+ // helpers
+ void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
+ void* pointer() const;
+ size_t size() const;
+ ssize_t offset() const;
+};
+
+class BnMemory : public BnInterface<IMemory>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ BnMemory();
+protected:
+ virtual ~BnMemory();
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IMEMORY_H
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
new file mode 100644
index 0000000..78306b2
--- /dev/null
+++ b/include/binder/IPCThreadState.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <utils/Vector.h>
+
+#ifdef HAVE_WIN32_PROC
+typedef int uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+ static IPCThreadState* self();
+
+ sp<ProcessState> process();
+
+ status_t clearLastError();
+
+ int getCallingPid();
+ int getCallingUid();
+
+ int64_t clearCallingIdentity();
+ void restoreCallingIdentity(int64_t token);
+
+ void flushCommands();
+
+ void joinThreadPool(bool isMain = true);
+
+ // Stop the local process.
+ void stopProcess(bool immediate = true);
+
+ status_t transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+
+ void incStrongHandle(int32_t handle);
+ void decStrongHandle(int32_t handle);
+ void incWeakHandle(int32_t handle);
+ void decWeakHandle(int32_t handle);
+ status_t attemptIncStrongHandle(int32_t handle);
+ static void expungeHandle(int32_t handle, IBinder* binder);
+ status_t requestDeathNotification( int32_t handle,
+ BpBinder* proxy);
+ status_t clearDeathNotification( int32_t handle,
+ BpBinder* proxy);
+
+ static void shutdown();
+
+private:
+ IPCThreadState();
+ ~IPCThreadState();
+
+ status_t sendReply(const Parcel& reply, uint32_t flags);
+ status_t waitForResponse(Parcel *reply,
+ status_t *acquireResult=NULL);
+ status_t talkWithDriver(bool doReceive=true);
+ status_t writeTransactionData(int32_t cmd,
+ uint32_t binderFlags,
+ int32_t handle,
+ uint32_t code,
+ const Parcel& data,
+ status_t* statusBuffer);
+ status_t executeCommand(int32_t command);
+
+ void clearCaller();
+
+ static void threadDestructor(void *st);
+ static void freeBuffer(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const sp<ProcessState> mProcess;
+ Vector<BBinder*> mPendingStrongDerefs;
+ Vector<RefBase::weakref_type*> mPendingWeakDerefs;
+
+ Parcel mIn;
+ Parcel mOut;
+ status_t mLastError;
+ pid_t mCallingPid;
+ uid_t mCallingUid;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
new file mode 100644
index 0000000..f9d371b
--- /dev/null
+++ b/include/binder/IPermissionController.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_IPERMISSION_CONTROLLER_H
+#define ANDROID_IPERMISSION_CONTROLLER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IPermissionController : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(PermissionController);
+
+ virtual bool checkPermission(const String16& permission,
+ int32_t pid, int32_t uid) = 0;
+
+ enum {
+ CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnPermissionController : public BnInterface<IPermissionController>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
new file mode 100644
index 0000000..24e9e99
--- /dev/null
+++ b/include/binder/IServiceManager.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_ISERVICE_MANAGER_H
+#define ANDROID_ISERVICE_MANAGER_H
+
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IServiceManager : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(ServiceManager);
+
+ /**
+ * Retrieve an existing service, blocking for a few seconds
+ * if it doesn't yet exist.
+ */
+ virtual sp<IBinder> getService( const String16& name) const = 0;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ virtual sp<IBinder> checkService( const String16& name) const = 0;
+
+ /**
+ * Register a service.
+ */
+ virtual status_t addService( const String16& name,
+ const sp<IBinder>& service) = 0;
+
+ /**
+ * Return list of all existing services.
+ */
+ virtual Vector<String16> listServices() = 0;
+
+ enum {
+ GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ CHECK_SERVICE_TRANSACTION,
+ ADD_SERVICE_TRANSACTION,
+ LIST_SERVICES_TRANSACTION,
+ };
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService)
+{
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ *outService = interface_cast<INTERFACE>(sm->getService(name));
+ if ((*outService) != NULL) return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+ int32_t* outPid, int32_t* outUid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+
+
+// ----------------------------------------------------------------------
+
+class BnServiceManager : public BnInterface<IServiceManager>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISERVICE_MANAGER_H
+
diff --git a/include/binder/MemoryBase.h b/include/binder/MemoryBase.h
new file mode 100644
index 0000000..463e26d
--- /dev/null
+++ b/include/binder/MemoryBase.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_BASE_H
+#define ANDROID_MEMORY_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryBase : public BnMemory
+{
+public:
+ MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~MemoryBase();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+
+protected:
+ size_t getSize() const { return mSize; }
+ ssize_t getOffset() const { return mOffset; }
+ const sp<IMemoryHeap>& getHeap() const { return mHeap; }
+
+private:
+ size_t mSize;
+ ssize_t mOffset;
+ sp<IMemoryHeap> mHeap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
new file mode 100644
index 0000000..03ac70a
--- /dev/null
+++ b/include/binder/MemoryDealer.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_MEMORY_DEALER_H
+#define ANDROID_MEMORY_DEALER_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IMemory.h>
+#include <utils/threads.h>
+#include <binder/MemoryHeapBase.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+class String8;
+
+/*
+ * interface for implementing a "heap". A heap basically provides
+ * the IMemoryHeap interface for cross-process sharing and the
+ * ability to map/unmap pages within the heap.
+ */
+class HeapInterface : public virtual BnMemoryHeap
+{
+public:
+ // all values must be page-aligned
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+
+ HeapInterface();
+protected:
+ virtual ~HeapInterface();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * interface for implementing an allocator. An allocator provides
+ * methods for allocating and freeing memory blocks and dumping
+ * its state.
+ */
+class AllocatorInterface : public RefBase
+{
+public:
+ enum {
+ PAGE_ALIGNED = 0x00000001
+ };
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
+ virtual status_t deallocate(size_t offset) = 0;
+ virtual size_t size() const = 0;
+ virtual void dump(const char* what, uint32_t flags = 0) const = 0;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const = 0;
+
+ AllocatorInterface();
+protected:
+ virtual ~AllocatorInterface();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * concrete implementation of HeapInterface on top of mmap()
+ */
+class SharedHeap : public HeapInterface, public MemoryHeapBase
+{
+public:
+ SharedHeap();
+ SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
+ virtual ~SharedHeap();
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * A simple templatized doubly linked-list implementation
+ */
+
+template <typename NODE>
+class LinkedList
+{
+ NODE* mFirst;
+ NODE* mLast;
+
+public:
+ LinkedList() : mFirst(0), mLast(0) { }
+ bool isEmpty() const { return mFirst == 0; }
+ NODE const* head() const { return mFirst; }
+ NODE* head() { return mFirst; }
+ NODE const* tail() const { return mLast; }
+ NODE* tail() { return mLast; }
+
+ void insertAfter(NODE* node, NODE* newNode) {
+ newNode->prev = node;
+ newNode->next = node->next;
+ if (node->next == 0) mLast = newNode;
+ else node->next->prev = newNode;
+ node->next = newNode;
+ }
+
+ void insertBefore(NODE* node, NODE* newNode) {
+ newNode->prev = node->prev;
+ newNode->next = node;
+ if (node->prev == 0) mFirst = newNode;
+ else node->prev->next = newNode;
+ node->prev = newNode;
+ }
+
+ void insertHead(NODE* newNode) {
+ if (mFirst == 0) {
+ mFirst = mLast = newNode;
+ newNode->prev = newNode->next = 0;
+ } else {
+ newNode->prev = 0;
+ newNode->next = mFirst;
+ mFirst->prev = newNode;
+ mFirst = newNode;
+ }
+ }
+
+ void insertTail(NODE* newNode) {
+ if (mLast == 0) {
+ insertHead(newNode);
+ } else {
+ newNode->prev = mLast;
+ newNode->next = 0;
+ mLast->next = newNode;
+ mLast = newNode;
+ }
+ }
+
+ NODE* remove(NODE* node) {
+ if (node->prev == 0) mFirst = node->next;
+ else node->prev->next = node->next;
+ if (node->next == 0) mLast = node->prev;
+ else node->next->prev = node->prev;
+ return node;
+ }
+};
+
+
+/*
+ * concrete implementation of AllocatorInterface using a simple
+ * best-fit allocation scheme
+ */
+class SimpleBestFitAllocator : public AllocatorInterface
+{
+public:
+
+ SimpleBestFitAllocator(size_t size);
+ virtual ~SimpleBestFitAllocator();
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0);
+ virtual status_t deallocate(size_t offset);
+ virtual size_t size() const;
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const;
+
+private:
+
+ struct chunk_t {
+ chunk_t(size_t start, size_t size)
+ : start(start), size(size), free(1), prev(0), next(0) {
+ }
+ size_t start;
+ size_t size : 28;
+ int free : 4;
+ mutable chunk_t* prev;
+ mutable chunk_t* next;
+ };
+
+ ssize_t alloc(size_t size, uint32_t flags);
+ chunk_t* dealloc(size_t start);
+ void dump_l(const char* what, uint32_t flags = 0) const;
+ void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
+
+ static const int kMemoryAlign;
+ mutable Mutex mLock;
+ LinkedList<chunk_t> mList;
+ size_t mHeapSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class MemoryDealer : public RefBase
+{
+public:
+
+ enum {
+ READ_ONLY = MemoryHeapBase::READ_ONLY,
+ PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
+ };
+
+ // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
+ MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
+
+ // provide a custom heap but use the SimpleBestFitAllocator
+ MemoryDealer(const sp<HeapInterface>& heap);
+
+ // provide both custom heap and allocotar
+ MemoryDealer(
+ const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator);
+
+ virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
+ virtual void deallocate(size_t offset);
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+
+
+ sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
+ sp<AllocatorInterface> getAllocator() const { return allocator(); }
+
+protected:
+ virtual ~MemoryDealer();
+
+private:
+ const sp<HeapInterface>& heap() const;
+ const sp<AllocatorInterface>& allocator() const;
+
+ class Allocation : public BnMemory {
+ public:
+ Allocation(const sp<MemoryDealer>& dealer,
+ ssize_t offset, size_t size, const sp<IMemory>& memory);
+ virtual ~Allocation();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+ private:
+ sp<MemoryDealer> mDealer;
+ ssize_t mOffset;
+ size_t mSize;
+ sp<IMemory> mMemory;
+ };
+
+ sp<HeapInterface> mHeap;
+ sp<AllocatorInterface> mAllocator;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
new file mode 100644
index 0000000..83c7283
--- /dev/null
+++ b/include/binder/MemoryHeapBase.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_BASE_H
+#define ANDROID_MEMORY_HEAP_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapBase : public virtual BnMemoryHeap
+{
+public:
+ enum {
+ READ_ONLY = IMemoryHeap::READ_ONLY,
+ MAP_ONCE = IMemoryHeap::MAP_ONCE,
+ // memory won't be mapped locally, but will be mapped in the remote
+ // process.
+ DONT_MAP_LOCALLY = 0x00000100
+ };
+
+ /*
+ * 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);
+
+ /*
+ * maps memory from the given device
+ */
+ MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
+
+ /*
+ * maps memory from ashmem, with the given name for debugging
+ */
+ MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
+
+ virtual ~MemoryHeapBase();
+
+ /* implement IMemoryHeap interface */
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+ const char* getDevice() const;
+
+ /* this closes this heap -- use carefully */
+ void dispose();
+
+ /* this is only needed as a workaround, use only if you know
+ * what you are doing */
+ status_t setDevice(const char* device) {
+ if (mDevice == 0)
+ mDevice = device;
+ return mDevice ? NO_ERROR : ALREADY_EXISTS;
+ }
+
+protected:
+ MemoryHeapBase();
+ // init() takes ownership of fd
+ status_t init(int fd, void *base, int size,
+ int flags = 0, const char* device = NULL);
+
+private:
+ status_t mapfd(int fd, size_t size);
+
+ int mFD;
+ size_t mSize;
+ void* mBase;
+ uint32_t mFlags;
+ const char* mDevice;
+ bool mNeedUnmap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/binder/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
new file mode 100644
index 0000000..dbf26ff
--- /dev/null
+++ b/include/binder/MemoryHeapPmem.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEMORY_HEAP_PMEM_H
+#define ANDROID_MEMORY_HEAP_PMEM_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IMemory.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+class MemoryHeapBase;
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
+{
+public:
+ class MemoryPmem : public BnMemory {
+ public:
+ MemoryPmem(const sp<MemoryHeapPmem>& heap);
+ ~MemoryPmem();
+ protected:
+ const sp<MemoryHeapPmem>& getHeap() const { return mClientHeap; }
+ private:
+ friend class MemoryHeapPmem;
+ virtual void revoke() = 0;
+ sp<MemoryHeapPmem> mClientHeap;
+ };
+
+ MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags = IMemoryHeap::MAP_ONCE);
+ ~MemoryHeapPmem();
+
+ /* HeapInterface additions */
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+
+ /* make the whole heap visible (you know who you are) */
+ virtual status_t slap();
+
+ /* hide (revoke) the whole heap (the client will see the garbage page) */
+ virtual status_t unslap();
+
+ /* revoke all allocations made by this heap */
+ virtual void revoke();
+
+private:
+ /* use this to create your own IMemory for mapMemory */
+ virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
+ void remove(const wp<MemoryPmem>& memory);
+
+private:
+ sp<MemoryHeapBase> mParentHeap;
+ mutable Mutex mLock;
+ SortedVector< wp<MemoryPmem> > mAllocations;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
new file mode 100644
index 0000000..ba6c711
--- /dev/null
+++ b/include/binder/Parcel.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_PARCEL_H
+#define ANDROID_PARCEL_H
+
+#include <cutils/native_handle.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IBinder;
+class ProcessState;
+class String8;
+class TextOutput;
+
+struct flat_binder_object; // defined in support_p/binder_module.h
+
+class Parcel
+{
+public:
+ Parcel();
+ ~Parcel();
+
+ const uint8_t* data() const;
+ size_t dataSize() const;
+ size_t dataAvail() const;
+ size_t dataPosition() const;
+ size_t dataCapacity() const;
+
+ status_t setDataSize(size_t size);
+ void setDataPosition(size_t pos) const;
+ status_t setDataCapacity(size_t size);
+
+ status_t setData(const uint8_t* buffer, size_t len);
+
+ status_t appendFrom(Parcel *parcel, size_t start, size_t len);
+
+ bool hasFileDescriptors() const;
+
+ status_t writeInterfaceToken(const String16& interface);
+ bool enforceInterface(const String16& interface) const;
+ bool checkInterface(IBinder*) const;
+
+ void freeData();
+
+ const size_t* objects() const;
+ size_t objectsCount() const;
+
+ status_t errorCheck() const;
+ void setError(status_t err);
+
+ status_t write(const void* data, size_t len);
+ void* writeInplace(size_t len);
+ status_t writeUnpadded(const void* data, size_t len);
+ status_t writeInt32(int32_t val);
+ 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);
+ status_t writeString16(const char16_t* str, size_t len);
+ status_t writeStrongBinder(const sp<IBinder>& val);
+ status_t writeWeakBinder(const wp<IBinder>& val);
+
+ // Place a native_handle into the parcel (the native_handle's file-
+ // descriptors are dup'ed, so it is safe to delete the native_handle
+ // when this function returns).
+ // Doesn't take ownership of the native_handle.
+ status_t writeNativeHandle(const native_handle* handle);
+
+ // Place a file descriptor into the parcel. The given fd must remain
+ // valid for the lifetime of the parcel.
+ status_t writeFileDescriptor(int fd);
+
+ // Place a file descriptor into the parcel. A dup of the fd is made, which
+ // will be closed once the parcel is destroyed.
+ status_t writeDupFileDescriptor(int fd);
+
+ status_t writeObject(const flat_binder_object& val, bool nullMetaData);
+
+ void remove(size_t start, size_t amt);
+
+ status_t read(void* outData, size_t len) const;
+ const void* readInplace(size_t len) const;
+ int32_t readInt32() const;
+ status_t readInt32(int32_t *pArg) const;
+ int64_t readInt64() const;
+ status_t readInt64(int64_t *pArg) const;
+ float readFloat() const;
+ 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;
+ String16 readString16() const;
+ const char16_t* readString16Inplace(size_t* outLen) const;
+ sp<IBinder> readStrongBinder() const;
+ wp<IBinder> readWeakBinder() const;
+
+
+ // Retrieve native_handle from the parcel. This returns a copy of the
+ // parcel's native_handle (the caller takes ownership). The caller
+ // must free the native_handle with native_handle_close() and
+ // native_handle_delete().
+ native_handle* readNativeHandle() const;
+
+
+ // Retrieve a file descriptor from the parcel. This returns the raw fd
+ // in the parcel, which you do not own -- use dup() to get your own copy.
+ int readFileDescriptor() const;
+
+ const flat_binder_object* readObject(bool nullMetaData) const;
+
+ // Explicitly close all file descriptors in the parcel.
+ void closeFileDescriptors();
+
+ typedef void (*release_func)(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const uint8_t* ipcData() const;
+ size_t ipcDataSize() const;
+ const size_t* ipcObjects() const;
+ size_t ipcObjectsCount() const;
+ void ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount,
+ release_func relFunc, void* relCookie);
+
+ void print(TextOutput& to, uint32_t flags = 0) const;
+
+private:
+ Parcel(const Parcel& o);
+ Parcel& operator=(const Parcel& o);
+
+ status_t finishWrite(size_t len);
+ void releaseObjects();
+ void acquireObjects();
+ status_t growData(size_t len);
+ status_t restartWrite(size_t desired);
+ status_t continueWrite(size_t desired);
+ void freeDataNoInit();
+ 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;
+ size_t mDataCapacity;
+ mutable size_t mDataPos;
+ size_t* mObjects;
+ size_t mObjectsSize;
+ size_t mObjectsCapacity;
+ mutable size_t mNextObjectHint;
+
+ mutable bool mFdsKnown;
+ mutable bool mHasFds;
+
+ release_func mOwner;
+ void* mOwnerCookie;
+};
+
+// ---------------------------------------------------------------------------
+
+inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
+{
+ parcel.print(to);
+ return to;
+}
+
+// ---------------------------------------------------------------------------
+
+// Generic acquire and release of objects.
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+
+void flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, flat_binder_object* out);
+void flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, flat_binder_object* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, sp<IBinder>* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, wp<IBinder>* out);
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PARCEL_H
diff --git a/include/binder/Permission.h b/include/binder/Permission.h
new file mode 100644
index 0000000..9542d50
--- /dev/null
+++ b/include/binder/Permission.h
@@ -0,0 +1,68 @@
+/*
+ * 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 BINDER_PERMISSION_H
+#define BINDER_PERMISSION_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <utils/SortedVector.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Permission caches the result of the permission check for the given
+ * permission name and the provided uid/pid. It also handles a few
+ * known cases efficiently (caller is in the same process or is root).
+ * The package manager does something similar but lives in dalvik world
+ * and is therefore extremely slow to access.
+ */
+
+class Permission
+{
+public:
+ Permission(char const* name);
+ Permission(const String16& name);
+ Permission(const Permission& rhs);
+ virtual ~Permission();
+
+ bool operator < (const Permission& rhs) const;
+
+ // checks the current binder call's caller has access to this permission
+ bool checkCalling() const;
+
+ // checks the specified pid/uid has access to this permission
+ bool check(pid_t pid, uid_t uid) const;
+
+protected:
+ virtual bool doCheckPermission(pid_t pid, uid_t uid) const;
+
+private:
+ Permission& operator = (const Permission& rhs) const;
+ const String16 mPermissionName;
+ mutable SortedVector<uid_t> mGranted;
+ const pid_t mPid;
+ mutable Mutex mLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* BINDER_PERMISSION_H */
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
new file mode 100644
index 0000000..feeb3c3
--- /dev/null
+++ b/include/binder/ProcessState.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_PROCESS_STATE_H
+#define ANDROID_PROCESS_STATE_H
+
+#include <binder/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+// Global variables
+extern int mArgC;
+extern const char* const* mArgV;
+extern int mArgLen;
+
+class IPCThreadState;
+
+class ProcessState : public virtual RefBase
+{
+public:
+ static sp<ProcessState> self();
+
+ static void setSingleProcess(bool singleProcess);
+
+ void setContextObject(const sp<IBinder>& object);
+ sp<IBinder> getContextObject(const sp<IBinder>& caller);
+
+ void setContextObject(const sp<IBinder>& object,
+ const String16& name);
+ sp<IBinder> getContextObject(const String16& name,
+ const sp<IBinder>& caller);
+
+ bool supportsProcesses() const;
+
+ void startThreadPool();
+
+ typedef bool (*context_check_func)(const String16& name,
+ const sp<IBinder>& caller,
+ void* userData);
+
+ bool isContextManager(void) const;
+ bool becomeContextManager(
+ context_check_func checkFunc,
+ void* userData);
+
+ sp<IBinder> getStrongProxyForHandle(int32_t handle);
+ wp<IBinder> getWeakProxyForHandle(int32_t handle);
+ void expungeHandle(int32_t handle, IBinder* binder);
+
+ void setArgs(int argc, const char* const argv[]);
+ int getArgC() const;
+ const char* const* getArgV() const;
+
+ void setArgV0(const char* txt);
+
+ void spawnPooledThread(bool isMain);
+
+private:
+ friend class IPCThreadState;
+
+ ProcessState();
+ ~ProcessState();
+
+ ProcessState(const ProcessState& o);
+ ProcessState& operator=(const ProcessState& o);
+
+ struct handle_entry {
+ IBinder* binder;
+ RefBase::weakref_type* refs;
+ };
+
+ handle_entry* lookupHandleLocked(int32_t handle);
+
+ int mDriverFD;
+ void* mVMStart;
+
+ mutable Mutex mLock; // protects everything below.
+
+ Vector<handle_entry>mHandleToObject;
+
+ bool mManagesContexts;
+ context_check_func mBinderContextCheckFunc;
+ void* mBinderContextUserData;
+
+ KeyedVector<String16, sp<IBinder> >
+ mContexts;
+
+
+ String8 mRootDir;
+ bool mThreadPoolStarted;
+ volatile int32_t mThreadPoolSeq;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 13e51ee..503cb31 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -26,8 +26,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
@@ -39,21 +39,10 @@
{
public:
- // input sources values must always be defined in the range
- // [AudioRecord::DEFAULT_INPUT, AudioRecord::NUM_INPUT_SOURCES[
- enum input_source {
- DEFAULT_INPUT =-1,
- MIC_INPUT = 0,
- VOICE_UPLINK_INPUT = 1,
- VOICE_DOWNLINK_INPUT = 2,
- VOICE_CALL_INPUT = 3,
- NUM_INPUT_SOURCES
- };
-
static const int DEFAULT_SAMPLE_RATE = 8000;
/* Events used by AudioRecord callback function (callback_t).
- *
+ *
* to keep in sync with frameworks/base/media/java/android/media/AudioRecord.java
*/
enum event_type {
@@ -61,7 +50,7 @@
EVENT_OVERRUN = 1, // PCM buffer overrun occured.
EVENT_MARKER = 2, // Record head is at the specified marker position
// (See setMarkerPosition()).
- EVENT_NEW_POS = 3, // Record head is at a new position
+ EVENT_NEW_POS = 3, // Record head is at a new position
// (See setPositionUpdatePeriod()).
};
@@ -123,11 +112,11 @@
*
* Parameters:
*
- * inputSource: Select the audio input to record to (e.g. AudioRecord::MIC_INPUT).
+ * inputSource: Select the audio input to record to (e.g. AUDIO_SOURCE_DEFAULT).
* sampleRate: Track sampling rate in Hz.
- * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
- * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * channels: Channel mask: see AudioSystem::audio_channels.
* frameCount: Total size of track PCM buffer in frames. This defines the
* latency of the track.
* flags: A bitmask of acoustic values from enum record_flags. It enables
@@ -148,7 +137,7 @@
AudioRecord(int inputSource,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -166,14 +155,14 @@
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful intialization
* - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
- * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* - PERMISSION_DENIED: recording is not allowed for the requesting process
* */
status_t set(int inputSource = 0,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -199,6 +188,7 @@
int format() const;
int channelCount() const;
+ int channels() const;
uint32_t frameCount() const;
int frameSize() const;
int inputSource() const;
@@ -222,8 +212,8 @@
/* Sets marker position. When record reaches the number of frames specified,
* a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
- * with marker == 0 cancels marker notification callback.
- * If the AudioRecord has been opened with no callback function associated,
+ * with marker == 0 cancels marker notification callback.
+ * If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
*
* Parameters:
@@ -238,10 +228,10 @@
status_t getMarkerPosition(uint32_t *marker);
- /* Sets position update period. Every time the number of frames specified has been recorded,
- * a callback with event type EVENT_NEW_POS is called.
- * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
- * callback.
+ /* Sets position update period. Every time the number of frames specified has been recorded,
+ * a callback with event type EVENT_NEW_POS is called.
+ * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+ * callback.
* If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
*
@@ -257,8 +247,8 @@
status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
- /* Gets record head position. The position is the total number of frames
- * recorded since record start.
+ /* Gets record head position. The position is the total number of frames
+ * recorded since record start.
*
* Parameters:
*
@@ -270,8 +260,16 @@
*/
status_t getPosition(uint32_t *position);
-
-
+ /* returns a handle on the audio input used by this AudioRecord.
+ *
+ * Parameters:
+ * none.
+ *
+ * Returned value:
+ * handle on audio hardware input
+ */
+ audio_io_handle_t getInput() { return mInput; }
+
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -342,6 +340,7 @@
bool mMarkerReached;
uint32_t mNewPosition;
uint32_t mUpdatePeriod;
+ audio_io_handle_t mInput;
};
}; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 3a3a714..1f726fe 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -24,36 +24,130 @@
namespace android {
typedef void (*audio_error_callback)(status_t err);
+typedef int audio_io_handle_t;
+
+class IAudioPolicyService;
+class String8;
class AudioSystem
{
public:
enum stream_type {
- DEFAULT =-1,
- VOICE_CALL = 0,
- SYSTEM = 1,
- RING = 2,
- MUSIC = 3,
- ALARM = 4,
- NOTIFICATION = 5,
- BLUETOOTH_SCO = 6,
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+ DTMF = 8,
+ TTS = 9,
NUM_STREAM_TYPES
};
- enum audio_output_type {
- AUDIO_OUTPUT_DEFAULT =-1,
- AUDIO_OUTPUT_HARDWARE = 0,
- AUDIO_OUTPUT_A2DP = 1,
- NUM_AUDIO_OUTPUT_TYPES
+ // Audio sub formats (see AudioSystem::audio_format).
+ enum pcm_sub_format {
+ PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
+ PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
};
+ // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
+ // bit rate, stereo mode, version...
+ enum mp3_sub_format {
+ //TODO
+ };
+
+ // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
+ // encoding mode for recording...
+ enum amr_sub_format {
+ //TODO
+ };
+
+ // AAC sub format field definition: specify profile or bitrate for recording...
+ enum aac_sub_format {
+ //TODO
+ };
+
+ // VORBIS sub format field definition: specify quality for recording...
+ enum vorbis_sub_format {
+ //TODO
+ };
+
+ // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
+ // The main format indicates the main codec type. The sub format field indicates options and parameters
+ // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
+ // or profile. It can also be used for certain formats to give informations not present in the encoded
+ // audio stream (e.g. octet alignement for AMR).
enum audio_format {
- FORMAT_DEFAULT = 0,
- PCM_16_BIT,
- PCM_8_BIT,
- INVALID_FORMAT
+ INVALID_FORMAT = -1,
+ FORMAT_DEFAULT = 0,
+ PCM = 0x00000000, // must be 0 for backward compatibility
+ MP3 = 0x01000000,
+ AMR_NB = 0x02000000,
+ AMR_WB = 0x03000000,
+ AAC = 0x04000000,
+ HE_AAC_V1 = 0x05000000,
+ HE_AAC_V2 = 0x06000000,
+ VORBIS = 0x07000000,
+ MAIN_FORMAT_MASK = 0xFF000000,
+ SUB_FORMAT_MASK = 0x00FFFFFF,
+ // Aliases
+ PCM_16_BIT = (PCM|PCM_SUB_16_BIT),
+ PCM_8_BIT = (PCM|PCM_SUB_8_BIT)
+ };
+
+
+ // Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
+ enum audio_channels {
+ // output channels
+ CHANNEL_OUT_FRONT_LEFT = 0x4,
+ CHANNEL_OUT_FRONT_RIGHT = 0x8,
+ CHANNEL_OUT_FRONT_CENTER = 0x10,
+ CHANNEL_OUT_LOW_FREQUENCY = 0x20,
+ CHANNEL_OUT_BACK_LEFT = 0x40,
+ CHANNEL_OUT_BACK_RIGHT = 0x80,
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
+ CHANNEL_OUT_BACK_CENTER = 0x400,
+ CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+ CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+ CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+ CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
+ CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
+
+ // input channels
+ CHANNEL_IN_LEFT = 0x4,
+ CHANNEL_IN_RIGHT = 0x8,
+ CHANNEL_IN_FRONT = 0x10,
+ CHANNEL_IN_BACK = 0x20,
+ CHANNEL_IN_LEFT_PROCESSED = 0x40,
+ CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+ CHANNEL_IN_FRONT_PROCESSED = 0x100,
+ CHANNEL_IN_BACK_PROCESSED = 0x200,
+ CHANNEL_IN_PRESSURE = 0x400,
+ CHANNEL_IN_X_AXIS = 0x800,
+ CHANNEL_IN_Y_AXIS = 0x1000,
+ CHANNEL_IN_Z_AXIS = 0x2000,
+ CHANNEL_IN_VOICE_UPLINK = 0x4000,
+ CHANNEL_IN_VOICE_DNLINK = 0x8000,
+ CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+ CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+ CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
+ CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
+ CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
};
enum audio_mode {
@@ -65,15 +159,6 @@
NUM_MODES // not a valid entry, denotes end-of-list
};
- enum audio_routes {
- ROUTE_EARPIECE = (1 << 0),
- ROUTE_SPEAKER = (1 << 1),
- ROUTE_BLUETOOTH_SCO = (1 << 2),
- ROUTE_HEADSET = (1 << 3),
- ROUTE_BLUETOOTH_A2DP = (1 << 4),
- ROUTE_ALL = -1UL,
- };
-
enum audio_in_acoustics {
AGC_ENABLE = 0x0001,
AGC_DISABLE = 0,
@@ -87,36 +172,37 @@
* only privileged processes can have access to them
*/
- // routing helper functions
- static status_t speakerphone(bool state);
- static status_t isSpeakerphoneOn(bool* state);
- static status_t bluetoothSco(bool state);
- static status_t isBluetoothScoOn(bool* state);
+ // mute/unmute microphone
static status_t muteMicrophone(bool state);
static status_t isMicrophoneMuted(bool *state);
+ // set/get master volume
static status_t setMasterVolume(float value);
- static status_t setMasterMute(bool mute);
static status_t getMasterVolume(float* volume);
+ // mute/unmute audio outputs
+ static status_t setMasterMute(bool mute);
static status_t getMasterMute(bool* mute);
- static status_t setStreamVolume(int stream, float value);
+ // set/get stream volume on specified output
+ static status_t setStreamVolume(int stream, float value, int output);
+ static status_t getStreamVolume(int stream, float* volume, int output);
+
+ // mute/unmute stream
static status_t setStreamMute(int stream, bool mute);
- static status_t getStreamVolume(int stream, float* volume);
static status_t getStreamMute(int stream, bool* mute);
+ // set audio mode in audio hardware (see AudioSystem::audio_mode)
static status_t setMode(int mode);
- static status_t getMode(int* mode);
- static status_t setRouting(int mode, uint32_t routes, uint32_t mask);
- static status_t getRouting(int mode, uint32_t* routes);
-
+ // returns true if tracks are active on AudioSystem::MUSIC stream
static status_t isMusicActive(bool *state);
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- static status_t setParameter(const char* key, const char* value);
-
+ // set/get audio hardware parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ static String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+
static void setErrorCallback(audio_error_callback cb);
// helper function to obtain AudioFlinger service handle
@@ -130,47 +216,247 @@
static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
static bool routedToA2dpOutput(int streamType);
-
- static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+
+ static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
size_t* buffSize);
+
+ //
+ // AudioPolicyService interface
+ //
+
+ enum audio_devices {
+ // output devices
+ DEVICE_OUT_EARPIECE = 0x1,
+ DEVICE_OUT_SPEAKER = 0x2,
+ DEVICE_OUT_WIRED_HEADSET = 0x4,
+ DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+ DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+ DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ DEVICE_OUT_AUX_DIGITAL = 0x400,
+ DEVICE_OUT_FM_HEADPHONE = 0x800,
+ DEVICE_OUT_FM_SPEAKER = 0x1000,
+ DEVICE_OUT_TTY = 0x2000,
+ DEVICE_OUT_DEFAULT = 0x8000,
+ DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+ DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_FM_HEADPHONE |
+ DEVICE_OUT_FM_SPEAKER | DEVICE_OUT_TTY | DEVICE_OUT_DEFAULT),
+
+ // input devices
+ DEVICE_IN_COMMUNICATION = 0x10000,
+ DEVICE_IN_AMBIENT = 0x20000,
+ DEVICE_IN_BUILTIN_MIC = 0x40000,
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+ DEVICE_IN_WIRED_HEADSET = 0x100000,
+ DEVICE_IN_AUX_DIGITAL = 0x200000,
+ DEVICE_IN_VOICE_CALL = 0x400000,
+ DEVICE_IN_DEFAULT = 0x80000000,
+
+ DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+ DEVICE_IN_VOICE_CALL| DEVICE_IN_DEFAULT)
+ };
+
+ // device connection states used for setDeviceConnectionState()
+ enum device_connection_state {
+ DEVICE_STATE_UNAVAILABLE,
+ DEVICE_STATE_AVAILABLE,
+ NUM_DEVICE_STATES
+ };
+
+ // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
+ enum output_flags {
+ OUTPUT_FLAG_INDIRECT = 0x0,
+ OUTPUT_FLAG_DIRECT = 0x1
+ };
+
+ // device categories used for setForceUse()
+ enum forced_config {
+ FORCE_NONE,
+ FORCE_SPEAKER,
+ FORCE_HEADPHONES,
+ FORCE_BT_SCO,
+ FORCE_BT_A2DP,
+ FORCE_WIRED_ACCESSORY,
+ NUM_FORCE_CONFIG,
+ FORCE_DEFAULT = FORCE_NONE
+ };
+
+ // usages used for setForceUse()
+ enum force_use {
+ FOR_COMMUNICATION,
+ FOR_MEDIA,
+ FOR_RECORD,
+ NUM_FORCE_USE
+ };
+
+ // types of io configuration change events received with ioConfigChanged()
+ enum io_config_event {
+ OUTPUT_OPENED,
+ OUTPUT_CLOSED,
+ OUTPUT_CONFIG_CHANGED,
+ INPUT_OPENED,
+ INPUT_CLOSED,
+ INPUT_CONFIG_CHANGED,
+ STREAM_CONFIG_CHANGED,
+ NUM_CONFIG_EVENTS
+ };
+
+ // audio output descritor used to cache output configurations in client process to avoid frequent calls
+ // through IAudioFlinger
+ class OutputDescriptor {
+ public:
+ OutputDescriptor()
+ : samplingRate(0), format(0), channels(0), frameCount(0), latency(0) {}
+
+ uint32_t samplingRate;
+ int32_t format;
+ int32_t channels;
+ size_t frameCount;
+ uint32_t latency;
+ };
+
+ //
+ // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+ //
+ static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address);
+ static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address);
+ static status_t setPhoneState(int state);
+ static status_t setRingerMode(uint32_t mode, uint32_t mask);
+ static status_t setForceUse(force_use usage, forced_config config);
+ static forced_config getForceUse(force_use usage);
+ static audio_io_handle_t getOutput(stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = FORMAT_DEFAULT,
+ uint32_t channels = CHANNEL_OUT_STEREO,
+ output_flags flags = OUTPUT_FLAG_INDIRECT);
+ static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ static void releaseOutput(audio_io_handle_t output);
+ static audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = FORMAT_DEFAULT,
+ uint32_t channels = CHANNEL_IN_MONO,
+ audio_in_acoustics acoustics = (audio_in_acoustics)0);
+ static status_t startInput(audio_io_handle_t input);
+ static status_t stopInput(audio_io_handle_t input);
+ static void releaseInput(audio_io_handle_t input);
+ static status_t initStreamVolume(stream_type stream,
+ int indexMin,
+ int indexMax);
+ static status_t setStreamVolumeIndex(stream_type stream, int index);
+ static status_t getStreamVolumeIndex(stream_type stream, int *index);
+
+ static const sp<IAudioPolicyService>& get_audio_policy_service();
+
// ----------------------------------------------------------------------------
+ static uint32_t popCount(uint32_t u);
+ static bool isOutputDevice(audio_devices device);
+ static bool isInputDevice(audio_devices device);
+ static bool isA2dpDevice(audio_devices device);
+ static bool isBluetoothScoDevice(audio_devices device);
+ static bool isLowVisibility(stream_type stream);
+ static bool isOutputChannel(uint32_t channel);
+ static bool isInputChannel(uint32_t channel);
+ static bool isValidFormat(uint32_t format);
+ static bool isLinearPCM(uint32_t format);
+
private:
class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
{
public:
- AudioFlingerClient() {
+ AudioFlingerClient() {
}
-
+
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
-
+
// IAudioFlingerClient
- virtual void a2dpEnabledChanged(bool enabled);
-
+
+ // indicate a change in the configuration of an output or input: keeps the cached
+ // values for output/input parameters upto date in client process
+ virtual void ioConfigChanged(int event, int ioHandle, void *param2);
};
- static int getOutput(int streamType);
+
+ class AudioPolicyServiceClient: public IBinder::DeathRecipient
+ {
+ public:
+ AudioPolicyServiceClient() {
+ }
+
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+ };
static sp<AudioFlingerClient> gAudioFlingerClient;
-
+ static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
friend class AudioFlingerClient;
+ friend class AudioPolicyServiceClient;
static Mutex gLock;
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
- static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
- static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
- static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
- static bool gA2dpEnabled;
-
+
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
static uint32_t gPrevInSamplingRate;
static int gPrevInFormat;
static int gPrevInChannelCount;
+ static sp<IAudioPolicyService> gAudioPolicyService;
+
+ // mapping between stream types and outputs
+ static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+ // list of output descritor containing cached parameters (sampling rate, framecount, channel count...)
+ static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
+};
+
+class AudioParameter {
+
+public:
+ AudioParameter() {}
+ AudioParameter(const String8& keyValuePairs);
+ virtual ~AudioParameter();
+
+ // reserved parameter keys for changeing standard parameters with setParameters() function.
+ // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
+ // configuration changes and act accordingly.
+ // keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices
+ // keySamplingRate: to change sampling rate routing, value is an int
+ // keyFormat: to change audio format, value is an int in AudioSystem::audio_format
+ // keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels
+ // keyFrameCount: to change audio output frame count, value is an int
+ static const char *keyRouting;
+ static const char *keySamplingRate;
+ static const char *keyFormat;
+ static const char *keyChannels;
+ static const char *keyFrameCount;
+
+ String8 toString();
+
+ status_t add(const String8& key, const String8& value);
+ status_t addInt(const String8& key, const int value);
+ status_t addFloat(const String8& key, const float value);
+
+ status_t remove(const String8& key);
+
+ status_t get(const String8& key, String8& value);
+ status_t getInt(const String8& key, int& value);
+ status_t getFloat(const String8& key, float& value);
+
+ size_t size() { return mParameters.size(); }
+
+private:
+ String8 mKeyValuePairs;
+ KeyedVector <String8, String8> mParameters;
};
}; // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7c86a65..981c2f6 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -26,8 +26,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
@@ -117,9 +117,9 @@
* streamType: Select the type of audio stream this track is attached to
* (e.g. AudioSystem::MUSIC).
* sampleRate: Track sampling rate in Hz.
- * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
- * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * channels: Channel mask: see AudioSystem::audio_channels.
* frameCount: Total size of track PCM buffer in frames. This defines the
* latency of the track.
* flags: Reserved for future use.
@@ -133,7 +133,7 @@
AudioTrack( int streamType,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -152,7 +152,7 @@
AudioTrack( int streamType,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
const sp<IMemory>& sharedBuffer = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -169,13 +169,13 @@
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful intialization
* - INVALID_OPERATION: AudioTrack is already intitialized
- * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* */
status_t set(int streamType =-1,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -330,6 +330,16 @@
*/
status_t reload();
+ /* returns a handle on the audio output used by this AudioTrack.
+ *
+ * Parameters:
+ * none.
+ *
+ * Returned value:
+ * handle on audio hardware output
+ */
+ audio_io_handle_t getOutput();
+
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -387,7 +397,6 @@
sp<AudioTrackThread> mAudioTrackThread;
float mVolume[2];
- uint32_t mSampleRate;
uint32_t mFrameCount;
audio_track_cblk_t* mCblk;
@@ -395,6 +404,7 @@
uint8_t mFormat;
uint8_t mChannelCount;
uint8_t mMuted;
+ uint32_t mChannels;
status_t mStatus;
uint32_t mLatency;
@@ -410,6 +420,7 @@
bool mMarkerReached;
uint32_t mNewPosition;
uint32_t mUpdatePeriod;
+ uint32_t mFlags;
};
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 3e59d85..8018568 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -23,11 +23,11 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h>
-
+#include <utils/String8.h>
namespace android {
@@ -50,11 +50,12 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status) = 0;
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -83,19 +84,14 @@
/* set/get stream type state. This will probably be used by
* the preference panel, mostly.
*/
- virtual status_t setStreamVolume(int stream, float value) = 0;
+ virtual status_t setStreamVolume(int stream, float value, int output) = 0;
virtual status_t setStreamMute(int stream, bool muted) = 0;
- virtual float streamVolume(int stream) const = 0;
+ virtual float streamVolume(int stream, int output) const = 0;
virtual bool streamMute(int stream) const = 0;
- // set/get audio routing
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask) = 0;
- virtual uint32_t getRouting(int mode) const = 0;
-
- // set/get audio mode
+ // set audio mode
virtual status_t setMode(int mode) = 0;
- virtual int getMode() const = 0;
// mic mute/state
virtual status_t setMicMute(bool state) = 0;
@@ -104,22 +100,34 @@
// is a music stream active?
virtual bool isMusicActive() const = 0;
- // pass a generic configuration parameter to libaudio
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- virtual status_t setParameter(const char* key, const char* value) = 0;
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(int ioHandle, const String8& keys) = 0;
// register a current process for audio output change notifications
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
// retrieve the audio recording buffer size
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
-
- // force AudioFlinger thread out of standby
- virtual void wakeUp() = 0;
- // is A2DP output enabled
- virtual bool isA2dpEnabled() const = 0;
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags) = 0;
+ virtual int openDuplicateOutput(int output1, int output2) = 0;
+ virtual status_t closeOutput(int output) = 0;
+ virtual status_t suspendOutput(int output) = 0;
+ virtual status_t restoreOutput(int output) = 0;
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics) = 0;
+ virtual status_t closeInput(int input) = 0;
+
+ virtual status_t setStreamOutput(uint32_t stream, int output) = 0;
};
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index c3deb0b..aa0cdcf 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -19,8 +19,8 @@
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-
+#include <binder/IInterface.h>
+#include <utils/KeyedVector.h>
namespace android {
@@ -31,8 +31,8 @@
public:
DECLARE_META_INTERFACE(AudioFlingerClient);
- // Notifies a change of audio output from/to hardware to/from A2DP.
- virtual void a2dpEnabledChanged(bool enabled) = 0;
+ // Notifies a change of audio input/output configuration.
+ virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
};
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
new file mode 100644
index 0000000..4804bbd
--- /dev/null
+++ b/include/media/IAudioPolicyService.h
@@ -0,0 +1,90 @@
+/*
+ * 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 ANDROID_IAUDIOPOLICYSERVICE_H
+#define ANDROID_IAUDIOPOLICYSERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <media/AudioSystem.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioPolicyService : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioPolicyService);
+
+ //
+ // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+ //
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address) = 0;
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address) = 0;
+ virtual status_t setPhoneState(int state) = 0;
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask) = 0;
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+ virtual void releaseOutput(audio_io_handle_t output) = 0;
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0) = 0;
+ virtual status_t startInput(audio_io_handle_t input) = 0;
+ virtual status_t stopInput(audio_io_handle_t input) = 0;
+ virtual void releaseInput(audio_io_handle_t input) = 0;
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax) = 0;
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0;
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioPolicyService : public BnInterface<IAudioPolicyService>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOPOLICYSERVICE_H
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 9d45d2d..46735de 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -22,8 +22,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 12f2111..de6426a 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -22,8 +22,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index c677e83..9baba8e 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -19,9 +19,9 @@
#define ANDROID_IMEDIAMETADATARETRIEVER_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index a683e74..b6f654f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -18,11 +18,12 @@
#define ANDROID_IMEDIAPLAYER_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
namespace android {
+class Parcel;
class ISurface;
class IMediaPlayer: public IInterface
@@ -45,6 +46,36 @@
virtual status_t setAudioStreamType(int type) = 0;
virtual status_t setLooping(int loop) = 0;
virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
+
+ // Invoke a generic method on the player by using opaque parcels
+ // for the request and reply.
+ // @param request Parcel that must start with the media player
+ // interface token.
+ // @param[out] reply Parcel to hold the reply data. Cannot be null.
+ // @return OK if the invocation was made successfully.
+ virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+
+ // Set a new metadata filter.
+ // @param filter A set of allow and drop rules serialized in a Parcel.
+ // @return OK if the invocation was made successfully.
+ virtual status_t setMetadataFilter(const Parcel& filter) = 0;
+
+ // Retrieve a set of metadata.
+ // @param update_only Include only the metadata that have changed
+ // since the last invocation of getMetadata.
+ // The set is built using the unfiltered
+ // notifications the native player sent to the
+ // MediaPlayerService during that period of
+ // time. If false, all the metadatas are considered.
+ // @param apply_filter If true, once the metadata set has been built based
+ // on the value update_only, the current filter is
+ // applied.
+ // @param[out] metadata On exit contains a set (possibly empty) of metadata.
+ // Valid only if the call returned OK.
+ // @return OK if the invocation was made successfully.
+ virtual status_t getMetadata(bool update_only,
+ bool apply_filter,
+ Parcel *metadata) = 0;
};
// ----------------------------------------------------------------------------
@@ -61,4 +92,3 @@
}; // namespace android
#endif // ANDROID_IMEDIAPLAYER_H
-
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index 5d32811..eee6c97 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -18,8 +18,8 @@
#define ANDROID_IMEDIAPLAYERCLIENT_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
namespace android {
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index d1d96b1..39b5e57 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -17,9 +17,10 @@
#ifndef ANDROID_IMEDIAPLAYERSERVICE_H
#define ANDROID_IMEDIAPLAYERSERVICE_H
+#include <utils/Errors.h> // for status_t
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
@@ -28,6 +29,7 @@
namespace android {
class IMediaRecorder;
+class IOMX;
class IMediaPlayerService: public IInterface
{
@@ -36,11 +38,11 @@
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
-
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+ virtual sp<IOMX> createOMX() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 64d3a40..24ac82b 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IMEDIARECORDER_H
#define ANDROID_IMEDIARECORDER_H
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
new file mode 100644
index 0000000..58a74c7
--- /dev/null
+++ b/include/media/IOMX.h
@@ -0,0 +1,204 @@
+/*
+ * 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 ANDROID_IOMX_H_
+
+#define ANDROID_IOMX_H_
+
+#include <binder/IInterface.h>
+#include <utils/List.h>
+#include <utils/String8.h>
+
+#include <OMX_Core.h>
+#include <OMX_Video.h>
+
+namespace android {
+
+class IMemory;
+class IOMXObserver;
+class IOMXRenderer;
+class ISurface;
+class Surface;
+
+class IOMX : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMX);
+
+ typedef void *buffer_id;
+ typedef void *node_id;
+
+ virtual status_t list_nodes(List<String8> *list) = 0;
+
+ virtual status_t allocate_node(const char *name, node_id *node) = 0;
+ virtual status_t free_node(node_id node) = 0;
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = 0;
+
+ virtual status_t get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) = 0;
+
+ virtual status_t set_parameter(
+ 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;
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) = 0;
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer) = 0;
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer) = 0;
+
+ virtual void fill_buffer(node_id node, buffer_id buffer) = 0;
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ 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,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) = 0;
+
+ // Note: This method is _not_ virtual, it exists as a wrapper around
+ // the virtual "createRenderer" method above facilitating extraction
+ // of the ISurface from a regular Surface.
+ sp<IOMXRenderer> createRenderer(
+ const sp<Surface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight);
+};
+
+struct omx_message {
+ enum {
+ EVENT,
+ EMPTY_BUFFER_DONE,
+ FILL_BUFFER_DONE,
+
+ // reserved for OMXDecoder use.
+ START,
+ INITIAL_FILL_BUFFER,
+
+ // reserved for OMXObserver use.
+ QUIT_OBSERVER,
+ } type;
+
+ IOMX::node_id node;
+
+ union {
+ // if type == EVENT
+ struct {
+ OMX_EVENTTYPE event;
+ OMX_U32 data1;
+ OMX_U32 data2;
+ } event_data;
+
+ // if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER
+ // || type == INITIAL_FILL_BUFFER
+ struct {
+ IOMX::buffer_id buffer;
+ } buffer_data;
+
+ // if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE
+ struct {
+ IOMX::buffer_id buffer;
+ OMX_U32 range_offset;
+ OMX_U32 range_length;
+ OMX_U32 flags;
+ OMX_TICKS timestamp;
+ OMX_PTR platform_private; // ignored if type == EMPTY_BUFFER
+ } extended_buffer_data;
+
+ // if type == SEND_COMMAND
+ struct {
+ OMX_COMMANDTYPE cmd;
+ OMX_S32 param;
+ } send_command_data;
+
+ } u;
+};
+
+class IOMXObserver : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMXObserver);
+
+ virtual void on_message(const omx_message &msg) = 0;
+};
+
+class IOMXRenderer : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMXRenderer);
+
+ virtual void render(IOMX::buffer_id buffer) = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BnOMX : public BnInterface<IOMX> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+class BnOMXObserver : public BnInterface<IOMXObserver> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+class BnOMXRenderer : public BnInterface<IOMXRenderer> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IOMX_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7bf555a..f723cfd 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -19,20 +19,32 @@
#ifdef __cplusplus
+#include <sys/types.h>
#include <ui/ISurface.h>
#include <utils/RefBase.h>
+#include <utils/Errors.h>
#include <media/mediaplayer.h>
#include <media/AudioSystem.h>
+#include <media/Metadata.h>
namespace android {
+class Parcel;
+template<typename T> class SortedVector;
+
enum player_type {
PV_PLAYER = 1,
SONIVOX_PLAYER = 2,
- VORBIS_PLAYER = 3
+ VORBIS_PLAYER = 3,
+ STAGEFRIGHT_PLAYER = 4,
+ // Test players are available only in the 'test' and 'eng' builds.
+ // The shared library with the test player is passed passed as an
+ // argument to the 'test:' url in the setDataSource call.
+ TEST_PLAYER = 5,
};
+
#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -45,10 +57,12 @@
class MediaPlayerBase : public RefBase
{
public:
-
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
public:
+ typedef void (*AudioCallback)(
+ AudioSink *audioSink, void *buffer, size_t size, void *cookie);
+
virtual ~AudioSink() {}
virtual bool ready() const = 0; // audio output is open and ready
virtual bool realtime() const = 0; // audio output is real-time output
@@ -58,7 +72,17 @@
virtual ssize_t frameSize() const = 0;
virtual uint32_t latency() const = 0;
virtual float msecsPerFrame() const = 0;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format=AudioSystem::PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
+
+ // If no callback is specified, use the "write" API below to submit
+ // audio data. Otherwise return a full buffer of audio data on each
+ // callback.
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount,
+ int format=AudioSystem::PCM_16_BIT,
+ int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ AudioCallback cb = NULL,
+ void *cookie = NULL) = 0;
+
virtual void start() = 0;
virtual ssize_t write(const void* buffer, size_t size) = 0;
virtual void stop() = 0;
@@ -88,6 +112,26 @@
virtual player_type playerType() = 0;
virtual void setNotifyCallback(void* cookie, notify_callback_f notifyFunc) {
mCookie = cookie; mNotify = notifyFunc; }
+ // Invoke a generic method on the player by using opaque parcels
+ // for the request and reply.
+ //
+ // @param request Parcel that is positioned at the start of the
+ // data sent by the java layer.
+ // @param[out] reply Parcel to hold the reply data. Cannot be null.
+ // @return OK if the call was successful.
+ virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+
+ // The Client in the MetadataPlayerService calls this method on
+ // the native player to retrieve all or a subset of metadata.
+ //
+ // @param ids SortedList of metadata ID to be fetch. If empty, all
+ // the known metadata should be returned.
+ // @param[inout] records Parcel where the player appends its metadata.
+ // @return OK if the call was successful.
+ virtual status_t getMetadata(const media::Metadata::Filter& ids,
+ Parcel *records) {
+ return INVALID_OPERATION;
+ };
protected:
virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
new file mode 100644
index 0000000..241868a
--- /dev/null
+++ b/include/media/Metadata.h
@@ -0,0 +1,133 @@
+/*
+ * 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 ANDROID_MEDIA_METADATA_H__
+#define ANDROID_MEDIA_METADATA_H__
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+class Parcel;
+
+namespace media {
+
+// Metadata is a class to build/serialize a set of metadata in a Parcel.
+//
+// This class should be kept in sync with android/media/Metadata.java.
+// It provides all the metadata ids available and methods to build the
+// header, add records and adjust the set size header field.
+//
+// Typical Usage:
+// ==============
+// Parcel p;
+// media::Metadata data(&p);
+//
+// data.appendHeader();
+// data.appendBool(Metadata::kPauseAvailable, true);
+// ... more append ...
+// data.updateLength();
+//
+
+class Metadata {
+ public:
+ typedef int32_t Type;
+ typedef SortedVector<Type> Filter;
+
+ static const Type kAny = 0;
+
+ // Keep in sync with android/media/Metadata.java
+ static const Type kTitle = 1; // String
+ static const Type kComment = 2; // String
+ static const Type kCopyright = 3; // String
+ static const Type kAlbum = 4; // String
+ static const Type kArtist = 5; // String
+ static const Type kAuthor = 6; // String
+ static const Type kComposer = 7; // String
+ static const Type kGenre = 8; // String
+ static const Type kDate = 9; // Date
+ static const Type kDuration = 10; // Integer(millisec)
+ static const Type kCdTrackNum = 11; // Integer 1-based
+ static const Type kCdTrackMax = 12; // Integer
+ static const Type kRating = 13; // String
+ static const Type kAlbumArt = 14; // byte[]
+ static const Type kVideoFrame = 15; // Bitmap
+ static const Type kCaption = 16; // TimedText
+
+ static const Type kBitRate = 17; // Integer, Aggregate rate of
+ // all the streams in bps.
+
+ static const Type kAudioBitRate = 18; // Integer, bps
+ static const Type kVideoBitRate = 19; // Integer, bps
+ static const Type kAudioSampleRate = 20; // Integer, Hz
+ static const Type kVideoframeRate = 21; // Integer, Hz
+
+ // See RFC2046 and RFC4281.
+ static const Type kMimeType = 22; // String
+ static const Type kAudioCodec = 23; // String
+ static const Type kVideoCodec = 24; // String
+
+ static const Type kVideoHeight = 25; // Integer
+ static const Type kVideoWidth = 26; // Integer
+ static const Type kNumTracks = 27; // Integer
+ static const Type kDrmCrippled = 28; // Boolean
+
+ // Playback capabilities.
+ static const Type kPauseAvailable = 29; // Boolean
+ static const Type kSeekBackwardAvailable = 30; // Boolean
+ static const Type kSeekForwardAvailable = 31; // Boolean
+
+ // @param p[inout] The parcel to append the metadata records
+ // to. The global metadata header should have been set already.
+ explicit Metadata(Parcel *p);
+ ~Metadata();
+
+ // Rewind the underlying parcel, undoing all the changes.
+ void resetParcel();
+
+ // Append the size and 'META' marker.
+ bool appendHeader();
+
+ // Once all the records have been added, call this to update the
+ // lenght field in the header.
+ void updateLength();
+
+ // append* are methods to append metadata.
+ // @param key Is the metadata Id.
+ // @param val Is the value of the metadata.
+ // @return true if successful, false otherwise.
+ // TODO: add more as needed to handle other types.
+ bool appendBool(Type key, bool val);
+ bool appendInt32(Type key, int32_t val);
+
+ private:
+ Metadata(const Metadata&);
+ Metadata& operator=(const Metadata&);
+
+
+ // Checks the key is valid and not already present.
+ bool checkKey(Type key);
+
+ Parcel *mData;
+ size_t mBegin;
+};
+
+} // namespace android::media
+} // namespace android
+
+#endif // ANDROID_MEDIA_METADATA_H__
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 8122df6..8a66152 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
#include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
#define MAX_OPENCORE_INSTANCES 25
@@ -52,6 +53,10 @@
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return PV_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t getMetadata(
+ const SortedVector<media::Metadata::Type>& ids,
+ Parcel *records);
// make available to PlayerDriver
void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
@@ -62,6 +67,7 @@
static void run_set_video_surface(status_t s, void *cookie, bool cancelled);
static void run_set_audio_output(status_t s, void *cookie, bool cancelled);
static void run_prepare(status_t s, void *cookie, bool cancelled);
+ static void check_for_live_streaming(status_t s, void *cookie, bool cancelled);
PlayerDriver* mPlayerDriver;
char * mDataSourcePath;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index f2719d3..9ea2775 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -20,7 +20,7 @@
#include <utils/Errors.h> // for status_t
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <media/IMediaMetadataRetriever.h>
namespace android {
@@ -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/mediaplayer.h b/include/media/mediaplayer.h
index 513ffe1..26b054bd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_MEDIAPLAYER_H
#define ANDROID_MEDIAPLAYER_H
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
@@ -97,6 +97,8 @@
MEDIA_INFO_BAD_INTERLEAVING = 800,
// The media is not seekable (e.g live stream).
MEDIA_INFO_NOT_SEEKABLE = 801,
+ // New media metadata is available.
+ MEDIA_INFO_METADATA_UPDATE = 802,
};
@@ -151,7 +153,9 @@
void notify(int msg, int ext1, int ext2);
static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-
+ status_t invoke(const Parcel& request, Parcel *reply);
+ status_t setMetadataFilter(const Parcel& filter);
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
private:
void clear_l();
status_t seekTo_l(int msec);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 9b54ca9..13316a9 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -18,7 +18,10 @@
#ifndef ANDROID_MEDIARECORDER_H
#define ANDROID_MEDIARECORDER_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <media/IMediaPlayerClient.h>
namespace android {
@@ -90,10 +93,6 @@
VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
};
-
-// Maximum frames per second is 24
-#define MEDIA_RECORDER_MAX_FRAME_RATE 24
-
/*
* The state machine of the media_recorder uses a set of different state names.
* The mapping between the media_recorder and the pvauthorengine is shown below:
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index fbef1db..7749566 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -17,7 +17,10 @@
#ifndef MEDIASCANNER_H
#define MEDIASCANNER_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <pthread.h>
namespace android {
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
new file mode 100644
index 0000000..960eda3
--- /dev/null
+++ b/include/media/stagefright/AudioPlayer.h
@@ -0,0 +1,98 @@
+/*
+ * 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 AUDIO_PLAYER_H_
+
+#define AUDIO_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/TimeSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaSource;
+class AudioTrack;
+
+class AudioPlayer : public TimeSource {
+public:
+ AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
+ virtual ~AudioPlayer();
+
+ // Caller retains ownership of "source".
+ void setSource(const sp<MediaSource> &source);
+
+ // Return time in us.
+ virtual int64_t getRealTimeUs();
+
+ void start();
+
+ void pause();
+ void resume();
+
+ void stop();
+
+ // Returns the timestamp of the last buffer played (in us).
+ int64_t getMediaTimeUs();
+
+ // Returns true iff a mapping is established, i.e. the AudioPlayer
+ // has played at least one frame of audio.
+ bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+ status_t seekTo(int64_t time_us);
+
+private:
+ sp<MediaSource> mSource;
+ AudioTrack *mAudioTrack;
+
+ MediaBuffer *mInputBuffer;
+
+ int mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+
+ Mutex mLock;
+ int64_t mNumFramesPlayed;
+
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ static void AudioCallback(int event, void *user, void *info);
+ void AudioCallback(int event, void *info);
+
+ static void AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me);
+
+ void fillBuffer(void *data, size_t size);
+
+ int64_t getRealTimeUsLocked() const;
+
+ AudioPlayer(const AudioPlayer &);
+ AudioPlayer &operator=(const AudioPlayer &);
+};
+
+} // namespace android
+
+#endif // AUDIO_PLAYER_H_
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
new file mode 100644
index 0000000..e129958
--- /dev/null
+++ b/include/media/stagefright/AudioSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 AUDIO_SOURCE_H_
+
+#define AUDIO_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class AudioRecord;
+
+class AudioSource {
+public:
+ AudioSource(int inputSource);
+ virtual ~AudioSource();
+
+ status_t initCheck() const;
+
+ 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);
+
+private:
+ AudioRecord *mRecord;
+ status_t mInitCheck;
+
+ AudioSource(const AudioSource &);
+ AudioSource &operator=(const AudioSource &);
+};
+
+} // namespace android
+
+#endif // AUDIO_SOURCE_H_
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
new file mode 100644
index 0000000..e35e19e
--- /dev/null
+++ b/include/media/stagefright/CachingDataSource.h
@@ -0,0 +1,62 @@
+/*
+ * 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 CACHING_DATASOURCE_H_
+
+#define CACHING_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CachingDataSource : public DataSource {
+public:
+ 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;
+ off_t mOffset;
+ size_t mLength;
+ void *mData;
+ };
+
+ sp<DataSource> mSource;
+ void *mData;
+ size_t mPageSize;
+ Page *mFirst, *mLast;
+
+ Page *allocate_page();
+
+ Mutex mLock;
+
+ CachingDataSource(const CachingDataSource &);
+ CachingDataSource &operator=(const CachingDataSource &);
+};
+
+} // namespace android
+
+#endif // CACHING_DATASOURCE_H_
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
new file mode 100644
index 0000000..7042e1a
--- /dev/null
+++ b/include/media/stagefright/CameraSource.h
@@ -0,0 +1,72 @@
+/*
+ * 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 CAMERA_SOURCE_H_
+
+#define CAMERA_SOURCE_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ICamera;
+class ICameraClient;
+class IMemory;
+
+class CameraSource : public MediaSource,
+ public MediaBufferObserver {
+public:
+ static CameraSource *Create();
+
+ virtual ~CameraSource();
+
+ 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);
+
+ virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
+ virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
+
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+ CameraSource(const sp<ICamera> &camera, const sp<ICameraClient> &client);
+
+ sp<ICamera> mCamera;
+ sp<ICameraClient> mCameraClient;
+
+ Mutex mLock;
+ Condition mFrameAvailableCondition;
+ List<sp<IMemory> > mFrames;
+
+ int mNumFrames;
+ bool mStarted;
+
+ CameraSource(const CameraSource &);
+ CameraSource &operator=(const CameraSource &);
+};
+
+} // namespace android
+
+#endif // CAMERA_SOURCE_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
new file mode 100644
index 0000000..f46f0af
--- /dev/null
+++ b/include/media/stagefright/DataSource.h
@@ -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.
+ */
+
+#ifndef DATA_SOURCE_H_
+
+#define DATA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class String8;
+
+class DataSource : public RefBase {
+public:
+ 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);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ bool sniff(String8 *mimeType, float *confidence);
+
+ typedef bool (*SnifferFunc)(
+ 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;
+
+ DataSource(const DataSource &);
+ DataSource &operator=(const DataSource &);
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_H_
diff --git a/include/media/stagefright/ESDS.h b/include/media/stagefright/ESDS.h
new file mode 100644
index 0000000..01bcd18
--- /dev/null
+++ b/include/media/stagefright/ESDS.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ESDS_H_
+
+#define ESDS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class ESDS {
+public:
+ ESDS(const void *data, size_t size);
+ ~ESDS();
+
+ status_t InitCheck() const;
+
+ status_t getCodecSpecificInfo(const void **data, size_t *size) const;
+
+private:
+ enum {
+ kTag_ESDescriptor = 0x03,
+ kTag_DecoderConfigDescriptor = 0x04,
+ kTag_DecoderSpecificInfo = 0x05
+ };
+
+ uint8_t *mData;
+ size_t mSize;
+
+ status_t mInitCheck;
+
+ size_t mDecoderSpecificOffset;
+ size_t mDecoderSpecificLength;
+
+ status_t skipDescriptorHeader(
+ size_t offset, size_t size,
+ uint8_t *tag, size_t *data_offset, size_t *data_size) const;
+
+ status_t parse();
+ status_t parseESDescriptor(size_t offset, size_t size);
+ status_t parseDecoderConfigDescriptor(size_t offset, size_t size);
+
+ ESDS(const ESDS &);
+ ESDS &operator=(const ESDS &);
+};
+
+} // namespace android
+#endif // ESDS_H_
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
new file mode 100644
index 0000000..ccbe0ef
--- /dev/null
+++ b/include/media/stagefright/FileSource.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FILE_SOURCE_H_
+
+#define FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class FileSource : public DataSource {
+public:
+ FileSource(const char *filename);
+ virtual ~FileSource();
+
+ status_t InitCheck() const;
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+ FILE *mFile;
+ Mutex mLock;
+
+ FileSource(const FileSource &);
+ FileSource &operator=(const FileSource &);
+};
+
+} // namespace android
+
+#endif // FILE_SOURCE_H_
+
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
new file mode 100644
index 0000000..0587c7c
--- /dev/null
+++ b/include/media/stagefright/HTTPDataSource.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 HTTP_DATASOURCE_H_
+
+#define HTTP_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPStream.h>
+
+namespace android {
+
+class HTTPDataSource : public DataSource {
+public:
+ HTTPDataSource(const char *host, int port, const char *path);
+ HTTPDataSource(const char *uri);
+
+ virtual ~HTTPDataSource();
+
+ // XXXandih
+ status_t InitCheck() const { return OK; }
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+ enum {
+ kBufferSize = 64 * 1024
+ };
+
+ HTTPStream mHttp;
+ char *mHost;
+ int mPort;
+ char *mPath;
+
+ void *mBuffer;
+ size_t mBufferLength;
+ off_t mBufferOffset;
+
+ HTTPDataSource(const HTTPDataSource &);
+ HTTPDataSource &operator=(const HTTPDataSource &);
+};
+
+} // namespace android
+
+#endif // HTTP_DATASOURCE_H_
+
diff --git a/include/media/stagefright/HTTPStream.h b/include/media/stagefright/HTTPStream.h
new file mode 100644
index 0000000..3d0d67a
--- /dev/null
+++ b/include/media/stagefright/HTTPStream.h
@@ -0,0 +1,74 @@
+/*
+ * 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 HTTP_STREAM_H_
+
+#define HTTP_STREAM_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/string.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class HTTPStream {
+public:
+ HTTPStream();
+ ~HTTPStream();
+
+ status_t connect(const char *server, int port = 80);
+ status_t disconnect();
+
+ status_t send(const char *data, size_t size);
+
+ // Assumes data is a '\0' terminated string.
+ status_t send(const char *data);
+
+ // Receive up to "size" bytes of data.
+ ssize_t receive(void *data, size_t size);
+
+ status_t receive_header(int *http_status);
+
+ // The header key used to retrieve the status line.
+ static const char *kStatusKey;
+
+ bool find_header_value(
+ const string &key, string *value) const;
+
+private:
+ enum State {
+ READY,
+ CONNECTED
+ };
+
+ State mState;
+ int mSocket;
+
+ KeyedVector<string, string> mHeaders;
+
+ // Receive a line of data terminated by CRLF, line will be '\0' terminated
+ // _excluding_ the termianting CRLF.
+ status_t receive_line(char *line, size_t size);
+
+ HTTPStream(const HTTPStream &);
+ HTTPStream &operator=(const HTTPStream &);
+};
+
+} // namespace android
+
+#endif // HTTP_STREAM_H_
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
new file mode 100644
index 0000000..4e1f3c3
--- /dev/null
+++ b/include/media/stagefright/MP3Extractor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 MP3_EXTRACTOR_H_
+
+#define MP3_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class String8;
+
+class MP3Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MP3Extractor(const sp<DataSource> &source);
+
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index);
+
+protected:
+ virtual ~MP3Extractor();
+
+private:
+ sp<DataSource> mDataSource;
+ off_t mFirstFramePos;
+ sp<MetaData> mMeta;
+ uint32_t mFixedHeader;
+
+ MP3Extractor(const MP3Extractor &);
+ MP3Extractor &operator=(const MP3Extractor &);
+};
+
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MP3_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Extractor.h b/include/media/stagefright/MPEG4Extractor.h
new file mode 100644
index 0000000..932e30f
--- /dev/null
+++ b/include/media/stagefright/MPEG4Extractor.h
@@ -0,0 +1,68 @@
+/*
+ * 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 MPEG4_EXTRACTOR_H_
+
+#define MPEG4_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class SampleTable;
+class String8;
+
+class MPEG4Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MPEG4Extractor(const sp<DataSource> &source);
+
+ 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;
+ sp<SampleTable> sampleTable;
+ };
+
+ sp<DataSource> mDataSource;
+ bool mHaveMetadata;
+
+ Track *mFirstTrack, *mLastTrack;
+
+ uint32_t mHandlerType;
+
+ status_t readMetaData();
+ status_t parseChunk(off_t *offset, int depth);
+
+ MPEG4Extractor(const MPEG4Extractor &);
+ MPEG4Extractor &operator=(const MPEG4Extractor &);
+};
+
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MPEG4_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
new file mode 100644
index 0000000..5147de9
--- /dev/null
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -0,0 +1,75 @@
+/*
+ * 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 MPEG4_WRITER_H_
+
+#define MPEG4_WRITER_H_
+
+#include <stdio.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaSource;
+class MetaData;
+
+class MPEG4Writer : public RefBase {
+public:
+ MPEG4Writer(const char *filename);
+
+ // Caller retains ownership of both meta and source.
+ void addSource(const sp<MetaData> &meta, const sp<MediaSource> &source);
+ void start();
+ void stop();
+
+ void beginBox(const char *fourcc);
+ void writeInt8(int8_t x);
+ void writeInt16(int16_t x);
+ void writeInt32(int32_t x);
+ void writeInt64(int64_t x);
+ void writeCString(const char *s);
+ void writeFourcc(const char *fourcc);
+ void write(const void *data, size_t size);
+ void endBox();
+
+protected:
+ virtual ~MPEG4Writer();
+
+private:
+ class Track;
+
+ FILE *mFile;
+ off_t mOffset;
+ off_t mMdatOffset;
+ Mutex mLock;
+
+ List<Track *> mTracks;
+
+ List<off_t> mBoxes;
+
+ off_t addSample(MediaBuffer *buffer);
+
+ MPEG4Writer(const MPEG4Writer &);
+ MPEG4Writer &operator=(const MPEG4Writer &);
+};
+
+} // namespace android
+
+#endif // MPEG4_WRITER_H_
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
new file mode 100644
index 0000000..339e6fb
--- /dev/null
+++ b/include/media/stagefright/MediaBuffer.h
@@ -0,0 +1,113 @@
+/*
+ * 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 MEDIA_BUFFER_H_
+
+#define MEDIA_BUFFER_H_
+
+#include <pthread.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaBufferObserver;
+class MetaData;
+
+class MediaBufferObserver {
+public:
+ MediaBufferObserver() {}
+ virtual ~MediaBufferObserver() {}
+
+ virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
+
+private:
+ MediaBufferObserver(const MediaBufferObserver &);
+ MediaBufferObserver &operator=(const MediaBufferObserver &);
+};
+
+class MediaBuffer {
+public:
+ // The underlying data remains the responsibility of the caller!
+ MediaBuffer(void *data, size_t size);
+
+ MediaBuffer(size_t size);
+
+ // Decrements the reference count and returns the buffer to its
+ // associated MediaBufferGroup if the reference count drops to 0.
+ void release();
+
+ // Increments the reference count.
+ void add_ref();
+
+ void *data() const;
+ size_t size() const;
+
+ size_t range_offset() const;
+ size_t range_length() const;
+
+ void set_range(size_t offset, size_t length);
+
+ sp<MetaData> meta_data();
+
+ // Clears meta data and resets the range to the full extent.
+ void reset();
+
+ void setObserver(MediaBufferObserver *group);
+
+ // Returns a clone of this MediaBuffer increasing its reference count.
+ // The clone references the same data but has its own range and
+ // MetaData.
+ MediaBuffer *clone();
+
+ int refcount() const;
+
+protected:
+ virtual ~MediaBuffer();
+
+private:
+ friend class MediaBufferGroup;
+ friend class OMXDecoder;
+
+ // For use by OMXDecoder, reference count must be 1, drop reference
+ // count to 0 without signalling the observer.
+ void claim();
+
+ MediaBufferObserver *mObserver;
+ MediaBuffer *mNextBuffer;
+ int mRefCount;
+
+ void *mData;
+ size_t mSize, mRangeOffset, mRangeLength;
+
+ bool mOwnsData;
+
+ sp<MetaData> mMetaData;
+
+ MediaBuffer *mOriginal;
+
+ void setNextBuffer(MediaBuffer *buffer);
+ MediaBuffer *nextBuffer();
+
+ MediaBuffer(const MediaBuffer &);
+ MediaBuffer &operator=(const MediaBuffer &);
+};
+
+} // namespace android
+
+#endif // MEDIA_BUFFER_H_
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
new file mode 100644
index 0000000..e95a9c2
--- /dev/null
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -0,0 +1,57 @@
+/*
+ * 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 MEDIA_BUFFER_GROUP_H_
+
+#define MEDIA_BUFFER_GROUP_H_
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+class MediaBufferGroup : public MediaBufferObserver {
+public:
+ MediaBufferGroup();
+ ~MediaBufferGroup();
+
+ void add_buffer(MediaBuffer *buffer);
+
+ // Blocks until a buffer is available and returns it to the caller,
+ // the returned buffer will have a reference count of 1.
+ status_t acquire_buffer(MediaBuffer **buffer);
+
+protected:
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+ friend class MediaBuffer;
+
+ Mutex mLock;
+ Condition mCondition;
+
+ MediaBuffer *mFirstBuffer, *mLastBuffer;
+
+ MediaBufferGroup(const MediaBufferGroup &);
+ MediaBufferGroup &operator=(const MediaBufferGroup &);
+};
+
+} // namespace android
+
+#endif // MEDIA_BUFFER_GROUP_H_
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
new file mode 100644
index 0000000..83acd77
--- /dev/null
+++ b/include/media/stagefright/MediaDebug.h
@@ -0,0 +1,18 @@
+#ifndef MEDIA_DEBUG_H_
+
+#define MEDIA_DEBUG_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/MediaErrors.h b/include/media/stagefright/MediaErrors.h
new file mode 100644
index 0000000..2bb0ed6
--- /dev/null
+++ b/include/media/stagefright/MediaErrors.h
@@ -0,0 +1,43 @@
+/*
+ * 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 MEDIA_ERRORS_H_
+
+#define MEDIA_ERRORS_H_
+
+#include <utils/Errors.h>
+
+namespace android {
+
+enum {
+ MEDIA_ERROR_BASE = -1000,
+
+ ERROR_ALREADY_CONNECTED = MEDIA_ERROR_BASE,
+ ERROR_NOT_CONNECTED = MEDIA_ERROR_BASE - 1,
+ ERROR_UNKNOWN_HOST = MEDIA_ERROR_BASE - 2,
+ ERROR_CANNOT_CONNECT = MEDIA_ERROR_BASE - 3,
+ ERROR_IO = MEDIA_ERROR_BASE - 4,
+ ERROR_CONNECTION_LOST = MEDIA_ERROR_BASE - 5,
+ ERROR_MALFORMED = MEDIA_ERROR_BASE - 7,
+ ERROR_OUT_OF_RANGE = MEDIA_ERROR_BASE - 8,
+ ERROR_BUFFER_TOO_SMALL = MEDIA_ERROR_BASE - 9,
+ ERROR_UNSUPPORTED = MEDIA_ERROR_BASE - 10,
+ ERROR_END_OF_STREAM = MEDIA_ERROR_BASE - 11,
+};
+
+} // namespace android
+
+#endif // MEDIA_ERRORS_H_
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
new file mode 100644
index 0000000..67e45bd
--- /dev/null
+++ b/include/media/stagefright/MediaExtractor.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_EXTRACTOR_H_
+
+#define MEDIA_EXTRACTOR_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class MediaSource;
+class MetaData;
+
+class MediaExtractor : public RefBase {
+public:
+ static sp<MediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
+
+ 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 &);
+ MediaExtractor &operator=(const MediaExtractor &);
+};
+
+} // namespace android
+
+#endif // MEDIA_EXTRACTOR_H_
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
new file mode 100644
index 0000000..53a2088
--- /dev/null
+++ b/include/media/stagefright/MediaPlayerImpl.h
@@ -0,0 +1,128 @@
+/*
+ * 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 MEDIA_PLAYER_IMPL_H_
+
+#define MEDIA_PLAYER_IMPL_H_
+
+#include <pthread.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class AudioPlayer;
+class IOMXRenderer;
+class ISurface;
+class MediaExtractor;
+class MediaBuffer;
+class MediaSource;
+class MemoryHeapPmem;
+class MetaData;
+class Surface;
+class TimeSource;
+
+class MediaPlayerImpl {
+public:
+ MediaPlayerImpl(const char *uri);
+
+ status_t initCheck() const;
+
+ // Assumes ownership of "fd".
+ MediaPlayerImpl(int fd, int64_t offset, int64_t length);
+
+ ~MediaPlayerImpl();
+
+ void play();
+ void pause();
+ bool isPlaying() const;
+
+ void setSurface(const sp<Surface> &surface);
+ void setISurface(const sp<ISurface> &isurface);
+
+ void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
+
+ int32_t getWidth() const { return mVideoWidth; }
+ int32_t getHeight() const { return mVideoHeight; }
+
+ int64_t getDuration();
+ int64_t getPosition();
+ status_t seekTo(int64_t time);
+
+private:
+ status_t mInitCheck;
+
+ OMXClient mClient;
+
+ sp<MediaExtractor> mExtractor;
+
+ TimeSource *mTimeSource;
+
+ sp<MediaSource> mAudioSource;
+ sp<MediaSource> mAudioDecoder;
+ AudioPlayer *mAudioPlayer;
+
+ sp<MediaSource> mVideoSource;
+ sp<MediaSource> mVideoDecoder;
+ int32_t mVideoWidth, mVideoHeight;
+ int64_t mVideoPosition;
+
+ int64_t mDuration;
+
+ bool mPlaying;
+ bool mPaused;
+
+ int64_t mTimeSourceDeltaUs;
+
+ sp<Surface> mSurface;
+ sp<ISurface> mISurface;
+ sp<IOMXRenderer> mVideoRenderer;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ Mutex mLock;
+ pthread_t mVideoThread;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ void init();
+
+ static void *VideoWrapper(void *me);
+ void videoEntry();
+
+ void setAudioSource(const sp<MediaSource> &source);
+ void setVideoSource(const sp<MediaSource> &source);
+
+ MediaSource *makeShoutcastSource(const char *path);
+
+ void displayOrDiscardFrame(MediaBuffer *buffer, int64_t pts_us);
+ void populateISurface();
+ void depopulateISurface();
+ void sendFrameToISurface(MediaBuffer *buffer);
+
+ void stop();
+
+ MediaPlayerImpl(const MediaPlayerImpl &);
+ MediaPlayerImpl &operator=(const MediaPlayerImpl &);
+};
+
+} // namespace android
+
+#endif // MEDIA_PLAYER_IMPL_H_
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
new file mode 100644
index 0000000..d1fa114
--- /dev/null
+++ b/include/media/stagefright/MediaSource.h
@@ -0,0 +1,93 @@
+/*
+ * 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 MEDIA_SOURCE_H_
+
+#define MEDIA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+struct MediaSource : public RefBase {
+ MediaSource();
+
+ // To be called before any other methods on this object, except
+ // getFormat().
+ virtual status_t start(MetaData *params = NULL) = 0;
+
+ // Any blocking read call returns immediately with a result of NO_INIT.
+ // It is an error to call any methods other than start after this call
+ // returns. Any buffers the object may be holding onto at the time of
+ // the stop() call are released.
+ // Also, it is imperative that any buffers output by this object and
+ // held onto by callers be released before a call to stop() !!!
+ virtual status_t stop() = 0;
+
+ // Returns the format of the data output by this media source.
+ virtual sp<MetaData> getFormat() = 0;
+
+ struct ReadOptions;
+
+ // Returns a new buffer of data. Call blocks until a
+ // buffer is available, an error is encountered of the end of the stream
+ // is reached.
+ // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us) const;
+
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ int64_t mLatenessUs;
+ };
+
+protected:
+ virtual ~MediaSource();
+
+private:
+ MediaSource(const MediaSource &);
+ MediaSource &operator=(const MediaSource &);
+};
+
+} // namespace android
+
+#endif // MEDIA_SOURCE_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
new file mode 100644
index 0000000..2d5b8d8
--- /dev/null
+++ b/include/media/stagefright/MetaData.h
@@ -0,0 +1,133 @@
+/*
+ * 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 META_DATA_H_
+
+#define META_DATA_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+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',
+};
+
+enum {
+ kTypeESDS = 'esds',
+ kTypeAVCC = 'avcc',
+};
+
+class MetaData : public RefBase {
+public:
+ MetaData();
+ MetaData(const MetaData &from);
+
+ enum Type {
+ TYPE_NONE = 'none',
+ TYPE_C_STRING = 'cstr',
+ TYPE_INT32 = 'in32',
+ TYPE_FLOAT = 'floa',
+ TYPE_POINTER = 'ptr ',
+ };
+
+ void clear();
+ bool remove(uint32_t key);
+
+ bool setCString(uint32_t key, const char *value);
+ bool setInt32(uint32_t key, int32_t value);
+ bool setFloat(uint32_t key, float value);
+ bool setPointer(uint32_t key, void *value);
+
+ bool findCString(uint32_t key, const char **value);
+ bool findInt32(uint32_t key, int32_t *value);
+ bool findFloat(uint32_t key, float *value);
+ bool findPointer(uint32_t key, void **value);
+
+ bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
+
+ bool findData(uint32_t key, uint32_t *type,
+ const void **data, size_t *size) const;
+
+protected:
+ virtual ~MetaData();
+
+private:
+ struct typed_data {
+ typed_data();
+ ~typed_data();
+
+ typed_data(const MetaData::typed_data &);
+ typed_data &operator=(const MetaData::typed_data &);
+
+ void clear();
+ void setData(uint32_t type, const void *data, size_t size);
+ void getData(uint32_t *type, const void **data, size_t *size) const;
+
+ private:
+ uint32_t mType;
+ size_t mSize;
+
+ union {
+ void *ext_data;
+ float reservoir;
+ } u;
+
+ bool usesReservoir() const {
+ return mSize <= sizeof(u.reservoir);
+ }
+
+ void allocateStorage(size_t size);
+ void freeStorage();
+
+ void *storage() {
+ return usesReservoir() ? &u.reservoir : u.ext_data;
+ }
+
+ const void *storage() const {
+ return usesReservoir() ? &u.reservoir : u.ext_data;
+ }
+ };
+
+ KeyedVector<uint32_t, typed_data> mItems;
+
+ // MetaData &operator=(const MetaData &);
+};
+
+} // namespace android
+
+#endif // META_DATA_H_
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
new file mode 100644
index 0000000..a8bd57f
--- /dev/null
+++ b/include/media/stagefright/MmapSource.h
@@ -0,0 +1,52 @@
+/*
+ * 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 MMAP_SOURCE_H_
+
+#define MMAP_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class MmapSource : public DataSource {
+public:
+ MmapSource(const char *filename);
+
+ // Assumes ownership of "fd".
+ MmapSource(int fd, int64_t offset, int64_t length);
+
+ virtual ~MmapSource();
+
+ status_t InitCheck() const;
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+ virtual status_t getSize(off_t *size);
+
+private:
+ int mFd;
+ void *mBase;
+ size_t mSize;
+
+ MmapSource(const MmapSource &);
+ MmapSource &operator=(const MmapSource &);
+};
+
+} // namespace android
+
+#endif // MMAP_SOURCE_H_
+
diff --git a/include/media/stagefright/OMXClient.h b/include/media/stagefright/OMXClient.h
new file mode 100644
index 0000000..7027e1b
--- /dev/null
+++ b/include/media/stagefright/OMXClient.h
@@ -0,0 +1,106 @@
+/*
+ * 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_CLIENT_H_
+
+#define OMX_CLIENT_H_
+
+#include <media/IOMX.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class OMXObserver {
+public:
+ OMXObserver();
+ virtual ~OMXObserver();
+
+ void postMessage(const omx_message &msg);
+
+protected:
+ virtual void onOMXMessage(const omx_message &msg) = 0;
+
+private:
+ friend class OMXClient;
+
+ pthread_t mThread;
+ Mutex mLock;
+ Condition mQueueNotEmpty;
+ List<omx_message> mQueue;
+
+ void start();
+ void stop();
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ OMXObserver(const OMXObserver &);
+ OMXObserver &operator=(const OMXObserver &);
+};
+
+class OMXClient;
+
+class OMXClientReflector : public BnOMXObserver {
+public:
+ OMXClientReflector(OMXClient *client);
+
+ virtual void on_message(const omx_message &msg);
+ void reset();
+
+private:
+ OMXClient *mClient;
+
+ OMXClientReflector(const OMXClientReflector &);
+ OMXClientReflector &operator=(const OMXClientReflector &);
+};
+
+class OMXClient {
+public:
+ friend class OMXClientReflector;
+
+ OMXClient();
+ ~OMXClient();
+
+ status_t connect();
+ void disconnect();
+
+ sp<IOMX> interface() {
+ return mOMX;
+ }
+
+ status_t registerObserver(IOMX::node_id node, OMXObserver *observer);
+ void unregisterObserver(IOMX::node_id node);
+
+private:
+ sp<IOMX> mOMX;
+ Mutex mLock;
+
+ KeyedVector<IOMX::node_id, OMXObserver *> mObservers;
+
+ sp<OMXClientReflector> mReflector;
+
+ bool onOMXMessage(const omx_message &msg);
+
+ OMXClient(const OMXClient &);
+ OMXClient &operator=(const OMXClient &);
+};
+
+} // namespace android
+
+#endif // OMX_CLIENT_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
new file mode 100644
index 0000000..d4ae349
--- /dev/null
+++ b/include/media/stagefright/OMXCodec.h
@@ -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.
+ * 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,
+ kWantsRawNALFrames = 2,
+ kRequiresLoadedToIdleAfterAllocation = 4,
+ kRequiresAllocateBufferOnInputPorts = 8,
+ };
+
+ 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;
+
+ 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);
+
+ 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();
+
+ void 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
new file mode 100644
index 0000000..0abc5a6
--- /dev/null
+++ b/include/media/stagefright/OMXDecoder.h
@@ -0,0 +1,185 @@
+/*
+ * 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_DECODER_H_
+
+#define OMX_DECODER_H_
+
+#include <binder/MemoryDealer.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+#include <OMX_Video.h>
+
+namespace android {
+
+class OMXMediaBuffer;
+
+class OMXDecoder : public MediaSource,
+ public OMXObserver,
+ public MediaBufferObserver {
+public:
+ static sp<OMXDecoder> Create(
+ OMXClient *client, const sp<MetaData> &data,
+ 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 addCodecSpecificData(const void *data, size_t size);
+
+ // from OMXObserver
+ virtual void onOMXMessage(const omx_message &msg);
+
+ // from MediaBufferObserver
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+protected:
+ virtual ~OMXDecoder();
+
+private:
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+
+ enum PortStatus {
+ kPortStatusActive = 0,
+ kPortStatusDisabled = 1,
+ kPortStatusShutdown = 2,
+ kPortStatusFlushing = 3,
+ kPortStatusFlushingToDisabled = 4,
+ kPortStatusFlushingToShutdown = 5,
+ };
+
+ enum Quirks {
+ kWantsRawNALFrames = 1,
+ kDoesntReturnBuffersOnDisable = 2,
+ kDoesntFlushOnExecutingToIdle = 4,
+ kDoesntProperlyFlushAllPortsAtOnce = 8,
+ kRequiresAllocateBufferOnInputPorts = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresLoadedToIdleAfterAllocation = 64,
+ kMeasuresTimeInMilliseconds = 128,
+ };
+
+ OMXClient *mClient;
+ sp<IOMX> mOMX;
+ IOMX::node_id mNode;
+ char *mComponentName;
+ char *mMIME;
+ bool mIsMP3;
+ bool mIsAVC;
+ bool mIsEncoder;
+ uint32_t mQuirks;
+
+ sp<MediaSource> mSource;
+ sp<MetaData> mOutputFormat;
+
+ Mutex mLock;
+ Condition mOutputBufferAvailable;
+
+ List<MediaBuffer *> mOutputBuffers;
+
+ struct CodecSpecificData {
+ void *data;
+ size_t size;
+ };
+
+ List<CodecSpecificData> mCodecSpecificData;
+ List<CodecSpecificData>::iterator mCodecSpecificDataIterator;
+
+ volatile OMX_STATETYPE mState;
+ OMX_U32 mPortStatusMask;
+ bool mShutdownInitiated;
+
+ typedef List<IOMX::buffer_id> BufferList;
+ Vector<BufferList> mBuffers;
+
+ KeyedVector<IOMX::buffer_id, sp<IMemory> > mBufferMap;
+ KeyedVector<IOMX::buffer_id, OMXMediaBuffer *> mMediaBufferMap;
+
+ sp<MemoryDealer> mDealer;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+ status_t mErrorCondition;
+ bool mReachedEndOfInput;
+
+ OMXDecoder(OMXClient *client, IOMX::node_id node,
+ const char *mime, const char *codec,
+ bool is_encoder,
+ uint32_t quirks,
+ const sp<MediaSource> &source);
+
+ void setPortStatus(OMX_U32 port_index, PortStatus status);
+ PortStatus getPortStatus(OMX_U32 port_index) const;
+
+ void allocateBuffers(OMX_U32 port_index);
+
+ void setAMRFormat();
+ void setAACFormat();
+
+ status_t setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat);
+
+ void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
+ void setVideoInputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
+ void setup();
+ void dumpPortDefinition(OMX_U32 port_index);
+
+ void onStart();
+ void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
+ void onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data);
+ void onEventPortSettingsChanged(OMX_U32 port_index);
+ void onStateChanged(OMX_STATETYPE to);
+ void onEmptyBufferDone(IOMX::buffer_id buffer);
+ void onFillBufferDone(const omx_message &msg);
+
+ void onRealEmptyBufferDone(IOMX::buffer_id buffer);
+ void onRealFillBufferDone(const omx_message &msg);
+
+ void initiateShutdown();
+
+ void freeInputBuffer(IOMX::buffer_id buffer);
+ void freeOutputBuffer(IOMX::buffer_id buffer);
+ void freePortBuffers(OMX_U32 port_index);
+
+ void postStart();
+ void postEmptyBufferDone(IOMX::buffer_id buffer);
+ void postInitialFillBuffer(IOMX::buffer_id buffer);
+
+ OMXDecoder(const OMXDecoder &);
+ OMXDecoder &operator=(const OMXDecoder &);
+};
+
+} // namespace android
+
+#endif // OMX_DECODER_H_
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/include/media/stagefright/QComHardwareRenderer.h
new file mode 100644
index 0000000..8292dd5
--- /dev/null
+++ b/include/media/stagefright/QComHardwareRenderer.h
@@ -0,0 +1,57 @@
+/*
+ * 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 QCOM_HARDWARE_RENDERER_H_
+
+#define QCOM_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapPmem;
+
+class QComHardwareRenderer : public VideoRenderer {
+public:
+ QComHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~QComHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapPmem> mMemoryHeap;
+
+ bool getOffset(void *platformPrivate, size_t *offset);
+ void publishBuffers(uint32_t pmem_fd);
+
+ QComHardwareRenderer(const QComHardwareRenderer &);
+ QComHardwareRenderer &operator=(const QComHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // QCOM_HARDWARE_RENDERER_H_
diff --git a/include/media/stagefright/SampleTable.h b/include/media/stagefright/SampleTable.h
new file mode 100644
index 0000000..808d142
--- /dev/null
+++ b/include/media/stagefright/SampleTable.h
@@ -0,0 +1,109 @@
+/*
+ * 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 SAMPLE_TABLE_H_
+
+#define SAMPLE_TABLE_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class DataSource;
+
+class SampleTable : public RefBase {
+public:
+ SampleTable(const sp<DataSource> &source);
+
+ // type can be 'stco' or 'co64'.
+ status_t setChunkOffsetParams(
+ uint32_t type, off_t data_offset, off_t data_size);
+
+ status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+
+ // type can be 'stsz' or 'stz2'.
+ status_t setSampleSizeParams(
+ uint32_t type, off_t data_offset, off_t data_size);
+
+ status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+
+ status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ uint32_t countChunkOffsets() const;
+ status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
+
+ status_t getChunkForSample(
+ uint32_t sample_index, uint32_t *chunk_index,
+ uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
+
+ uint32_t countSamples() const;
+ status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
+
+ status_t getSampleOffsetAndSize(
+ uint32_t sample_index, off_t *offset, size_t *size);
+
+ status_t getMaxSampleSize(size_t *size);
+
+ status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+
+ enum {
+ kSyncSample_Flag = 1
+ };
+ status_t findClosestSample(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+
+ status_t findClosestSyncSample(
+ uint32_t start_sample_index, uint32_t *sample_index);
+
+protected:
+ ~SampleTable();
+
+private:
+ sp<DataSource> mDataSource;
+ Mutex mLock;
+
+ off_t mChunkOffsetOffset;
+ uint32_t mChunkOffsetType;
+ uint32_t mNumChunkOffsets;
+
+ off_t mSampleToChunkOffset;
+ uint32_t mNumSampleToChunkOffsets;
+
+ off_t mSampleSizeOffset;
+ uint32_t mSampleSizeFieldSize;
+ uint32_t mDefaultSampleSize;
+ uint32_t mNumSampleSizes;
+
+ uint32_t mTimeToSampleCount;
+ uint32_t *mTimeToSample;
+
+ off_t mSyncSampleOffset;
+ uint32_t mNumSyncSamples;
+
+ SampleTable(const SampleTable &);
+ SampleTable &operator=(const SampleTable &);
+};
+
+} // namespace android
+
+#endif // SAMPLE_TABLE_H_
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
new file mode 100644
index 0000000..352857a
--- /dev/null
+++ b/include/media/stagefright/ShoutcastSource.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 SHOUTCAST_SOURCE_H_
+
+#define SHOUTCAST_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class HTTPStream;
+class MediaBufferGroup;
+
+class ShoutcastSource : public MediaSource {
+public:
+ // Assumes ownership of "http".
+ ShoutcastSource(HTTPStream *http);
+ virtual ~ShoutcastSource();
+
+ 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);
+
+private:
+ HTTPStream *mHttp;
+ size_t mMetaDataOffset;
+ size_t mBytesUntilMetaData;
+
+ MediaBufferGroup *mGroup;
+ bool mStarted;
+
+ ShoutcastSource(const ShoutcastSource &);
+ ShoutcastSource &operator= (const ShoutcastSource &);
+};
+
+} // namespace android
+
+#endif // SHOUTCAST_SOURCE_H_
+
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
new file mode 100644
index 0000000..705b914
--- /dev/null
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 SOFTWARE_RENDERER_H_
+
+#define SOFTWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapBase;
+
+class SoftwareRenderer : public VideoRenderer {
+public:
+ SoftwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~SoftwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapBase> mMemoryHeap;
+ int mIndex;
+
+ SoftwareRenderer(const SoftwareRenderer &);
+ SoftwareRenderer &operator=(const SoftwareRenderer &);
+};
+
+} // namespace android
+
+#endif // SOFTWARE_RENDERER_H_
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * 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 TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+ TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~TIHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<Overlay> mOverlay;
+ Vector<void *> mOverlayAddresses;
+ size_t mIndex;
+
+ TIHardwareRenderer(const TIHardwareRenderer &);
+ TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // TI_HARDWARE_RENDERER_H_
+
diff --git a/include/media/stagefright/TimeSource.h b/include/media/stagefright/TimeSource.h
new file mode 100644
index 0000000..443673d
--- /dev/null
+++ b/include/media/stagefright/TimeSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 TIME_SOURCE_H_
+
+#define TIME_SOURCE_H_
+
+#include <stdint.h>
+
+namespace android {
+
+class TimeSource {
+public:
+ TimeSource() {}
+ virtual ~TimeSource() {}
+
+ virtual int64_t getRealTimeUs() = 0;
+
+private:
+ TimeSource(const TimeSource &);
+ TimeSource &operator=(const TimeSource &);
+};
+
+class SystemTimeSource : public TimeSource {
+public:
+ SystemTimeSource();
+
+ virtual int64_t getRealTimeUs();
+
+private:
+ static int64_t GetSystemTimeUs();
+
+ int64_t mStartTimeUs;
+};
+
+} // namespace android
+
+#endif // TIME_SOURCE_H_
diff --git a/include/media/stagefright/TimedEventQueue.h b/include/media/stagefright/TimedEventQueue.h
new file mode 100644
index 0000000..a264421
--- /dev/null
+++ b/include/media/stagefright/TimedEventQueue.h
@@ -0,0 +1,106 @@
+/*
+ * 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 TIMED_EVENT_QUEUE_H_
+
+#define TIMED_EVENT_QUEUE_H_
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct TimedEventQueue {
+
+ struct Event : public RefBase {
+ Event() {}
+ virtual ~Event() {}
+
+ protected:
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
+
+ private:
+ friend class TimedEventQueue;
+
+ Event(const Event &);
+ Event &operator=(const Event &);
+ };
+
+ TimedEventQueue();
+ ~TimedEventQueue();
+
+ // Start executing the event loop.
+ void start();
+
+ // Stop executing the event loop, if flush is false, any pending
+ // events are discarded, otherwise the queue will stop (and this call
+ // return) once all pending events have been handled.
+ void stop(bool flush = false);
+
+ // Posts an event to the front of the queue (after all events that
+ // have previously been posted to the front but before timed events).
+ void postEvent(const sp<Event> &event);
+
+ void postEventToBack(const sp<Event> &event);
+
+ // It is an error to post an event with a negative delay.
+ void postEventWithDelay(const sp<Event> &event, int64_t delay_us);
+
+ // If the event is to be posted at a time that has already passed,
+ // it will fire as soon as possible.
+ void postTimedEvent(const sp<Event> &event, int64_t realtime_us);
+
+ // Returns true iff event is currently in the queue and has been
+ // successfully cancelled. In this case the event will have been
+ // removed from the queue and won't fire.
+ bool cancelEvent(const sp<Event> &event);
+
+ static int64_t getRealTimeUs();
+
+private:
+ struct QueueItem {
+ sp<Event> event;
+ int64_t realtime_us;
+ };
+
+ struct StopEvent : public TimedEventQueue::Event {
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+ queue->mStopped = true;
+ }
+ };
+
+ pthread_t mThread;
+ List<QueueItem> mQueue;
+ Mutex mLock;
+ Condition mQueueNotEmptyCondition;
+ Condition mQueueHeadChangedCondition;
+
+ bool mRunning;
+ bool mStopped;
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ TimedEventQueue(const TimedEventQueue &);
+ TimedEventQueue &operator=(const TimedEventQueue &);
+};
+
+} // namespace android
+
+#endif // TIMED_EVENT_QUEUE_H_
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
new file mode 100644
index 0000000..30c7f11
--- /dev/null
+++ b/include/media/stagefright/Utils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 UTILS_H_
+
+#define UTILS_H_
+
+#include <stdint.h>
+
+namespace android {
+
+#define FOURCC(c1, c2, c3, c4) \
+ (c1 << 24 | c2 << 16 | c3 << 8 | c4)
+
+uint16_t U16_AT(const uint8_t *ptr);
+uint32_t U32_AT(const uint8_t *ptr);
+uint64_t U64_AT(const uint8_t *ptr);
+
+uint64_t ntoh64(uint64_t x);
+uint64_t hton64(uint64_t x);
+
+} // namespace android
+
+#endif // UTILS_H_
diff --git a/include/media/stagefright/VideoRenderer.h b/include/media/stagefright/VideoRenderer.h
new file mode 100644
index 0000000..f80b277
--- /dev/null
+++ b/include/media/stagefright/VideoRenderer.h
@@ -0,0 +1,41 @@
+/*
+ * 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 VIDEO_RENDERER_H_
+
+#define VIDEO_RENDERER_H_
+
+#include <sys/types.h>
+
+namespace android {
+
+class VideoRenderer {
+public:
+ virtual ~VideoRenderer() {}
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate) = 0;
+
+protected:
+ VideoRenderer() {}
+
+ VideoRenderer(const VideoRenderer &);
+ VideoRenderer &operator=(const VideoRenderer &);
+};
+
+} // namespace android
+
+#endif // VIDEO_RENDERER_H_
diff --git a/include/media/stagefright/string.h b/include/media/stagefright/string.h
new file mode 100644
index 0000000..5dc7116
--- /dev/null
+++ b/include/media/stagefright/string.h
@@ -0,0 +1,54 @@
+/*
+ * 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 STRING_H_
+
+#define STRING_H_
+
+#include <utils/String8.h>
+
+namespace android {
+
+class string {
+public:
+ typedef size_t size_type;
+ static size_type npos;
+
+ string();
+ string(const char *s);
+ string(const char *s, size_t length);
+ string(const string &from, size_type start, size_type length = npos);
+
+ const char *c_str() const;
+ size_type size() const;
+
+ void clear();
+ void erase(size_type from, size_type length);
+
+ size_type find(char c) const;
+
+ bool operator<(const string &other) const;
+ bool operator==(const string &other) const;
+
+ string &operator+=(char c);
+
+private:
+ String8 mString;
+};
+
+} // namespace android
+
+#endif // STRING_H_
diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h
new file mode 100644
index 0000000..5b0f9fc
--- /dev/null
+++ b/include/private/binder/Static.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+
+#include <binder/IBinder.h>
+#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/binder/binder_module.h
similarity index 100%
rename from include/private/utils/binder_module.h
rename to include/private/binder/binder_module.h
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 496a739..8e2db20 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,17 +55,18 @@
uint32_t volumeLR;
};
uint32_t sampleRate;
+ // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
+ // 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
+ // 16 bit because data is converted to 16 bit before being stored in buffer
+ uint32_t frameSize;
uint8_t channels;
uint8_t flowControlFlag; // underrun (out) or overrrun (in) indication
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
- uint8_t forceReady;
+ uint8_t forceReady;
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time
- // Padding ensuring that data buffer starts on a cache line boundary (32 bytes).
- // See AudioFlinger::TrackBase constructor
- int32_t Padding[1];
- // Cache line boundary
-
+ // Cache line boundary (32 bytes)
+
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);
bool stepServer(uint32_t frameCount);
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index a85f275..523aed0 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -26,6 +26,8 @@
#endif
#include <private/pixelflinger/ggl_context.h>
+#include <hardware/copybit.h>
+#include <hardware/gralloc.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -39,7 +41,7 @@
class EGLBufferObjectManager;
namespace gl {
-
+
struct ogles_context_t;
struct matrixx_t;
struct transform_t;
@@ -96,7 +98,7 @@
struct vertex_t {
enum {
- // these constant matter for our clipping
+ // these constant matter for our clipping
CLIP_L = 0x0001, // clipping flags
CLIP_R = 0x0002,
CLIP_B = 0x0004,
@@ -106,7 +108,7 @@
EYE = 0x0040,
RESERVED = 0x0080,
-
+
USER_CLIP_0 = 0x0100, // user clipping flags
USER_CLIP_1 = 0x0200,
USER_CLIP_2 = 0x0400,
@@ -121,7 +123,7 @@
USER_CLIP_ALL = 0x3F00,
CLIP_ALL = 0x3F3F,
};
-
+
// the fields below are arranged to minimize d-cache usage
// we group together, by cache-line, the fields most likely to be used
@@ -130,7 +132,7 @@
vec4_t eye;
};
vec4_t clip;
-
+
uint32_t flags;
size_t index; // cache tag, and vertex index
GLfixed fog;
@@ -142,7 +144,7 @@
vec4_t color;
vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
uint32_t reserved1[4];
-
+
inline void clear() {
flags = index = locked = mru = 0;
}
@@ -199,7 +201,7 @@
GLenum indicesType;
buffer_t const* array_buffer;
buffer_t const* element_array_buffer;
-
+
void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
@@ -410,7 +412,7 @@
matrixx_t matrix;
uint32_t flags;
uint32_t ops;
-
+
union {
struct {
void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
@@ -509,17 +511,17 @@
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
+ GLsizei h;
struct {
GLint x;
GLint y;
- } surfaceport;
+ } surfaceport;
struct {
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
- } scissor;
+ GLsizei h;
+ } scissor;
};
// ----------------------------------------------------------------------------
@@ -594,6 +596,14 @@
void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
};
+struct copybits_context_t {
+ // A handle to the blit engine, if it exists, else NULL.
+ copybit_device_t* blitEngine;
+ int32_t minScale;
+ int32_t maxScale;
+ buffer_handle_t drawSurfaceBuffer;
+};
+
struct ogles_context_t {
context_t rasterizer;
array_machine_t arrays __attribute__((aligned(32)));
@@ -617,6 +627,14 @@
uint32_t transformTextures : 1;
EGLSurfaceManager* surfaceManager;
EGLBufferObjectManager* bufferObjectManager;
+
+ // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
+ // defined, but it is always present because ogles_context_t is a public
+ // struct that is used by clients of libagl. We want the size and offsets
+ // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
+
+ copybits_context_t copybits;
+
GLenum error;
static inline ogles_context_t* get() {
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
new file mode 100644
index 0000000..926fddb
--- /dev/null
+++ b/include/private/ui/RegionHelper.h
@@ -0,0 +1,281 @@
+/*
+ * 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 ANDROID_UI_PRIVATE_REGION_HELPER_H
+#define ANDROID_UI_PRIVATE_REGION_HELPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+template<typename RECT>
+class region_operator
+{
+ typedef typename RECT::value_type TYPE;
+ static const TYPE max_value = 0x7FFFFFF;
+
+public:
+ /*
+ * Common boolean operations:
+ * value is computed as 0b101 op 0b110
+ * other boolean operation are possible, simply compute
+ * their corresponding value with the above formulae and use
+ * it when instantiating a region_operator.
+ */
+ static const uint32_t LHS = 0x5; // 0b101
+ static const uint32_t RHS = 0x6; // 0b110
+ enum {
+ op_nand = LHS & ~RHS,
+ op_and = LHS & RHS,
+ op_or = LHS | RHS,
+ op_xor = LHS ^ RHS
+ };
+
+ struct region {
+ RECT const* rects;
+ size_t count;
+ TYPE dx;
+ TYPE dy;
+ inline region(const region& rhs)
+ : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
+ inline region(RECT const* r, size_t c)
+ : rects(r), count(c), dx(), dy() { }
+ inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
+ : rects(r), count(c), dx(dx), dy(dy) { }
+ };
+
+ class region_rasterizer {
+ friend class region_operator;
+ virtual void operator()(const RECT& rect) = 0;
+ public:
+ virtual ~region_rasterizer() { };
+ };
+
+ inline region_operator(int op, const region& lhs, const region& rhs)
+ : op_mask(op), spanner(lhs, rhs)
+ {
+ }
+
+ void operator()(region_rasterizer& rasterizer) {
+ RECT current;
+ do {
+ SpannerInner spannerInner(spanner.lhs, spanner.rhs);
+ int inside = spanner.next(current.top, current.bottom);
+ spannerInner.prepare(inside);
+ do {
+ TYPE left, right;
+ int inside = spannerInner.next(current.left, current.right);
+ if ((op_mask >> inside) & 1) {
+ if (current.left < current.right &&
+ current.top < current.bottom) {
+ rasterizer(current);
+ }
+ }
+ } while(!spannerInner.isDone());
+ } while(!spanner.isDone());
+ }
+
+private:
+ uint32_t op_mask;
+
+ class SpannerBase
+ {
+ public:
+ enum {
+ lhs_before_rhs = 0,
+ lhs_after_rhs = 1,
+ lhs_coincide_rhs = 2
+ };
+
+ protected:
+ TYPE lhs_head;
+ TYPE lhs_tail;
+ TYPE rhs_head;
+ TYPE rhs_tail;
+
+ inline int next(TYPE& head, TYPE& tail,
+ bool& more_lhs, bool& more_rhs)
+ {
+ int inside;
+ more_lhs = false;
+ more_rhs = false;
+ if (lhs_head < rhs_head) {
+ inside = lhs_before_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_head) {
+ tail = lhs_tail;
+ more_lhs = true;
+ } else {
+ lhs_head = rhs_head;
+ tail = rhs_head;
+ }
+ } else if (rhs_head < lhs_head) {
+ inside = lhs_after_rhs;
+ head = rhs_head;
+ if (rhs_tail <= lhs_head) {
+ tail = rhs_tail;
+ more_rhs = true;
+ } else {
+ rhs_head = lhs_head;
+ tail = lhs_head;
+ }
+ } else {
+ inside = lhs_coincide_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_tail) {
+ tail = rhs_head = lhs_tail;
+ more_lhs = true;
+ }
+ if (rhs_tail <= lhs_tail) {
+ tail = lhs_head = rhs_tail;
+ more_rhs = true;
+ }
+ }
+ return inside;
+ }
+ };
+
+ class Spanner : protected SpannerBase
+ {
+ friend class region_operator;
+ region lhs;
+ region rhs;
+
+ public:
+ inline Spanner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
+ SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy;
+ SpannerBase::rhs_head = rhs.rects->top + rhs.dy;
+ SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy;
+ }
+
+ inline bool isDone() const {
+ return !rhs.count && !lhs.count;
+ }
+
+ inline int next(TYPE& top, TYPE& bottom)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
+ // got to next span
+ size_t count = reg.count;
+ RECT const * rects = reg.rects;
+ RECT const * const end = rects + count;
+ const int top = rects->top;
+ while (rects != end && rects->top == top) {
+ rects++;
+ count--;
+ }
+ if (rects != end) {
+ aTop = rects->top + reg.dy;
+ aBottom = rects->bottom + reg.dy;
+ } else {
+ aTop = max_value;
+ aBottom = max_value;
+ }
+ reg.rects = rects;
+ reg.count = count;
+ }
+ };
+
+ class SpannerInner : protected SpannerBase
+ {
+ region lhs;
+ region rhs;
+
+ public:
+ inline SpannerInner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ }
+
+ inline void prepare(int inside) {
+ SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
+ SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+ SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
+ SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+ if (inside == SpannerBase::lhs_before_rhs) {
+ SpannerBase::rhs_head = max_value;
+ SpannerBase::rhs_tail = max_value;
+ } else if (inside == SpannerBase::lhs_after_rhs) {
+ SpannerBase::lhs_head = max_value;
+ SpannerBase::lhs_tail = max_value;
+ } else {
+ // use both spans
+ }
+ }
+
+ inline bool isDone() const {
+ return SpannerBase::lhs_head == max_value &&
+ SpannerBase::rhs_head == max_value;
+ }
+
+ inline int next(TYPE& left, TYPE& right)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& left, TYPE& right) {
+ if (reg.rects && reg.count) {
+ const int cur_span_top = reg.rects->top;
+ reg.rects++;
+ reg.count--;
+ if (!reg.count || reg.rects->top != cur_span_top) {
+ left = max_value;
+ right = max_value;
+ } else {
+ left = reg.rects->left + reg.dx;
+ right = reg.rects->right + reg.dx;
+ }
+ }
+ }
+ };
+
+ Spanner spanner;
+};
+
+// ----------------------------------------------------------------------------
+};
+
+#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
index 546d0ad..c9f6b5e 100644
--- a/include/private/ui/SharedState.h
+++ b/include/private/ui/SharedState.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <utils/Debug.h>
#include <utils/threads.h>
namespace android {
@@ -32,16 +33,12 @@
struct surface_info_t { // 4 longs, 16 bytes
enum {
- eBufferDirty = 0x01
+ eBufferDirty = 0x01,
+ eNeedNewBuffer = 0x02
};
- uint16_t w;
- uint16_t h;
- uint16_t stride;
- uint16_t bpr;
- uint16_t reserved;
- uint8_t format;
+ uint8_t reserved[11];
uint8_t flags;
- ssize_t bits_offset;
+ status_t status;
};
// ---------------------------------------------------------------------------
@@ -101,6 +98,8 @@
struct per_client_cblk_t // 4KB max
{
+ per_client_cblk_t() : lock(Mutex::SHARED) { }
+
Mutex lock;
Condition cv;
layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
@@ -110,8 +109,6 @@
INSPECT = 0x00000002
};
- per_client_cblk_t();
-
// these functions are used by the clients
status_t validate(size_t i) const;
int32_t lock_layer(size_t i, uint32_t flags);
@@ -138,30 +135,19 @@
struct surface_flinger_cblk_t // 4KB max
{
- surface_flinger_cblk_t();
-
uint8_t connected;
uint8_t reserved[3];
uint32_t pad[7];
-
display_cblk_t displays[NUM_DISPLAY_MAX];
};
// ---------------------------------------------------------------------------
-template<bool> struct CTA;
-template<> struct CTA<true> { };
+COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128)
+COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096)
+COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
-// compile-time assertions. just to avoid catastrophes.
-inline void compile_time_asserts() {
- CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
- (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
- CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
- (void)sizeof__per_client_cblk_t__le_4096; // we don't want a warning
- CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
- (void)sizeof__surface_flinger_cblk_t__le_4096; // we don't want a warning
-}
-
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UI_SHARED_STATE_H
diff --git a/include/private/ui/SurfaceBuffer.h b/include/private/ui/SurfaceBuffer.h
new file mode 100644
index 0000000..bf68406
--- /dev/null
+++ b/include/private/ui/SurfaceBuffer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+#define ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+#include <private/ui/android_natives_priv.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class BufferMapper;
+class Parcel;
+class Rect;
+class Surface;
+class SurfaceBuffer;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ SurfaceBuffer,
+ LightRefBase<SurfaceBuffer> >
+{
+public:
+ status_t lock(uint32_t usage, void** vaddr);
+ status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
+ status_t unlock();
+
+protected:
+ SurfaceBuffer();
+ SurfaceBuffer(const Parcel& reply);
+ virtual ~SurfaceBuffer();
+ bool mOwner;
+
+ inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline BufferMapper& getBufferMapper() { return mBufferMapper; }
+
+private:
+ friend class Surface;
+ friend class BpSurface;
+ friend class BnSurface;
+ friend class LightRefBase<SurfaceBuffer>;
+
+ SurfaceBuffer& operator = (const SurfaceBuffer& rhs);
+ const SurfaceBuffer& operator = (const SurfaceBuffer& rhs) const;
+
+ static status_t writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer);
+
+ BufferMapper& mBufferMapper;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
index ff91b61..7386d33 100644
--- a/include/private/ui/SurfaceFlingerSynchro.h
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -21,7 +21,6 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/threads.h>
#include <ui/ISurfaceComposer.h>
namespace android {
@@ -31,7 +30,6 @@
class SurfaceFlingerSynchro
{
public:
-
// client constructor
SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
~SurfaceFlingerSynchro();
@@ -40,34 +38,8 @@
status_t signal();
private:
- class Barrier {
- public:
- Barrier();
- ~Barrier();
- void open();
- void close();
- void waitAndClose();
- status_t waitAndClose(nsecs_t timeout);
- private:
- enum { OPENED, CLOSED };
- mutable Mutex lock;
- mutable Condition cv;
- volatile int state;
- };
-
friend class SurfaceFlinger;
-
- // server constructor
- SurfaceFlingerSynchro();
-
- void open();
-
- // wait until there is some work to do
- status_t wait();
- status_t wait(nsecs_t timeout);
-
sp<ISurfaceComposer> mSurfaceComposer;
- Barrier mBarrier;
};
}; // namespace android
diff --git a/include/private/ui/android_natives_priv.h b/include/private/ui/android_natives_priv.h
new file mode 100644
index 0000000..9c92af8
--- /dev/null
+++ b/include/private/ui/android_natives_priv.h
@@ -0,0 +1,62 @@
+/*
+ * 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 ANDROID_ANDROID_NATIVES_PRIV_H
+#define ANDROID_ANDROID_NATIVES_PRIV_H
+
+#include <ui/egl/android_natives.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+typedef struct android_native_buffer_t
+{
+#ifdef __cplusplus
+ android_native_buffer_t() {
+ common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ common.version = sizeof(android_native_buffer_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ int width;
+ int height;
+ int stride;
+ int format;
+ int usage;
+
+ void* reserved[2];
+
+ buffer_handle_t handle;
+
+ void* reserved_proc[8];
+} android_native_buffer_t;
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
index f1439b7..d95ae0d 100644
--- a/include/private/utils/Static.h
+++ b/include/private/utils/Static.h
@@ -20,14 +20,6 @@
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#ifndef LIBUTILS_NATIVE
-#include <utils/IBinder.h>
-#include <utils/IMemory.h>
-#include <utils/ProcessState.h>
-#include <utils/IPermissionController.h>
-#include <utils/IServiceManager.h>
-#endif
-
namespace android {
// For TextStream.cpp
extern Vector<int32_t> gTextBuffers;
@@ -40,19 +32,4 @@
extern void initialize_string16();
extern void terminate_string16();
-
-
-#ifndef LIBUTILS_NATIVE
-
-// For ProcessState.cpp
-extern Mutex gProcessMutex;
-extern sp<ProcessState> gProcess;
-
-// For ServiceManager.cpp
-extern Mutex gDefaultServiceManagerLock;
-extern sp<IServiceManager> gDefaultServiceManager;
-extern sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
deleted file mode 100644
index ac2ab19..0000000
--- a/include/private/utils/futex_synchro.h
+++ /dev/null
@@ -1,60 +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.
- */
-
-#ifndef _FUTEX_SYNCHRO_H
-#define _FUTEX_SYNCHRO_H
-
-#ifndef HAVE_FUTEX
-#error "HAVE_FUTEX not defined"
-#endif
-
-#define FUTEX_WAIT_INFINITE (0)
-
-typedef struct futex_mutex_t futex_mutex_t;
-
-struct futex_mutex_t
-{
- volatile int value;
-};
-
-typedef struct futex_cond_t futex_cond_t;
-
-struct futex_cond_t
-{
- volatile int value;
-};
-
-
-#if __cplusplus
-extern "C" {
-#endif
-
-void futex_mutex_init(futex_mutex_t *m);
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
-void futex_mutex_unlock(futex_mutex_t *m);
-int futex_mutex_trylock(futex_mutex_t *m);
-
-void futex_cond_init(futex_cond_t *c);
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
-void futex_cond_signal(futex_cond_t *c);
-void futex_cond_broadcast(futex_cond_t *c);
-
-#if __cplusplus
-} // extern "C"
-#endif
-
-#endif // _FUTEX_SYNCHRO_H
-
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 21cb73b..28b0d2f 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -43,7 +43,7 @@
// @param [inout] void *& - The userdata pointer set in the original
// synth call
// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] audio_format - The AudioSystem::audio_format enum
+// @param [in] uint32_t - The audio format
// @param [in] int - The number of channels
// @param [inout] int8_t *& - A buffer of audio data only valid during the
// execution of the callback
@@ -54,7 +54,7 @@
// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
// there is more data to produce.
typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
- AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
+ uint32_t, int, int8_t *&, size_t&, tts_synth_status);
class TtsEngine;
extern "C" TtsEngine* getTtsEngine();
@@ -80,6 +80,8 @@
class TtsEngine
{
public:
+ virtual ~TtsEngine() {}
+
// Initialize the TTS engine and returns whether initialization succeeded.
// @param synthDoneCBPtr synthesis callback function pointer
// @return TTS_SUCCESS, or TTS_FAILURE
diff --git a/include/ui/BufferMapper.h b/include/ui/BufferMapper.h
new file mode 100644
index 0000000..5f084be
--- /dev/null
+++ b/include/ui/BufferMapper.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UI_BUFFER_MAPPER_H
+#define ANDROID_UI_BUFFER_MAPPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Singleton.h>
+
+#include <hardware/gralloc.h>
+
+
+struct gralloc_module_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Rect;
+
+class BufferMapper : public Singleton<BufferMapper>
+{
+public:
+ static inline BufferMapper& get() { return getInstance(); }
+
+ status_t registerBuffer(buffer_handle_t handle);
+
+ status_t unregisterBuffer(buffer_handle_t handle);
+
+ status_t lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr);
+
+ status_t unlock(buffer_handle_t handle);
+
+ // dumps information about the mapping of this handle
+ void dump(buffer_handle_t handle);
+
+private:
+ friend class Singleton<BufferMapper>;
+ BufferMapper();
+ gralloc_module_t const *mAllocMod;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_UI_BUFFER_MAPPER_H
+
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index afb07b5..ae6e255 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -66,15 +66,16 @@
// msgType in notifyCallback and dataCallback functions
enum {
- CAMERA_MSG_ERROR = 0,
- CAMERA_MSG_SHUTTER,
- CAMERA_MSG_FOCUS,
- CAMERA_MSG_ZOOM,
- CAMERA_MSG_PREVIEW_FRAME,
- CAMERA_MSG_VIDEO_FRAME,
- CAMERA_MSG_POSTVIEW_FRAME,
- CAMERA_MSG_RAW_IMAGE,
- CAMERA_MSG_COMPRESSED_IMAGE
+ CAMERA_MSG_ERROR = 0x001,
+ CAMERA_MSG_SHUTTER = 0x002,
+ CAMERA_MSG_FOCUS = 0x004,
+ CAMERA_MSG_ZOOM = 0x008,
+ CAMERA_MSG_PREVIEW_FRAME = 0x010,
+ CAMERA_MSG_VIDEO_FRAME = 0x020,
+ CAMERA_MSG_POSTVIEW_FRAME = 0x040,
+ CAMERA_MSG_RAW_IMAGE = 0x080,
+ CAMERA_MSG_COMPRESSED_IMAGE = 0x100,
+ CAMERA_MSG_ALL_MSGS = 0x1FF
};
// camera fatal errors
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 822b4a8..535f70e 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -17,30 +17,28 @@
#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/RefBase.h>
+#include <ui/ISurface.h>
+#include <ui/Camera.h>
#include <ui/CameraParameters.h>
#include <ui/Overlay.h>
namespace android {
-/** Callback for startPreview() */
-typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*notify_callback)(int32_t msgType,
+ int32_t ext1,
+ int32_t ext2,
+ void* user);
-/** Callback for startRecord() */
-typedef void (*recording_callback)(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
+typedef void (*data_callback)(int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
-/** Callback for takePicture() */
-typedef void (*shutter_callback)(void* user);
-
-/** Callback for takePicture() */
-typedef void (*raw_callback)(const sp<IMemory>& mem, void* user);
-
-/** Callback for takePicture() */
-typedef void (*jpeg_callback)(const sp<IMemory>& mem, void* user);
-
-/** Callback for autoFocus() */
-typedef void (*autofocus_callback)(bool focused, void* user);
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+ int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
/**
* CameraHardwareInterface.h defines the interface to the
@@ -57,28 +55,21 @@
* CameraService calls getPreviewHeap() to establish access to the
* preview heap so it can be registered with SurfaceFlinger for
* efficient display updating while in preview mode.
- * -# startPreview() is called, which is passed a preview_callback()
- * function and a user parameter. The camera instance then periodically
- * calls preview_callback() each time a new preview frame is available.
- * The callback routine has two parameters: the first is a pointer to
- * the IMemory containing the frame and the second a user parameter. If
- * the preview_callback code needs to use this memory after returning,
- * it must copy the data.
+ * -# startPreview() is called. The camera instance then periodically
+ * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ * a new preview frame is available. If data callback code needs to use
+ * this memory after returning, it must copy the data.
*
- * Prior to taking a picture, CameraService calls autofocus() with
- * autofocus_callback() and a user parameter. When auto focusing has
- * completed, the camera instance calls autofocus_callback(), which informs
- * the application whether focusing was successful. The camera instance
- * only calls autofocus_callback() once and it is up to the application to
- * call autoFocus() again if refocusing is desired.
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up to the application to call autoFocus()
+ * again if refocusing is desired.
*
* CameraService calls takePicture() to request the camera instance take a
- * picture. This method has two callbacks: raw_callback() and jpeg_callback().
- * When the raw image is available, raw_callback() is called with a pointer
- * to the IMemory containing the raw image. When the jpeg image is available,
- * jpeg_callback() is called with a pointer to the IMemory containing the
- * jpeg image. As with preview_callback(), the memory must be copied if it's
- * needed after returning.
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
*/
class CameraHardwareInterface : public virtual RefBase {
public:
@@ -90,17 +81,45 @@
/** Return the IMemoryHeap for the raw image heap */
virtual sp<IMemoryHeap> getRawHeap() const = 0;
+ /** Set the notification and data callbacks */
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user) = 0;
+
/**
- * Start preview mode. When a preview image is available
- * preview_callback is called with the user parameter. The
- * call back parameter may be null.
+ * The following three functions all take a msgtype,
+ * which is a bitmask of the messages defined in
+ * include/ui/Camera.h
*/
- virtual status_t startPreview(preview_callback cb, void* user) = 0;
+
+ /**
+ * Enable a message, or set of messages.
+ */
+ virtual void enableMsgType(int32_t msgType) = 0;
+
+ /**
+ * Disable a message, or a set of messages.
+ */
+ virtual void disableMsgType(int32_t msgType) = 0;
+
+ /**
+ * Query whether a message, or a set of messages, is enabled.
+ * Note that this is operates as an AND, if any of the messages
+ * queried are off, this will return false.
+ */
+ virtual bool msgTypeEnabled(int32_t msgType) = 0;
+
+ /**
+ * Start preview mode.
+ */
+ virtual status_t startPreview() = 0;
+
/**
* Only used if overlays are used for camera preview.
*/
- virtual bool useOverlay() {return false;}
- virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
+ virtual bool useOverlay() {return false;}
+ virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
/**
* Stop a previously started preview.
@@ -113,11 +132,11 @@
virtual bool previewEnabled() = 0;
/**
- * Start record mode. When a record image is available recording_callback()
- * is called with the user parameter. Every record frame must be released
+ * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+ * message is sent with the corresponding frame. Every record frame must be released
* by calling releaseRecordingFrame().
*/
- virtual status_t startRecording(recording_callback cb, void* user) = 0;
+ virtual status_t startRecording() = 0;
/**
* Stop a previously started recording.
@@ -130,39 +149,27 @@
virtual bool recordingEnabled() = 0;
/**
- * Release a record frame previously returned by the recording_callback()
- * passed to startRecord().
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
*/
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
/**
- * Start auto focus, the callback routine is called
- * once when focusing is complete. autoFocus() will
- * be called again if another auto focus is needed.
+ * Start auto focus, the notification callback routine is called
+ * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+ * will be called again if another auto focus is needed.
*/
- virtual status_t autoFocus(autofocus_callback,
- void* user) = 0;
+ virtual status_t autoFocus() = 0;
/**
- * Take a picture. The raw_callback is called when
- * the uncompressed image is available. The jpeg_callback
- * is called when the compressed image is available. These
- * call backs may be null. The user parameter is passed
- * to each of the call back routines.
+ * Take a picture.
*/
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user) = 0;
+ virtual status_t takePicture() = 0;
/**
- * Cancel a picture that was started with takePicture. You may cancel any
- * of the shutter, raw, or jpeg callbacks. Calling this method when no
- * picture is being taken is a no-op.
+ * Cancel a picture that was started with takePicture. Calling this
+ * method when no picture is being taken is a no-op.
*/
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg) = 0;
+ virtual status_t cancelPicture() = 0;
/** Set the camera parameters. */
virtual status_t setParameters(const CameraParameters& params) = 0;
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
deleted file mode 100644
index a8b5853..0000000
--- a/include/ui/EGLDisplaySurface.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_EGL_DISPLAY_SURFACE_H
-#define ANDROID_EGL_DISPLAY_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/EGLNativeSurface.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <linux/fb.h>
-
-#include <EGL/egl.h>
-
-struct copybit_device_t;
-struct copybit_image_t;
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Region;
-class Rect;
-
-class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
-{
-public:
- EGLDisplaySurface();
- ~EGLDisplaySurface();
-
- int32_t getPageFlipCount() const;
- void copyFrontToBack(const Region& copyback);
- void copyFrontToImage(const copybit_image_t& dst);
- void copyBackToImage(const copybit_image_t& dst);
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
-
- uint32_t swapBuffers();
-
- status_t mapFrameBuffer();
-
- enum {
- PAGE_FLIP = 0x00000001
- };
- GGLSurface mFb[2];
- int mIndex;
- uint32_t mFlags;
- size_t mSize;
- fb_var_screeninfo mInfo;
- fb_fix_screeninfo mFinfo;
- int32_t mPageFlipCount;
- nsecs_t mTime;
- int32_t mSwapCount;
- nsecs_t mSleep;
- uint32_t mFeatureFlags;
- copybit_device_t* mBlitEngine;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_DISPLAY_SURFACE_H
-
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
deleted file mode 100644
index 3494234..0000000
--- a/include/ui/EGLNativeWindowSurface.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-#define ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ui/EGLNativeSurface.h>
-#include <EGL/egl.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Surface;
-
-class EGLNativeWindowSurface : public EGLNativeSurface<EGLNativeWindowSurface>
-{
-public:
- EGLNativeWindowSurface(const sp<Surface>& surface);
- ~EGLNativeWindowSurface();
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
- static void hook_connect(NativeWindowType window);
- static void hook_disconnect(NativeWindowType window);
-
- uint32_t swapBuffers();
- void connect();
- void disconnect();
-
- sp<Surface> mSurface;
- bool mConnected;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
diff --git a/include/ui/EGLUtils.h b/include/ui/EGLUtils.h
new file mode 100644
index 0000000..a5bff81
--- /dev/null
+++ b/include/ui/EGLUtils.h
@@ -0,0 +1,53 @@
+/*
+ * 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 ANDROID_UI_EGLUTILS_H
+#define ANDROID_UI_EGLUTILS_H
+
+#include <utils/Errors.h>
+#include <ui/PixelFormat.h>
+#include <EGL/egl.h>
+
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class EGLUtils
+{
+public:
+
+ static const char *strerror(EGLint err);
+
+ static status_t selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig);
+
+ static status_t selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_UI_EGLUTILS_H */
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3848d8c..3b18c77 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -20,7 +20,10 @@
#include <utils/String8.h>
#include <utils/threads.h>
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <linux/input.h>
@@ -52,7 +55,9 @@
CLASS_KEYBOARD = 0x00000001,
CLASS_ALPHAKEY = 0x00000002,
CLASS_TOUCHSCREEN = 0x00000004,
- CLASS_TRACKBALL = 0x00000008
+ CLASS_TRACKBALL = 0x00000008,
+ CLASS_TOUCHSCREEN_MT= 0x00000010,
+ CLASS_DPAD = 0x00000020
};
uint32_t getDeviceClasses(int32_t deviceId) const;
@@ -70,6 +75,13 @@
int getKeycodeState(int key) const;
int getKeycodeState(int32_t deviceId, int key) const;
+ status_t scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const;
+
+ // exclude a particular device from opening
+ // this can be used to ignore input devices for sensors
+ void addExcludedDevice(const char* deviceName);
+
// special type codes when devices are added/removed.
enum {
DEVICE_ADDED = 0x10000000,
@@ -82,10 +94,9 @@
virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen);
-
+
protected:
virtual ~EventHub();
- virtual void onFirstRef();
private:
bool openPlatformInput(void);
@@ -108,17 +119,18 @@
String8 keylayoutFilename;
device_t* next;
- device_t(int32_t _id, const char* _path);
+ device_t(int32_t _id, const char* _path, const char* name);
~device_t();
};
device_t* getDevice(int32_t deviceId) const;
+ bool hasKeycode(device_t* device, int keycode) const;
// Protect all internal state.
mutable Mutex mLock;
bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+ int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
struct device_ent {
device_t* device;
@@ -133,7 +145,10 @@
device_t **mDevices;
struct pollfd *mFDs;
int mFDCount;
-
+
+ bool mOpened;
+ List<String8> mExcludedDevices;
+
// device ids that report particular switches.
#ifdef EV_SW
int32_t mSwitches[SW_MAX+1];
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
new file mode 100644
index 0000000..68144b5
--- /dev/null
+++ b/include/ui/FramebufferNativeWindow.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+#define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <utils/threads.h>
+#include <ui/Rect.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include <ui/egl/android_natives.h>
+
+
+extern "C" EGLNativeWindowType android_createDisplaySurface(void);
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Surface;
+class NativeBuffer;
+
+// ---------------------------------------------------------------------------
+
+class FramebufferNativeWindow
+ : public EGLNativeBase<
+ android_native_window_t,
+ FramebufferNativeWindow,
+ LightRefBase<FramebufferNativeWindow> >
+{
+public:
+ FramebufferNativeWindow();
+
+ framebuffer_device_t const * getDevice() const { return fbDev; }
+
+ bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+ status_t setUpdateRectangle(const Rect& updateRect);
+
+private:
+ friend class LightRefBase<FramebufferNativeWindow>;
+ ~FramebufferNativeWindow(); // this class cannot be overloaded
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+
+ framebuffer_device_t* fbDev;
+ alloc_device_t* grDev;
+
+ sp<NativeBuffer> buffers[2];
+ sp<NativeBuffer> front;
+
+ mutable Mutex mutex;
+ Condition mCondition;
+ int32_t mNumBuffers;
+ int32_t mNumFreeBuffers;
+ int32_t mBufferHead;
+ bool mUpdateOnDemand;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index 241fb63..1df7914 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -18,10 +18,10 @@
#define ANDROID_HARDWARE_ICAMERA_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ISurface.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/String8.h>
#include <ui/Camera.h>
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index 1001c71..236d0f6 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -18,9 +18,9 @@
#define ANDROID_HARDWARE_ICAMERA_APP_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <utils/Timers.h>
namespace android {
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
index c652c51..061681a 100644
--- a/include/ui/ICameraService.h
+++ b/include/ui/ICameraService.h
@@ -18,8 +18,8 @@
#define ANDROID_HARDWARE_ICAMERASERVICE_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ICameraClient.h>
#include <ui/ICamera.h>
diff --git a/include/ui/IOverlay.h b/include/ui/IOverlay.h
index 699b1b0..af3add1 100644
--- a/include/ui/IOverlay.h
+++ b/include/ui/IOverlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 87b320f..7909c2f 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -21,11 +21,12 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
namespace android {
@@ -33,6 +34,7 @@
class IMemoryHeap;
class OverlayRef;
+class SurfaceBuffer;
class ISurface : public IInterface
{
@@ -42,11 +44,13 @@
UNREGISTER_BUFFERS,
POST_BUFFER, // one-way transaction
CREATE_OVERLAY,
+ GET_BUFFER,
};
public:
DECLARE_META_INTERFACE(Surface);
+ virtual sp<SurfaceBuffer> getBuffer(int usage) = 0;
class BufferHeap {
public:
@@ -78,9 +82,7 @@
};
virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
-
virtual void postBuffer(ssize_t offset) = 0; // one-way
-
virtual void unregisterBuffers() = 0;
virtual sp<OverlayRef> createOverlay(
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
index 5c64b22..25d954c 100644
--- a/include/ui/ISurfaceComposer.h
+++ b/include/ui/ISurfaceComposer.h
@@ -22,7 +22,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -32,7 +32,6 @@
// ----------------------------------------------------------------------------
class DisplayInfo;
-class IGPUCallback;
class ISurfaceComposer : public IInterface
{
@@ -41,8 +40,6 @@
enum { // (keep in sync with Surface.java)
eHidden = 0x00000004,
- eGPU = 0x00000008,
- eHardware = 0x00000010,
eDestroyBackbuffer = 0x00000020,
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
@@ -63,7 +60,6 @@
eTransparentRegionChanged = 0x00000020,
eVisibilityChanged = 0x00000040,
eFreezeTintChanged = 0x00000080,
- eDestroyed = 0x00000100
};
enum {
@@ -94,7 +90,7 @@
virtual sp<ISurfaceFlingerClient> createConnection() = 0;
/* retrieve the control block */
- virtual sp<IMemory> getCblk() const = 0;
+ virtual sp<IMemoryHeap> getCblk() const = 0;
/* open/close transactions. recquires ACCESS_SURFACE_FLINGER permission */
virtual void openGlobalTransaction() = 0;
@@ -112,37 +108,12 @@
*/
virtual void bootFinished() = 0;
- /* get access to the GPU. Access is relinquished when releasing regs */
- struct gpu_info_t {
- struct gpu_region_t {
- sp<IMemory> region;
- size_t reserved;
- };
- sp<IMemory> regs;
- size_t count;
- gpu_region_t regions[2];
- };
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback,
- gpu_info_t* gpu) = 0;
-
- /* take the gpu back from any apps using it. They'll get a
- * EGL_CONTEXT_LOST error */
- virtual status_t revokeGPU() = 0;
-
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
};
-class IGPUCallback : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(GPUCallback);
- virtual void gpuLost() = 0; //one-way
-};
-
// ----------------------------------------------------------------------------
class BnSurfaceComposer : public BnInterface<ISurfaceComposer>
@@ -159,8 +130,6 @@
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
- REQUEST_GPU,
- REVOKE_GPU,
SIGNAL
};
@@ -170,15 +139,6 @@
uint32_t flags = 0);
};
-class BnGPUCallback : public BnInterface<IGPUCallback>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 5b9361d..932a70a 100644
--- a/include/ui/ISurfaceFlingerClient.h
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/ISurface.h>
@@ -52,12 +52,11 @@
struct surface_data_t {
int32_t token;
int32_t identity;
- sp<IMemoryHeap> heap[2];
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
};
- virtual void getControlBlocks(sp<IMemory>* ctl) const = 0;
+ virtual sp<IMemoryHeap> getControlBlock() const = 0;
virtual sp<ISurface> createSurface( surface_data_t* data,
int pid,
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
index 66514b4..a9ae1c4 100644
--- a/include/ui/Overlay.h
+++ b/include/ui/Overlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -82,6 +82,16 @@
/* release the overlay buffer and post it */
status_t queueBuffer(overlay_buffer_t buffer);
+ /* change the width and height of the overlay */
+ status_t resizeInput(uint32_t width, uint32_t height);
+
+ status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
+
+ status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
+
+ /* set the buffer attributes */
+ status_t setParameter(int param, int value);
+
/* returns the address of a given buffer if supported, NULL otherwise. */
void* getBufferAddress(overlay_buffer_t buffer);
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index 14af823..6d87321 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -84,6 +84,13 @@
struct PixelFormatInfo
{
+ enum {
+ INDEX_ALPHA = 0,
+ INDEX_RED = 1,
+ INDEX_GREEN = 2,
+ INDEX_BLUE = 3
+ };
+
enum { // components
ALPHA = 1,
RGB = 2,
@@ -95,20 +102,33 @@
Y_CB_CR_I = 8,
};
+ struct szinfo {
+ uint8_t h;
+ uint8_t l;
+ };
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
+ size_t getSize(size_t ci) const {
+ return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
+ }
size_t version;
PixelFormat format;
size_t bytesPerPixel;
size_t bitsPerPixel;
- uint8_t h_alpha;
- uint8_t l_alpha;
- uint8_t h_red;
- uint8_t l_red;
- uint8_t h_green;
- uint8_t l_green;
- uint8_t h_blue;
- uint8_t l_blue;
+ union {
+ szinfo cinfo[4];
+ struct {
+ uint8_t h_alpha;
+ uint8_t l_alpha;
+ uint8_t h_red;
+ uint8_t l_red;
+ uint8_t h_green;
+ uint8_t l_green;
+ uint8_t h_blue;
+ uint8_t l_blue;
+ };
+ };
uint8_t components;
uint8_t reserved0[3];
uint32_t reserved1;
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index da72944..a213c09 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -30,6 +30,8 @@
int right;
int bottom;
+ typedef int value_type;
+
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
@@ -46,7 +48,11 @@
}
void makeInvalid();
-
+
+ inline void clear() {
+ left = top = right = bottom = 0;
+ }
+
// a valid rectangle has a non negative width and height
inline bool isValid() const {
return (width()>=0) && (height()>=0);
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 7689673..2bcad5b 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -21,14 +21,12 @@
#include <sys/types.h>
#include <utils/Vector.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/Rect.h>
#include <hardware/copybit.h>
-#include <core/SkRegion.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -40,7 +38,6 @@
public:
Region();
Region(const Region& rhs);
- explicit Region(const SkRegion& rhs);
explicit Region(const Rect& rhs);
explicit Region(const Parcel& parcel);
explicit Region(const void* buffer);
@@ -48,65 +45,78 @@
Region& operator = (const Region& rhs);
- inline bool isEmpty() const { return mRegion.isEmpty(); }
- inline bool isRect() const { return mRegion.isRect(); }
+ inline bool isEmpty() const { return mBounds.isEmpty(); }
+ inline bool isRect() const { return mStorage.isEmpty(); }
- Rect bounds() const;
+ inline Rect getBounds() const { return mBounds; }
+ inline Rect bounds() const { return getBounds(); }
- const SkRegion& toSkRegion() const;
-
+ // the region becomes its bounds
+ Region& makeBoundsSelf();
+
void clear();
void set(const Rect& r);
+ void set(uint32_t w, uint32_t h);
Region& orSelf(const Rect& rhs);
Region& andSelf(const Rect& rhs);
+ Region& subtractSelf(const Rect& rhs);
// boolean operators, applied on this
Region& orSelf(const Region& rhs);
Region& andSelf(const Region& rhs);
Region& subtractSelf(const Region& rhs);
+ // boolean operators
+ const Region merge(const Rect& rhs) const;
+ const Region intersect(const Rect& rhs) const;
+ const Region subtract(const Rect& rhs) const;
+
+ // boolean operators
+ const Region merge(const Region& rhs) const;
+ const Region intersect(const Region& rhs) const;
+ const Region subtract(const Region& rhs) const;
+
// these translate rhs first
Region& translateSelf(int dx, int dy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
- // boolean operators
- Region merge(const Region& rhs) const;
- Region intersect(const Region& rhs) const;
- Region subtract(const Region& rhs) const;
-
// these translate rhs first
- Region translate(int dx, int dy) const;
- Region merge(const Region& rhs, int dx, int dy) const;
- Region intersect(const Region& rhs, int dx, int dy) const;
- Region subtract(const Region& rhs, int dx, int dy) const;
+ const Region translate(int dx, int dy) const;
+ const Region merge(const Region& rhs, int dx, int dy) const;
+ const Region intersect(const Region& rhs, int dx, int dy) const;
+ const Region subtract(const Region& rhs, int dx, int dy) const;
// convenience operators overloads
- inline Region operator | (const Region& rhs) const;
- inline Region operator & (const Region& rhs) const;
- inline Region operator - (const Region& rhs) const;
- inline Region operator + (const Point& pt) const;
+ inline const Region operator | (const Region& rhs) const;
+ inline const Region operator & (const Region& rhs) const;
+ inline const Region operator - (const Region& rhs) const;
+ inline const Region operator + (const Point& pt) const;
inline Region& operator |= (const Region& rhs);
inline Region& operator &= (const Region& rhs);
inline Region& operator -= (const Region& rhs);
inline Region& operator += (const Point& pt);
- class iterator {
- SkRegion::Iterator mIt;
- public:
- iterator(const Region& r);
- inline operator bool () const { return !done(); }
- int iterate(Rect* rect);
- private:
- inline bool done() const {
- return const_cast<SkRegion::Iterator&>(mIt).done();
- }
- };
+
+ /* various ways to access the rectangle list */
+
+ typedef Rect const* const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
- size_t rects(Vector<Rect>& rectList) const;
+ /* no user serviceable parts here... */
+
+ size_t getRects(Vector<Rect>& rectList) const;
+ Rect const* getArray(size_t* count) const;
+
+
+ // add a rectangle to the internal list. This rectangle must
+ // be sorted in Y and X and must not make the region invalid.
+ void addRectUnchecked(int l, int t, int r, int b);
// flatten/unflatten a region to/from a Parcel
status_t write(Parcel& parcel) const;
@@ -123,20 +133,46 @@
void dump(const char* what, uint32_t flags=0) const;
private:
- SkRegion mRegion;
+ class rasterizer;
+ friend class rasterizer;
+
+ Region& operationSelf(const Rect& r, int op);
+ Region& operationSelf(const Region& r, int op);
+ Region& operationSelf(const Region& r, int dx, int dy, int op);
+ const Region operation(const Rect& rhs, int op) const;
+ const Region operation(const Region& rhs, int op) const;
+ const Region operation(const Region& rhs, int dx, int dy, int op) const;
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs, int dx, int dy);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs, int dx, int dy);
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs);
+
+ static void translate(Region& reg, int dx, int dy);
+ static void translate(Region& dst, const Region& reg, int dx, int dy);
+
+ static bool validate(const Region& reg, const char* name);
+
+ Rect mBounds;
+ Vector<Rect> mStorage;
};
-Region Region::operator | (const Region& rhs) const {
+const Region Region::operator | (const Region& rhs) const {
return merge(rhs);
}
-Region Region::operator & (const Region& rhs) const {
+const Region Region::operator & (const Region& rhs) const {
return intersect(rhs);
}
-Region Region::operator - (const Region& rhs) const {
+const Region Region::operator - (const Region& rhs) const {
return subtract(rhs);
}
-Region Region::operator + (const Point& pt) const {
+const Region Region::operator + (const Point& pt) const {
return translate(pt.x, pt.y);
}
@@ -157,16 +193,23 @@
// ---------------------------------------------------------------------------
struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region) : i(region) {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
this->next = iterate;
}
private:
static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- return static_cast<const region_iterator*>(self)
- ->i.iterate(reinterpret_cast<Rect*>(rect));
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
}
- mutable Region::iterator i;
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
};
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 33953a9..30ab82f 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -28,48 +28,41 @@
#include <ui/Region.h>
#include <ui/ISurfaceFlingerClient.h>
+#include <ui/egl/android_natives.h>
+
namespace android {
// ---------------------------------------------------------------------------
+class BufferMapper;
+class IOMX;
class Rect;
+class Surface;
class SurfaceComposerClient;
+struct per_client_cblk_t;
+struct layer_cblk_t;
-class Surface : public RefBase
+// ---------------------------------------------------------------------------
+
+class SurfaceControl : public RefBase
{
-
public:
- struct SurfaceInfo {
- uint32_t w;
- uint32_t h;
- uint32_t bpr;
- PixelFormat format;
- void* bits;
- void* base;
- uint32_t reserved[2];
- };
-
- bool isValid() const { return this && mToken>=0 && mClient!=0; }
+ static bool isValid(const sp<SurfaceControl>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+ bool isValid() {
+ return mToken>=0 && mClient!=0;
+ }
+ static bool isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
+
SurfaceID ID() const { return mToken; }
-
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
- status_t unlockAndPost();
- status_t unlock();
-
- void* heapBase(int i) const;
uint32_t getFlags() const { return mFlags; }
+ uint32_t getIdentity() const { return mIdentity; }
- // setSwapRectangle() is mainly used by EGL
- void setSwapRectangle(const Rect& r);
- const Rect& swapRectangle() const;
- status_t nextBuffer(SurfaceInfo* info);
-
- sp<Surface> dup() const;
- static sp<Surface> readFromParcel(Parcel* parcel);
- static status_t writeToParcel(const sp<Surface>& surface, Parcel* parcel);
- static bool isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs);
-
+ // release surface data from java
+ void clear();
+
status_t setLayer(int32_t layer);
status_t setPosition(int32_t x, int32_t y);
status_t setSize(uint32_t w, uint32_t h);
@@ -83,8 +76,17 @@
status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
status_t setFreezeTint(uint32_t tint);
- uint32_t getIdentity() const { return mIdentity; }
+ static status_t writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel);
+
+ sp<Surface> getSurface() const;
+
private:
+ // can't be copied
+ SurfaceControl& operator = (SurfaceControl& rhs);
+ SurfaceControl(const SurfaceControl& rhs);
+
+
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
@@ -92,42 +94,157 @@
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
+ // for testing
friend class Test;
const sp<ISurface>& getISurface() const { return mSurface; }
+
+ friend class Surface;
+
+ SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::surface_data_t& data,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ ~SurfaceControl();
+
+ status_t validate(per_client_cblk_t const* cblk) const;
+ void destroy();
+
+ sp<SurfaceComposerClient> mClient;
+ sp<ISurface> mSurface;
+ SurfaceID mToken;
+ uint32_t mIdentity;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ mutable Mutex mLock;
+
+ mutable sp<Surface> mSurfaceData;
+};
+
+// ---------------------------------------------------------------------------
+
+class Surface
+ : public EGLNativeBase<android_native_window_t, Surface, RefBase>
+{
+public:
+ struct SurfaceInfo {
+ uint32_t w;
+ uint32_t h;
+ uint32_t s;
+ uint32_t usage;
+ PixelFormat format;
+ void* bits;
+ uint32_t reserved[2];
+ };
+
+ Surface(const Parcel& data);
+
+ static bool isValid(const sp<Surface>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+
+ static bool isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs);
+
+ 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();
+
+ // setSwapRectangle() is intended to be used by GL ES clients
+ void setSwapRectangle(const Rect& r);
+
+private:
// can't be copied
Surface& operator = (Surface& rhs);
Surface(const Surface& rhs);
- Surface(const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner = true);
+ Surface(const sp<SurfaceControl>& control);
+ void init();
+ ~Surface();
+
+ friend class SurfaceComposerClient;
+ friend class SurfaceControl;
- Surface(Surface const* rhs);
+
+ // 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 IOMX;
+ // this is just to be able to write some unit tests
+ friend class Test;
- ~Surface();
+ sp<SurfaceComposerClient> getClient() const;
+ sp<ISurface> getISurface() const;
- Region dirtyRegion() const;
- void setDirtyRegion(const Region& region) const;
+ status_t getBufferLocked(int index, int usage);
+
+ status_t validate(per_client_cblk_t const* cblk) const;
+ static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
- // this locks protects calls to lockSurface() / unlockSurface()
- // and is called by SurfaceComposerClient.
- Mutex& getLock() const { return mSurfaceLock; }
+ inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline BufferMapper& getBufferMapper() { return mBufferMapper; }
+
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+ int dequeueBuffer(android_native_buffer_t** buffer);
+ int lockBuffer(android_native_buffer_t* buffer);
+ int queueBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value);
+ int perform(int operation, va_list args);
+
+ status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
+ status_t lockBuffer(const sp<SurfaceBuffer>& buffer);
+ status_t queueBuffer(const sp<SurfaceBuffer>& buffer);
+
+
+ void setUsage(uint32_t reqUsage);
+
+ // constants
sp<SurfaceComposerClient> mClient;
sp<ISurface> mSurface;
- sp<IMemoryHeap> mHeap[2];
SurfaceID mToken;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
- const bool mOwner;
- mutable void* mSurfaceHeapBase[2];
+ 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 Rect mSwapRectangle;
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;
};
diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h
index 76a3b55..286f885 100644
--- a/include/ui/SurfaceComposerClient.h
+++ b/include/ui/SurfaceComposerClient.h
@@ -62,7 +62,7 @@
// surface creation / destruction
//! Create a surface
- sp<Surface> createSurface(
+ sp<SurfaceControl> createSurface(
int pid, //!< pid of the process the surfacec is for
DisplayID display, //!< Display to create this surface on
uint32_t w, //!< width in pixel
@@ -111,51 +111,35 @@
private:
friend class Surface;
+ friend class SurfaceControl;
SurfaceComposerClient(const sp<ISurfaceComposer>& sm,
const sp<IBinder>& conn);
- status_t hide(Surface* surface);
- status_t show(Surface* surface, int32_t layer = -1);
- status_t freeze(Surface* surface);
- status_t unfreeze(Surface* surface);
- status_t setFlags(Surface* surface, uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(Surface* surface, const Region& transparent);
- status_t setLayer(Surface* surface, int32_t layer);
- status_t setAlpha(Surface* surface, float alpha=1.0f);
- status_t setFreezeTint(Surface* surface, uint32_t tint);
- status_t setMatrix(Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy);
- status_t setPosition(Surface* surface, int32_t x, int32_t y);
- status_t setSize(Surface* surface, uint32_t w, uint32_t h);
+ status_t hide(SurfaceID id);
+ status_t show(SurfaceID id, int32_t layer = -1);
+ status_t freeze(SurfaceID id);
+ status_t unfreeze(SurfaceID id);
+ status_t setFlags(SurfaceID id, uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(SurfaceID id, const Region& transparent);
+ status_t setLayer(SurfaceID id, int32_t layer);
+ status_t setAlpha(SurfaceID id, float alpha=1.0f);
+ status_t setFreezeTint(SurfaceID id, uint32_t tint);
+ status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setPosition(SurfaceID id, int32_t x, int32_t y);
+ status_t setSize(SurfaceID id, uint32_t w, uint32_t h);
- //! Unlock the surface, and specify the dirty region if any
- status_t unlockAndPostSurface(Surface* surface);
- status_t unlockSurface(Surface* surface);
-
- status_t lockSurface(Surface* surface,
- Surface::SurfaceInfo* info,
- Region* dirty,
- bool blocking = true);
-
- status_t nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info);
+ void signalServer();
status_t destroySurface(SurfaceID sid);
void _init(const sp<ISurfaceComposer>& sm,
const sp<ISurfaceFlingerClient>& conn);
- void _signal_server();
- static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
- inline layer_state_t* _get_state_l(const sp<Surface>& surface);
- layer_state_t* _lockLayerState(const sp<Surface>& surface);
+ inline layer_state_t* _get_state_l(SurfaceID id);
+ layer_state_t* _lockLayerState(SurfaceID id);
inline void _unlockLayerState();
- status_t validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface);
-
- void pinHeap(const sp<IMemoryHeap>& heap);
-
mutable Mutex mLock;
layer_state_t* mPrebuiltLayerState;
SortedVector<layer_state_t> mStates;
@@ -165,11 +149,8 @@
// after assignment
status_t mStatus;
per_client_cblk_t* mControl;
- sp<IMemory> mControlMemory;
+ sp<IMemoryHeap> mControlMemory;
sp<ISurfaceFlingerClient> mClient;
- sp<IMemoryHeap> mSurfaceHeap;
- uint8_t* mSurfaceHeapBase;
- void* mGL;
SurfaceFlingerSynchro* mSignalServer;
};
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
new file mode 100644
index 0000000..3740db5
--- /dev/null
+++ b/include/ui/egl/android_natives.h
@@ -0,0 +1,263 @@
+/*
+ * 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 ANDROID_ANDROID_NATIVES_H
+#define ANDROID_ANDROID_NATIVES_H
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <hardware/gralloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+ (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
+
+#define ANDROID_NATIVE_WINDOW_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+#define ANDROID_NATIVE_BUFFER_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+// ---------------------------------------------------------------------------
+
+struct android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_base_t
+{
+ /* a magic value defined by the actual EGL native type */
+ int magic;
+
+ /* the sizeof() of the actual EGL native type */
+ int version;
+
+ void* reserved[4];
+
+ /* reference-counting interface */
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+ NATIVE_WINDOW_WIDTH = 0,
+ NATIVE_WINDOW_HEIGHT = 1,
+ NATIVE_WINDOW_FORMAT = 2,
+};
+
+/* valid operations for the (*perform)() hook */
+enum {
+ NATIVE_WINDOW_SET_USAGE = 0
+};
+
+typedef struct android_native_window_t
+{
+#ifdef __cplusplus
+ android_native_window_t()
+ : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+ {
+ common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+ common.version = sizeof(android_native_window_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ /* flags describing some attributes of this surface or its updater */
+ const uint32_t flags;
+
+ /* min swap interval supported by this updated */
+ const int minSwapInterval;
+
+ /* max swap interval supported by this updated */
+ const int maxSwapInterval;
+
+ /* horizontal and vertical resolution in DPI */
+ const float xdpi;
+ const float ydpi;
+
+ /* Some storage reserved for the OEM's driver. */
+ intptr_t oem[4];
+
+
+ /*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*setSwapInterval)(struct android_native_window_t* window,
+ int interval);
+
+ /*
+ * hook called by EGL to acquire a buffer. After this call, the buffer
+ * is not locked, so its content cannot be modified.
+ * this call may block if no buffers are available.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*dequeueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t** buffer);
+
+ /*
+ * hook called by EGL to lock a buffer. This MUST be called before modifying
+ * the content of a buffer. The buffer must have been acquired with
+ * dequeueBuffer first.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ 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.
+ * This unlocks and post the buffer.
+ *
+ * Buffers MUST be queued in the same order than they were dequeued.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*queueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t* buffer);
+
+ /*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*query)(struct android_native_window_t* window,
+ int what, int* value);
+
+ /*
+ * hook used to perform various operations on the surface.
+ * (*perform)() is a generic mechanism to add functionality to
+ * android_native_window_t while keeping backward binary compatibility.
+ *
+ * This hook should not be called directly, instead use the helper functions
+ * defined below.
+ *
+ * The valid operations are:
+ * NATIVE_WINDOW_SET_USAGE
+ *
+ */
+
+ int (*perform)(struct android_native_window_t* window,
+ int operation, ... );
+
+ void* reserved_proc[3];
+} android_native_window_t;
+
+
+/*
+ * native_window_set_usage() sets the intended usage flags for the next
+ * buffers acquired with (*lockBuffer)() and on.
+ * By default (if this function is never called), a usage of
+ * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ * is assumed.
+ * Calling this function will usually cause following buffers to be
+ * reallocated.
+ */
+
+static inline int native_window_set_usage(
+ android_native_window_t* window, int usage)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+
+// ---------------------------------------------------------------------------
+
+/* FIXME: this is legacy for pixmaps */
+typedef struct egl_native_pixmap_t
+{
+ int32_t version; /* must be 32 */
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t* data;
+ uint8_t format;
+ uint8_t rfu[3];
+ union {
+ uint32_t compressedFormat;
+ int32_t vstride;
+ };
+ int32_t reserved;
+} egl_native_pixmap_t;
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/*
+ * This helper class turns an EGL android_native_xxx type into a C++
+ * reference-counted object; with proper type conversions.
+ */
+template <typename NATIVE_TYPE, typename TYPE, typename REF>
+class EGLNativeBase : public NATIVE_TYPE, public REF
+{
+protected:
+ typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE;
+ EGLNativeBase() : NATIVE_TYPE(), REF() {
+ NATIVE_TYPE::common.incRef = incRef;
+ NATIVE_TYPE::common.decRef = decRef;
+ }
+ static inline TYPE* getSelf(NATIVE_TYPE* self) {
+ return static_cast<TYPE*>(self);
+ }
+ static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
+ return static_cast<TYPE const *>(self);
+ }
+ static inline TYPE* getSelf(android_native_base_t* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));
+ }
+ static inline TYPE const * getSelf(android_native_base_t const* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));
+ }
+ static void incRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->incStrong(self);
+ }
+ static void decRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->decStrong(self);
+ }
+};
+
+} // namespace android
+#endif // __cplusplus
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_H */
diff --git a/include/utils.h b/include/utils.h
deleted file mode 100644
index 30648b1..0000000
--- a/include/utils.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Handy utility functions and portability code. This file includes all
-// of the generally-useful headers in the "utils" directory.
-//
-#ifndef _LIBS_UTILS_H
-#define _LIBS_UTILS_H
-
-#include <utils/ported.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/List.h>
-#include <utils/string_array.h>
-#include <utils/misc.h>
-#include <utils/Errors.h>
-
-#endif // _LIBS_UTILS_H
diff --git a/include/utils/Binder.h b/include/utils/Binder.h
deleted file mode 100644
index b5b8d98..0000000
--- a/include/utils/Binder.h
+++ /dev/null
@@ -1,103 +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.
- */
-
-#ifndef ANDROID_BINDER_H
-#define ANDROID_BINDER_H
-
-#include <utils/IBinder.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder : public IBinder
-{
-public:
- BBinder();
-
- virtual String16 getInterfaceDescriptor() const;
- virtual bool isBinderAlive() const;
- virtual status_t pingBinder();
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0);
-
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
-
- virtual BBinder* localBinder();
-
-protected:
- virtual ~BBinder();
-
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
-private:
- BBinder(const BBinder& o);
- BBinder& operator=(const BBinder& o);
-
- class Extras;
-
- Extras* mExtras;
- void* mReserved0;
-};
-
-// ---------------------------------------------------------------------------
-
-class BpRefBase : public virtual RefBase
-{
-protected:
- BpRefBase(const sp<IBinder>& o);
- virtual ~BpRefBase();
- virtual void onFirstRef();
- virtual void onLastStrongRef(const void* id);
- virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-
- inline IBinder* remote() { return mRemote; }
- inline IBinder* remote() const { return mRemote; }
-
-private:
- BpRefBase(const BpRefBase& o);
- BpRefBase& operator=(const BpRefBase& o);
-
- IBinder* const mRemote;
- RefBase::weakref_type* mRefs;
- volatile int32_t mState;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_BINDER_H
diff --git a/include/utils/BpBinder.h b/include/utils/BpBinder.h
deleted file mode 100644
index 7b96e29..0000000
--- a/include/utils/BpBinder.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_BPBINDER_H
-#define ANDROID_BPBINDER_H
-
-#include <utils/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BpBinder : public IBinder
-{
-public:
- BpBinder(int32_t handle);
-
- inline int32_t handle() const { return mHandle; }
-
- virtual String16 getInterfaceDescriptor() const;
- virtual bool isBinderAlive() const;
- virtual status_t pingBinder();
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0);
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
-
- virtual BpBinder* remoteBinder();
-
- status_t setConstantData(const void* data, size_t size);
- void sendObituary();
-
- class ObjectManager
- {
- public:
- ObjectManager();
- ~ObjectManager();
-
- void attach( const void* objectID,
- void* object,
- void* cleanupCookie,
- IBinder::object_cleanup_func func);
- void* find(const void* objectID) const;
- void detach(const void* objectID);
-
- void kill();
-
- private:
- ObjectManager(const ObjectManager&);
- ObjectManager& operator=(const ObjectManager&);
-
- struct entry_t
- {
- void* object;
- void* cleanupCookie;
- IBinder::object_cleanup_func func;
- };
-
- KeyedVector<const void*, entry_t> mObjects;
- };
-
-protected:
- virtual ~BpBinder();
- virtual void onFirstRef();
- virtual void onLastStrongRef(const void* id);
- virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-
-private:
- const int32_t mHandle;
-
- struct Obituary {
- wp<DeathRecipient> recipient;
- void* cookie;
- uint32_t flags;
- };
-
- void reportOneDeath(const Obituary& obit);
-
- mutable Mutex mLock;
- volatile int32_t mAlive;
- volatile int32_t mObitsSent;
- Vector<Obituary>* mObituaries;
- ObjectManager mObjects;
- Parcel* mConstantData;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_BPBINDER_H
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
index a662b9c..d9ed32d 100644
--- a/include/utils/Debug.h
+++ b/include/utils/Debug.h
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-//
-// Debugging tools. These should be able to be stripped
-// in release builds.
-//
#ifndef ANDROID_DEBUG_H
#define ANDROID_DEBUG_H
@@ -25,9 +21,32 @@
#include <sys/types.h>
namespace android {
+// ---------------------------------------------------------------------------
+#ifdef __cplusplus
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
+#define COMPILE_TIME_ASSERT(_exp) \
+ template class CompileTimeAssert< (_exp) >;
+#endif
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
+ CompileTimeAssert<( _exp )>();
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+template<bool C, typename LSH, typename RHS> struct CompileTimeIfElse;
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<true, LHS, RHS> { typedef LHS TYPE; };
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; };
+#endif
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
const char* stringForIndent(int32_t indentLevel);
@@ -35,11 +54,17 @@
void printTypeCode(uint32_t typeCode,
debugPrintFunc func = 0, void* cookie = 0);
+
void printHexData(int32_t indent, const void *buf, size_t length,
size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
size_t alignment=0, bool cArrayStyle=false,
debugPrintFunc func = 0, void* cookie = 0);
+#ifdef __cplusplus
+}
+#endif
+
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_DEBUG_H
diff --git a/include/utils/IBinder.h b/include/utils/IBinder.h
deleted file mode 100644
index 7370330..0000000
--- a/include/utils/IBinder.h
+++ /dev/null
@@ -1,159 +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.
- */
-
-#ifndef ANDROID_IBINDER_H
-#define ANDROID_IBINDER_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-
-#define B_PACK_CHARS(c1, c2, c3, c4) \
- ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder;
-class BpBinder;
-class IInterface;
-class Parcel;
-
-/**
- * Base class and low-level protocol for a remotable object.
- * You can derive from this class to create an object for which other
- * processes can hold references to it. Communication between processes
- * (method calls, property get and set) is down through a low-level
- * protocol implemented on top of the transact() API.
- */
-class IBinder : public virtual RefBase
-{
-public:
- enum {
- FIRST_CALL_TRANSACTION = 0x00000001,
- LAST_CALL_TRANSACTION = 0x00ffffff,
-
- PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
- DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
- INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
-
- // Corresponds to tfOneWay -- an asynchronous call.
- FLAG_ONEWAY = 0x00000001
- };
-
- inline IBinder() { }
-
- /**
- * Check if this IBinder implements the interface named by
- * @a descriptor. If it does, the base pointer to it is returned,
- * which you can safely static_cast<> to the concrete C++ interface.
- */
- virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
-
- /**
- * Return the canonical name of the interface provided by this IBinder
- * object.
- */
- virtual String16 getInterfaceDescriptor() const = 0;
-
- virtual bool isBinderAlive() const = 0;
- virtual status_t pingBinder() = 0;
- virtual status_t dump(int fd, const Vector<String16>& args) = 0;
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0) = 0;
-
- /**
- * This method allows you to add data that is transported through
- * IPC along with your IBinder pointer. When implementing a Binder
- * object, override it to write your desired data in to @a outData.
- * You can then call getConstantData() on your IBinder to retrieve
- * that data, from any process. You MUST return the number of bytes
- * written in to the parcel (including padding).
- */
- class DeathRecipient : public virtual RefBase
- {
- public:
- virtual void binderDied(const wp<IBinder>& who) = 0;
- };
-
- /**
- * Register the @a recipient for a notification if this binder
- * goes away. If this binder object unexpectedly goes away
- * (typically because its hosting process has been killed),
- * then DeathRecipient::binderDied() will be called with a referene
- * to this.
- *
- * The @a cookie is optional -- if non-NULL, it should be a
- * memory address that you own (that is, you know it is unique).
- *
- * @note You will only receive death notifications for remote binders,
- * as local binders by definition can't die without you dying as well.
- * Trying to use this function on a local binder will result in an
- * INVALID_OPERATION code being returned and nothing happening.
- *
- * @note This link always holds a weak reference to its recipient.
- *
- * @note You will only receive a weak reference to the dead
- * binder. You should not try to promote this to a strong reference.
- * (Nor should you need to, as there is nothing useful you can
- * directly do with it now that it has passed on.)
- */
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0) = 0;
-
- /**
- * Remove a previously registered death notification.
- * The @a recipient will no longer be called if this object
- * dies. The @a cookie is optional. If non-NULL, you can
- * supply a NULL @a recipient, and the recipient previously
- * added with that cookie will be unlinked.
- */
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL) = 0;
-
- virtual bool checkSubclass(const void* subclassID) const;
-
- typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) = 0;
- virtual void* findObject(const void* objectID) const = 0;
- virtual void detachObject(const void* objectID) = 0;
-
- virtual BBinder* localBinder();
- virtual BpBinder* remoteBinder();
-
-protected:
- inline virtual ~IBinder() { }
-
-private:
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IBINDER_H
diff --git a/include/utils/IInterface.h b/include/utils/IInterface.h
deleted file mode 100644
index 959722a..0000000
--- a/include/utils/IInterface.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_IINTERFACE_H
-#define ANDROID_IINTERFACE_H
-
-#include <utils/Binder.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IInterface : public virtual RefBase
-{
-public:
- sp<IBinder> asBinder();
- sp<const IBinder> asBinder() const;
-
-protected:
- virtual IBinder* onAsBinder() = 0;
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
-{
- return INTERFACE::asInterface(obj);
-}
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BnInterface : public INTERFACE, public BBinder
-{
-public:
- virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
-
-protected:
- virtual IBinder* onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BpInterface : public INTERFACE, public BpRefBase
-{
-public:
- BpInterface(const sp<IBinder>& remote);
-
-protected:
- virtual IBinder* onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-#define DECLARE_META_INTERFACE(INTERFACE) \
- static const String16 descriptor; \
- static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
- virtual String16 getInterfaceDescriptor() const; \
-
-#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
- const String16 I##INTERFACE::descriptor(NAME); \
- String16 I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
- { \
- sp<I##INTERFACE> intr; \
- if (obj != NULL) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
- if (intr == NULL) { \
- intr = new Bp##INTERFACE(obj); \
- } \
- } \
- return intr; \
- } \
-
-// ----------------------------------------------------------------------
-// No user-servicable parts after this...
-
-template<typename INTERFACE>
-inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
- const String16& _descriptor)
-{
- if (_descriptor == INTERFACE::descriptor) return this;
- return NULL;
-}
-
-template<typename INTERFACE>
-inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
-{
- return INTERFACE::getInterfaceDescriptor();
-}
-
-template<typename INTERFACE>
-IBinder* BnInterface<INTERFACE>::onAsBinder()
-{
- return this;
-}
-
-template<typename INTERFACE>
-inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
- : BpRefBase(remote)
-{
-}
-
-template<typename INTERFACE>
-inline IBinder* BpInterface<INTERFACE>::onAsBinder()
-{
- return remote();
-}
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IINTERFACE_H
diff --git a/include/utils/IMemory.h b/include/utils/IMemory.h
deleted file mode 100644
index 35a3fd7..0000000
--- a/include/utils/IMemory.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_IMEMORY_H
-#define ANDROID_IMEMORY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IMemoryHeap : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MemoryHeap);
-
- // flags returned by getFlags()
- enum {
- READ_ONLY = 0x00000001,
- MAP_ONCE = 0x00000002
- };
-
- virtual int getHeapID() const = 0;
- virtual void* getBase() const = 0;
- virtual size_t getSize() const = 0;
- virtual uint32_t getFlags() const = 0;
-
- // these are there just for backward source compatibility
- int32_t heapID() const { return getHeapID(); }
- void* base() const { return getBase(); }
- size_t virtualSize() const { return getSize(); }
-};
-
-class BnMemoryHeap : public BnInterface<IMemoryHeap>
-{
-public:
- virtual status_t onTransact(
- uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-class IMemory : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(Memory);
-
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
-
- // helpers
- void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
- void* pointer() const;
- size_t size() const;
- ssize_t offset() const;
-};
-
-class BnMemory : public BnInterface<IMemory>
-{
-public:
- virtual status_t onTransact(
- uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IMEMORY_H
diff --git a/include/utils/IPCThreadState.h b/include/utils/IPCThreadState.h
deleted file mode 100644
index 0490fd3..0000000
--- a/include/utils/IPCThreadState.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_IPC_THREAD_STATE_H
-#define ANDROID_IPC_THREAD_STATE_H
-
-#include <utils/Errors.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/Vector.h>
-
-#ifdef HAVE_WIN32_PROC
-typedef int uid_t;
-#endif
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IPCThreadState
-{
-public:
- static IPCThreadState* self();
-
- sp<ProcessState> process();
-
- status_t clearLastError();
-
- int getCallingPid();
- int getCallingUid();
-
- int64_t clearCallingIdentity();
- void restoreCallingIdentity(int64_t token);
-
- void flushCommands();
-
- void joinThreadPool(bool isMain = true);
-
- // Stop the local process.
- void stopProcess(bool immediate = true);
-
- status_t transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
- void incStrongHandle(int32_t handle);
- void decStrongHandle(int32_t handle);
- void incWeakHandle(int32_t handle);
- void decWeakHandle(int32_t handle);
- status_t attemptIncStrongHandle(int32_t handle);
- static void expungeHandle(int32_t handle, IBinder* binder);
- status_t requestDeathNotification( int32_t handle,
- BpBinder* proxy);
- status_t clearDeathNotification( int32_t handle,
- BpBinder* proxy);
-
- static void shutdown();
-
-private:
- IPCThreadState();
- ~IPCThreadState();
-
- status_t sendReply(const Parcel& reply, uint32_t flags);
- status_t waitForResponse(Parcel *reply,
- status_t *acquireResult=NULL);
- status_t talkWithDriver(bool doReceive=true);
- status_t writeTransactionData(int32_t cmd,
- uint32_t binderFlags,
- int32_t handle,
- uint32_t code,
- const Parcel& data,
- status_t* statusBuffer);
- status_t executeCommand(int32_t command);
-
- void clearCaller();
-
- static void threadDestructor(void *st);
- static void freeBuffer(Parcel* parcel,
- const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie);
-
- const sp<ProcessState> mProcess;
- Vector<BBinder*> mPendingStrongDerefs;
- Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
- Parcel mIn;
- Parcel mOut;
- status_t mLastError;
- pid_t mCallingPid;
- uid_t mCallingUid;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/utils/IPermissionController.h b/include/utils/IPermissionController.h
deleted file mode 100644
index cb1dd34..0000000
--- a/include/utils/IPermissionController.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_IPERMISSION_CONTROLLER_H
-#define ANDROID_IPERMISSION_CONTROLLER_H
-
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IPermissionController : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(PermissionController);
-
- virtual bool checkPermission(const String16& permission,
- int32_t pid, int32_t uid) = 0;
-
- enum {
- CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
- };
-};
-
-// ----------------------------------------------------------------------
-
-class BnPermissionController : public BnInterface<IPermissionController>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPERMISSION_CONTROLLER_H
-
diff --git a/include/utils/IServiceManager.h b/include/utils/IServiceManager.h
deleted file mode 100644
index e3d99fe..0000000
--- a/include/utils/IServiceManager.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_ISERVICE_MANAGER_H
-#define ANDROID_ISERVICE_MANAGER_H
-
-#include <utils/IInterface.h>
-#include <utils/IPermissionController.h>
-#include <utils/Vector.h>
-#include <utils/String16.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IServiceManager : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ServiceManager);
-
- /**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
- */
- virtual sp<IBinder> getService( const String16& name) const = 0;
-
- /**
- * Retrieve an existing service, non-blocking.
- */
- virtual sp<IBinder> checkService( const String16& name) const = 0;
-
- /**
- * Register a service.
- */
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
-
- /**
- * Return list of all existing services.
- */
- virtual Vector<String16> listServices() = 0;
-
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
-};
-
-sp<IServiceManager> defaultServiceManager();
-
-template<typename INTERFACE>
-status_t getService(const String16& name, sp<INTERFACE>* outService)
-{
- const sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- *outService = interface_cast<INTERFACE>(sm->getService(name));
- if ((*outService) != NULL) return NO_ERROR;
- }
- return NAME_NOT_FOUND;
-}
-
-bool checkCallingPermission(const String16& permission);
-bool checkCallingPermission(const String16& permission,
- int32_t* outPid, int32_t* outUid);
-
-// ----------------------------------------------------------------------
-
-class BnServiceManager : public BnInterface<IServiceManager>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_ISERVICE_MANAGER_H
-
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index f4513ee..6bcdea4 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -164,7 +164,7 @@
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
if (index<size()) {
- mVector.editValueAt(index).value = item;
+ mVector.editItemAt(index).value = item;
return index;
}
return BAD_INDEX;
diff --git a/include/utils/List.h b/include/utils/List.h
index 1a6be9a..403cd7f 100644
--- a/include/utils/List.h
+++ b/include/utils/List.h
@@ -22,147 +22,200 @@
// construction, so if the compiler's auto-generated versions won't work for
// you, define your own.
//
-// The only class you want to use from here is "List". Do not use classes
-// starting with "_" directly.
+// The only class you want to use from here is "List".
//
#ifndef _LIBS_UTILS_LIST_H
#define _LIBS_UTILS_LIST_H
+#include <stddef.h>
+#include <stdint.h>
+
namespace android {
/*
- * One element in the list.
- */
-template<class T> class _ListNode {
-public:
- typedef _ListNode<T> _Node;
-
- _ListNode(const T& val) : mVal(val) {}
- ~_ListNode(void) {}
-
- T& getRef(void) { return mVal; }
- void setVal(const T& val) { mVal = val; }
-
- _Node* getPrev(void) const { return mpPrev; }
- void setPrev(_Node* ptr) { mpPrev = ptr; }
- _Node* getNext(void) const { return mpNext; }
- void setNext(_Node* ptr) { mpNext = ptr; }
-
-private:
- T mVal;
- _Node* mpPrev;
- _Node* mpNext;
-};
-
-/*
- * Iterator for walking through the list.
- */
-template<class T, class Tref> class _ListIterator {
-public:
- typedef _ListIterator<T,Tref> _Iter;
- typedef _ListNode<T> _Node;
-
- _ListIterator(void) {}
- _ListIterator(_Node* ptr) : mpNode(ptr) {}
- ~_ListIterator(void) {}
-
- /*
- * Dereference operator. Used to get at the juicy insides.
- */
- Tref operator*() const { return mpNode->getRef(); }
-
- /*
- * Iterator comparison.
- */
- bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
- bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
-
- /*
- * Incr/decr, used to move through the list.
- */
- _Iter& operator++(void) { // pre-increment
- mpNode = mpNode->getNext();
- return *this;
- }
- _Iter operator++(int) { // post-increment
- _Iter tmp = *this;
- ++*this;
- return tmp;
- }
- _Iter& operator--(void) { // pre-increment
- mpNode = mpNode->getPrev();
- return *this;
- }
- _Iter operator--(int) { // post-increment
- _Iter tmp = *this;
- --*this;
- return tmp;
- }
-
- _Node* getNode(void) const { return mpNode; }
-
-private:
- _Node* mpNode;
-};
-
-
-/*
* Doubly-linked list. Instantiate with "List<MyClass> myList".
*
* Objects added to the list are copied using the assignment operator,
* so this must be defined.
*/
-template<class T> class List {
-public:
- typedef _ListNode<T> _Node;
+template<typename T>
+class List
+{
+protected:
+ /*
+ * One element in the list.
+ */
+ class _Node {
+ public:
+ explicit _Node(const T& val) : mVal(val) {}
+ ~_Node() {}
+ inline T& getRef() { return mVal; }
+ inline const T& getRef() const { return mVal; }
+ inline _Node* getPrev() const { return mpPrev; }
+ inline _Node* getNext() const { return mpNext; }
+ inline void setVal(const T& val) { mVal = val; }
+ inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+ inline void setNext(_Node* ptr) { mpNext = ptr; }
+ private:
+ friend class List;
+ friend class _ListIterator;
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+ };
- List(void) {
+ /*
+ * Iterator for walking through the list.
+ */
+
+ template <typename TYPE>
+ struct CONST_ITERATOR {
+ typedef _Node const * NodePtr;
+ typedef const TYPE Type;
+ };
+
+ template <typename TYPE>
+ struct NON_CONST_ITERATOR {
+ typedef _Node* NodePtr;
+ typedef TYPE Type;
+ };
+
+ template<
+ typename U,
+ template <class> class Constness
+ >
+ class _ListIterator {
+ typedef _ListIterator<U, Constness> _Iter;
+ typedef typename Constness<U>::NodePtr _NodePtr;
+ typedef typename Constness<U>::Type _Type;
+
+ explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+ public:
+ _ListIterator() {}
+ _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+ ~_ListIterator() {}
+
+ // this will handle conversions from iterator to const_iterator
+ // (and also all convertible iterators)
+ // Here, in this implementation, the iterators can be converted
+ // if the nodes can be converted
+ template<typename V> explicit
+ _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ _Type& operator*() const { return mpNode->getRef(); }
+ _Type* operator->() const { return &(mpNode->getRef()); }
+
+ /*
+ * Iterator comparison.
+ */
+ inline bool operator==(const _Iter& right) const {
+ return mpNode == right.mpNode; }
+
+ inline bool operator!=(const _Iter& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * handle comparisons between iterator and const_iterator
+ */
+ template<typename OTHER>
+ inline bool operator==(const OTHER& right) const {
+ return mpNode == right.mpNode; }
+
+ template<typename OTHER>
+ inline bool operator!=(const OTHER& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ inline _Iter& operator++() { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ const _Iter operator++(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getNext();
+ return tmp;
+ }
+ inline _Iter& operator--() { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ const _Iter operator--(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getPrev();
+ return tmp;
+ }
+
+ inline _NodePtr getNode() const { return mpNode; }
+
+ _NodePtr mpNode; /* should be private, but older gcc fails */
+ private:
+ friend class List;
+ };
+
+public:
+ List() {
prep();
}
List(const List<T>& src) { // copy-constructor
prep();
insert(begin(), src.begin(), src.end());
}
- virtual ~List(void) {
+ virtual ~List() {
clear();
delete[] (unsigned char*) mpMiddle;
}
- typedef _ListIterator<T,T&> iterator;
- typedef _ListIterator<T, const T&> const_iterator;
+ typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+ typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
List<T>& operator=(const List<T>& right);
/* returns true if the list is empty */
- bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
+ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
/* return #of elements in list */
- unsigned int size(void) const {
- return distance(begin(), end());
+ size_t size() const {
+ return size_t(distance(begin(), end()));
}
/*
* Return the first element or one past the last element. The
- * _ListNode* we're returning is converted to an "iterator" by a
+ * _Node* we're returning is converted to an "iterator" by a
* constructor in _ListIterator.
*/
- iterator begin() { return mpMiddle->getNext(); }
- const_iterator begin() const { return mpMiddle->getNext(); }
- iterator end() { return mpMiddle; }
- const_iterator end() const { return mpMiddle; }
+ inline iterator begin() {
+ return iterator(mpMiddle->getNext());
+ }
+ inline const_iterator begin() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
+ }
+ inline iterator end() {
+ return iterator(mpMiddle);
+ }
+ inline const_iterator end() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle));
+ }
/* add the object to the head or tail of the list */
void push_front(const T& val) { insert(begin(), val); }
void push_back(const T& val) { insert(end(), val); }
/* insert before the current node; returns iterator at new node */
- iterator insert(iterator posn, const T& val) {
+ iterator insert(iterator posn, const T& val)
+ {
_Node* newNode = new _Node(val); // alloc & copy-construct
newNode->setNext(posn.getNode());
newNode->setPrev(posn.getNode()->getPrev());
posn.getNode()->getPrev()->setNext(newNode);
posn.getNode()->setPrev(newNode);
- return newNode;
+ return iterator(newNode);
}
/* insert a range of elements before the current node */
@@ -178,18 +231,18 @@
pPrev->setNext(pNext);
pNext->setPrev(pPrev);
delete posn.getNode();
- return pNext;
+ return iterator(pNext);
}
/* remove a range of elements */
iterator erase(iterator first, iterator last) {
while (first != last)
erase(first++); // don't erase than incr later!
- return last;
+ return iterator(last);
}
/* remove all contents of the list */
- void clear(void) {
+ void clear() {
_Node* pCurrent = mpMiddle->getNext();
_Node* pNext;
@@ -207,21 +260,20 @@
* will be equal to "last". The iterators must refer to the same
* list.
*
- * (This is actually a generic iterator function. It should be part
- * of some other class, possibly an iterator base class. It needs to
- * know the difference between a list, which has to march through,
- * and a vector, which can just do pointer math.)
+ * FIXME: This is actually a generic iterator function. It should be a
+ * template function at the top-level with specializations for things like
+ * vector<>, which can just do pointer math). Here we limit it to
+ * _ListIterator of the same type but different constness.
*/
- unsigned int distance(iterator first, iterator last) {
- unsigned int count = 0;
- while (first != last) {
- ++first;
- ++count;
- }
- return count;
- }
- unsigned int distance(const_iterator first, const_iterator last) const {
- unsigned int count = 0;
+ template<
+ typename U,
+ template <class> class CL,
+ template <class> class CR
+ >
+ ptrdiff_t distance(
+ _ListIterator<U, CL> first, _ListIterator<U, CR> last) const
+ {
+ ptrdiff_t count = 0;
while (first != last) {
++first;
++count;
@@ -231,12 +283,12 @@
private:
/*
- * I want a _ListNode but don't need it to hold valid data. More
+ * I want a _Node but don't need it to hold valid data. More
* to the point, I don't want T's constructor to fire, since it
* might have side-effects or require arguments. So, we do this
* slightly uncouth storage alloc.
*/
- void prep(void) {
+ void prep() {
mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
mpMiddle->setPrev(mpMiddle);
mpMiddle->setNext(mpMiddle);
diff --git a/include/utils/LogSocket.h b/include/utils/LogSocket.h
deleted file mode 100644
index 01fbfb5..0000000
--- a/include/utils/LogSocket.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* utils/LogSocket.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGSOCKET_H
-#define _UTILS_LOGSOCKET_H
-
-#define SOCKET_CLOSE_LOCAL 0
-
-void add_send_stats(int fd, int send);
-void add_recv_stats(int fd, int recv);
-void log_socket_close(int fd, short reason);
-void log_socket_connect(int fd, unsigned int ip, unsigned short port);
-
-#endif /* _UTILS_LOGSOCKET_H */
diff --git a/include/utils/MemoryBase.h b/include/utils/MemoryBase.h
deleted file mode 100644
index eb5a9d2..0000000
--- a/include/utils/MemoryBase.h
+++ /dev/null
@@ -1,51 +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.
- */
-
-#ifndef ANDROID_MEMORY_BASE_H
-#define ANDROID_MEMORY_BASE_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/IMemory.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class MemoryBase : public BnMemory
-{
-public:
- MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
- virtual ~MemoryBase();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
-
-protected:
- size_t getSize() const { return mSize; }
- ssize_t getOffset() const { return mOffset; }
- const sp<IMemoryHeap>& getHeap() const { return mHeap; }
-
-private:
- size_t mSize;
- ssize_t mOffset;
- sp<IMemoryHeap> mHeap;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/utils/MemoryDealer.h b/include/utils/MemoryDealer.h
deleted file mode 100644
index 454b627..0000000
--- a/include/utils/MemoryDealer.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_MEMORY_DEALER_H
-#define ANDROID_MEMORY_DEALER_H
-
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/MemoryHeapBase.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-class String8;
-
-/*
- * interface for implementing a "heap". A heap basically provides
- * the IMemoryHeap interface for cross-process sharing and the
- * ability to map/unmap pages within the heap.
- */
-class HeapInterface : public virtual BnMemoryHeap
-{
-public:
- // all values must be page-aligned
- virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * interface for implementing an allocator. An allocator provides
- * methods for allocating and freeing memory blocks and dumping
- * its state.
- */
-class AllocatorInterface : public RefBase
-{
-public:
- enum {
- PAGE_ALIGNED = 0x00000001
- };
-
- virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
- virtual status_t deallocate(size_t offset) = 0;
- virtual size_t size() const = 0;
- virtual void dump(const char* what, uint32_t flags = 0) const = 0;
- virtual void dump(String8& res,
- const char* what, uint32_t flags = 0) const = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * concrete implementation of HeapInterface on top of mmap()
- */
-class SharedHeap : public HeapInterface, public MemoryHeapBase
-{
-public:
- SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
- virtual ~SharedHeap();
- virtual sp<IMemory> mapMemory(size_t offset, size_t size);
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * A simple templatized doubly linked-list implementation
- */
-
-template <typename NODE>
-class LinkedList
-{
- NODE* mFirst;
- NODE* mLast;
-
-public:
- LinkedList() : mFirst(0), mLast(0) { }
- bool isEmpty() const { return mFirst == 0; }
- NODE const* head() const { return mFirst; }
- NODE* head() { return mFirst; }
- NODE const* tail() const { return mLast; }
- NODE* tail() { return mLast; }
-
- void insertAfter(NODE* node, NODE* newNode) {
- newNode->prev = node;
- newNode->next = node->next;
- if (node->next == 0) mLast = newNode;
- else node->next->prev = newNode;
- node->next = newNode;
- }
-
- void insertBefore(NODE* node, NODE* newNode) {
- newNode->prev = node->prev;
- newNode->next = node;
- if (node->prev == 0) mFirst = newNode;
- else node->prev->next = newNode;
- node->prev = newNode;
- }
-
- void insertHead(NODE* newNode) {
- if (mFirst == 0) {
- mFirst = mLast = newNode;
- newNode->prev = newNode->next = 0;
- } else {
- insertBefore(mFirst, newNode);
- }
- }
-
- void insertTail(NODE* newNode) {
- if (mLast == 0) insertBeginning(newNode);
- else insertAfter(mLast, newNode);
- }
-
- NODE* remove(NODE* node) {
- if (node->prev == 0) mFirst = node->next;
- else node->prev->next = node->next;
- if (node->next == 0) mLast = node->prev;
- else node->next->prev = node->prev;
- return node;
- }
-};
-
-
-/*
- * concrete implementation of AllocatorInterface using a simple
- * best-fit allocation scheme
- */
-class SimpleBestFitAllocator : public AllocatorInterface
-{
-public:
-
- SimpleBestFitAllocator(size_t size);
- virtual ~SimpleBestFitAllocator();
-
- virtual size_t allocate(size_t size, uint32_t flags = 0);
- virtual status_t deallocate(size_t offset);
- virtual size_t size() const;
- virtual void dump(const char* what, uint32_t flags = 0) const;
- virtual void dump(String8& res,
- const char* what, uint32_t flags = 0) const;
-
-private:
-
- struct chunk_t {
- chunk_t(size_t start, size_t size)
- : start(start), size(size), free(1), prev(0), next(0) {
- }
- size_t start;
- size_t size : 28;
- int free : 4;
- mutable chunk_t* prev;
- mutable chunk_t* next;
- };
-
- ssize_t alloc(size_t size, uint32_t flags);
- chunk_t* dealloc(size_t start);
- void dump_l(const char* what, uint32_t flags = 0) const;
- void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
-
- static const int kMemoryAlign;
- mutable Mutex mLock;
- LinkedList<chunk_t> mList;
- size_t mHeapSize;
-};
-
-// ----------------------------------------------------------------------------
-
-class MemoryDealer : public RefBase
-{
-public:
-
- enum {
- READ_ONLY = MemoryHeapBase::READ_ONLY,
- PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
- };
-
- // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
- MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
-
- // provide a custom heap but use the SimpleBestFitAllocator
- MemoryDealer(const sp<HeapInterface>& heap);
-
- // provide both custom heap and allocotar
- MemoryDealer(
- const sp<HeapInterface>& heap,
- const sp<AllocatorInterface>& allocator);
-
- virtual ~MemoryDealer();
-
- virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
- virtual void deallocate(size_t offset);
- virtual void dump(const char* what, uint32_t flags = 0) const;
-
-
- sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
- sp<AllocatorInterface> getAllocator() const { return allocator(); }
-
-private:
- const sp<HeapInterface>& heap() const;
- const sp<AllocatorInterface>& allocator() const;
-
- class Allocation : public BnMemory {
- public:
- Allocation(const sp<MemoryDealer>& dealer,
- ssize_t offset, size_t size, const sp<IMemory>& memory);
- virtual ~Allocation();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
- private:
- sp<MemoryDealer> mDealer;
- ssize_t mOffset;
- size_t mSize;
- sp<IMemory> mMemory;
- };
-
- sp<HeapInterface> mHeap;
- sp<AllocatorInterface> mAllocator;
-};
-
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/utils/MemoryHeapBase.h b/include/utils/MemoryHeapBase.h
deleted file mode 100644
index 574acf4..0000000
--- a/include/utils/MemoryHeapBase.h
+++ /dev/null
@@ -1,98 +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.
- */
-
-#ifndef ANDROID_MEMORY_HEAP_BASE_H
-#define ANDROID_MEMORY_HEAP_BASE_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/IMemory.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class MemoryHeapBase : public virtual BnMemoryHeap
-{
-public:
- enum {
- READ_ONLY = IMemoryHeap::READ_ONLY,
- MAP_ONCE = IMemoryHeap::MAP_ONCE,
- // memory won't be mapped locally, but will be mapped in the remote
- // process.
- DONT_MAP_LOCALLY = 0x00000100
- };
-
- /*
- * 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);
-
- /*
- * maps memory from the given device
- */
- MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
-
- /*
- * maps memory from ashmem, with the given name for debugging
- */
- MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
-
- virtual ~MemoryHeapBase();
-
- /* implement IMemoryHeap interface */
- virtual int getHeapID() const;
- virtual void* getBase() const;
- virtual size_t getSize() const;
- virtual uint32_t getFlags() const;
-
- const char* getDevice() const;
-
- /* this closes this heap -- use carefully */
- void dispose();
-
- /* this is only needed as a workaround, use only if you know
- * what you are doing */
- status_t setDevice(const char* device) {
- if (mDevice == 0)
- mDevice = device;
- return mDevice ? NO_ERROR : ALREADY_EXISTS;
- }
-
-protected:
- MemoryHeapBase();
- // init() takes ownership of fd
- status_t init(int fd, void *base, int size,
- int flags = 0, const char* device = NULL);
-
-private:
- status_t mapfd(int fd, size_t size);
-
- int mFD;
- size_t mSize;
- void* mBase;
- uint32_t mFlags;
- const char* mDevice;
- bool mNeedUnmap;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/utils/MemoryHeapPmem.h b/include/utils/MemoryHeapPmem.h
deleted file mode 100644
index 60335ad..0000000
--- a/include/utils/MemoryHeapPmem.h
+++ /dev/null
@@ -1,80 +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.
- */
-
-#ifndef ANDROID_MEMORY_HEAP_PMEM_H
-#define ANDROID_MEMORY_HEAP_PMEM_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IMemory.h>
-#include <utils/SortedVector.h>
-
-namespace android {
-
-class MemoryHeapBase;
-
-// ---------------------------------------------------------------------------
-
-class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
-{
-public:
- class MemoryPmem : public BnMemory {
- public:
- MemoryPmem(const sp<MemoryHeapPmem>& heap);
- ~MemoryPmem();
- protected:
- const sp<MemoryHeapPmem>& getHeap() const { return mClientHeap; }
- private:
- friend class MemoryHeapPmem;
- virtual void revoke() = 0;
- sp<MemoryHeapPmem> mClientHeap;
- };
-
- MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
- uint32_t flags = IMemoryHeap::MAP_ONCE);
- ~MemoryHeapPmem();
-
- /* HeapInterface additions */
- virtual sp<IMemory> mapMemory(size_t offset, size_t size);
-
- /* make the whole heap visible (you know who you are) */
- virtual status_t slap();
-
- /* hide (revoke) the whole heap (the client will see the garbage page) */
- virtual status_t unslap();
-
- /* revoke all allocations made by this heap */
- virtual void revoke();
-
-private:
- /* use this to create your own IMemory for mapMemory */
- virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
- void remove(const wp<MemoryPmem>& memory);
-
-private:
- sp<MemoryHeapBase> mParentHeap;
- mutable Mutex mLock;
- SortedVector< wp<MemoryPmem> > mAllocations;
-};
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h
deleted file mode 100644
index af1490a..0000000
--- a/include/utils/Parcel.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_PARCEL_H
-#define ANDROID_PARCEL_H
-
-#include <cutils/native_handle.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IBinder;
-class ProcessState;
-class String8;
-class TextOutput;
-
-struct flat_binder_object; // defined in support_p/binder_module.h
-
-class Parcel
-{
-public:
- Parcel();
- ~Parcel();
-
- const uint8_t* data() const;
- size_t dataSize() const;
- size_t dataAvail() const;
- size_t dataPosition() const;
- size_t dataCapacity() const;
-
- status_t setDataSize(size_t size);
- void setDataPosition(size_t pos) const;
- status_t setDataCapacity(size_t size);
-
- status_t setData(const uint8_t* buffer, size_t len);
-
- status_t appendFrom(Parcel *parcel, size_t start, size_t len);
-
- bool hasFileDescriptors() const;
-
- status_t writeInterfaceToken(const String16& interface);
- bool enforceInterface(const String16& interface) const;
-
- void freeData();
-
- const size_t* objects() const;
- size_t objectsCount() const;
-
- status_t errorCheck() const;
- void setError(status_t err);
-
- status_t write(const void* data, size_t len);
- void* writeInplace(size_t len);
- status_t writeUnpadded(const void* data, size_t len);
- status_t writeInt32(int32_t val);
- status_t writeInt64(int64_t val);
- status_t writeFloat(float val);
- status_t writeDouble(double val);
- status_t writeCString(const char* str);
- status_t writeString8(const String8& str);
- status_t writeString16(const String16& str);
- status_t writeString16(const char16_t* str, size_t len);
- status_t writeStrongBinder(const sp<IBinder>& val);
- status_t writeWeakBinder(const wp<IBinder>& val);
-
- // Place a native_handle into the parcel (the native_handle's file-
- // descriptors are dup'ed, so it is safe to delete the native_handle
- // when this function returns).
- // Doesn't take ownership of the native_handle.
- status_t writeNativeHandle(const native_handle* handle);
-
- // Place a file descriptor into the parcel. The given fd must remain
- // valid for the lifetime of the parcel.
- status_t writeFileDescriptor(int fd);
-
- // Place a file descriptor into the parcel. A dup of the fd is made, which
- // will be closed once the parcel is destroyed.
- status_t writeDupFileDescriptor(int fd);
-
- status_t writeObject(const flat_binder_object& val, bool nullMetaData);
-
- void remove(size_t start, size_t amt);
-
- status_t read(void* outData, size_t len) const;
- const void* readInplace(size_t len) const;
- int32_t readInt32() const;
- status_t readInt32(int32_t *pArg) const;
- int64_t readInt64() const;
- status_t readInt64(int64_t *pArg) const;
- float readFloat() const;
- status_t readFloat(float *pArg) const;
- double readDouble() const;
- status_t readDouble(double *pArg) const;
-
- const char* readCString() const;
- String8 readString8() const;
- String16 readString16() const;
- const char16_t* readString16Inplace(size_t* outLen) const;
- sp<IBinder> readStrongBinder() const;
- wp<IBinder> readWeakBinder() const;
-
-
- // Retrieve native_handle from the parcel. This returns a copy of the
- // parcel's native_handle (the caller takes ownership). The caller
- // must free the native_handle with native_handle_close() and
- // native_handle_delete().
- native_handle* readNativeHandle() const;
-
-
- // Retrieve a file descriptor from the parcel. This returns the raw fd
- // in the parcel, which you do not own -- use dup() to get your own copy.
- int readFileDescriptor() const;
-
- const flat_binder_object* readObject(bool nullMetaData) const;
-
- // Explicitly close all file descriptors in the parcel.
- void closeFileDescriptors();
-
- typedef void (*release_func)(Parcel* parcel,
- const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie);
-
- const uint8_t* ipcData() const;
- size_t ipcDataSize() const;
- const size_t* ipcObjects() const;
- size_t ipcObjectsCount() const;
- void ipcSetDataReference(const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsCount,
- release_func relFunc, void* relCookie);
-
- void print(TextOutput& to, uint32_t flags = 0) const;
-
-private:
- Parcel(const Parcel& o);
- Parcel& operator=(const Parcel& o);
-
- status_t finishWrite(size_t len);
- void releaseObjects();
- void acquireObjects();
- status_t growData(size_t len);
- status_t restartWrite(size_t desired);
- status_t continueWrite(size_t desired);
- void freeDataNoInit();
- void initState();
- void scanForFds() const;
-
- status_t mError;
- uint8_t* mData;
- size_t mDataSize;
- size_t mDataCapacity;
- mutable size_t mDataPos;
- size_t* mObjects;
- size_t mObjectsSize;
- size_t mObjectsCapacity;
- mutable size_t mNextObjectHint;
-
- mutable bool mFdsKnown;
- mutable bool mHasFds;
-
- release_func mOwner;
- void* mOwnerCookie;
-};
-
-// ---------------------------------------------------------------------------
-
-inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
-{
- parcel.print(to);
- return to;
-}
-
-// ---------------------------------------------------------------------------
-
-// Generic acquire and release of objects.
-void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
-void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
-
-void flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, flat_binder_object* out);
-void flatten_binder(const sp<ProcessState>& proc,
- const wp<IBinder>& binder, flat_binder_object* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const flat_binder_object& flat, sp<IBinder>* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const flat_binder_object& flat, wp<IBinder>* out);
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PARCEL_H
diff --git a/include/utils/Pipe.h b/include/utils/Pipe.h
deleted file mode 100644
index 6404168..0000000
--- a/include/utils/Pipe.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// FIFO I/O.
-//
-#ifndef _LIBS_UTILS_PIPE_H
-#define _LIBS_UTILS_PIPE_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-namespace android {
-
-/*
- * Simple anonymous unidirectional pipe.
- *
- * The primary goal is to create an implementation with minimal overhead
- * under Linux. Making Windows, Mac OS X, and Linux all work the same way
- * is a secondary goal. Part of this goal is to have something that can
- * be fed to a select() call, so that the application can sleep in the
- * kernel until something interesting happens.
- */
-class Pipe {
-public:
- Pipe(void);
- virtual ~Pipe(void);
-
- /* Create the pipe */
- bool create(void);
-
- /* Create a read-only pipe, using the supplied handle as read handle */
- bool createReader(unsigned long handle);
- /* Create a write-only pipe, using the supplied handle as write handle */
- bool createWriter(unsigned long handle);
-
- /* Is this object ready to go? */
- bool isCreated(void);
-
- /*
- * Read "count" bytes from the pipe. Returns the amount of data read,
- * or 0 if no data available and we're non-blocking.
- * Returns -1 on error.
- */
- int read(void* buf, int count);
-
- /*
- * Write "count" bytes into the pipe. Returns number of bytes written,
- * or 0 if there's no room for more data and we're non-blocking.
- * Returns -1 on error.
- */
- int write(const void* buf, int count);
-
- /* Returns "true" if data is available to read */
- bool readReady(void);
-
- /* Enable or disable non-blocking I/O for reads */
- bool setReadNonBlocking(bool val);
- /* Enable or disable non-blocking I/O for writes. Only works on Linux. */
- bool setWriteNonBlocking(bool val);
-
- /*
- * Get the handle. Only useful in some platform-specific situations.
- */
- unsigned long getReadHandle(void);
- unsigned long getWriteHandle(void);
-
- /*
- * Modify inheritance, i.e. whether or not a child process will get
- * copies of the descriptors. Systems with fork+exec allow us to close
- * the descriptors before launching the child process, but Win32
- * doesn't allow it.
- */
- bool disallowReadInherit(void);
- bool disallowWriteInherit(void);
-
- /*
- * Close one side or the other. Useful in the parent after launching
- * a child process.
- */
- bool closeRead(void);
- bool closeWrite(void);
-
-private:
- bool mReadNonBlocking;
- bool mWriteNonBlocking;
-
- unsigned long mReadHandle;
- unsigned long mWriteHandle;
-};
-
-}; // android
-
-#endif // _LIBS_UTILS_PIPE_H
diff --git a/include/utils/ProcessState.h b/include/utils/ProcessState.h
deleted file mode 100644
index 39584f4..0000000
--- a/include/utils/ProcessState.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_PROCESS_STATE_H
-#define ANDROID_PROCESS_STATE_H
-
-#include <utils/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-#include <utils/threads.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-// Global variables
-extern int mArgC;
-extern const char* const* mArgV;
-extern int mArgLen;
-
-class IPCThreadState;
-
-class ProcessState : public virtual RefBase
-{
-public:
- static sp<ProcessState> self();
-
- static void setSingleProcess(bool singleProcess);
-
- void setContextObject(const sp<IBinder>& object);
- sp<IBinder> getContextObject(const sp<IBinder>& caller);
-
- void setContextObject(const sp<IBinder>& object,
- const String16& name);
- sp<IBinder> getContextObject(const String16& name,
- const sp<IBinder>& caller);
-
- bool supportsProcesses() const;
-
- void startThreadPool();
-
- typedef bool (*context_check_func)(const String16& name,
- const sp<IBinder>& caller,
- void* userData);
-
- bool isContextManager(void) const;
- bool becomeContextManager(
- context_check_func checkFunc,
- void* userData);
-
- sp<IBinder> getStrongProxyForHandle(int32_t handle);
- wp<IBinder> getWeakProxyForHandle(int32_t handle);
- void expungeHandle(int32_t handle, IBinder* binder);
-
- void setArgs(int argc, const char* const argv[]);
- int getArgC() const;
- const char* const* getArgV() const;
-
- void setArgV0(const char* txt);
-
- void spawnPooledThread(bool isMain);
-
-private:
- friend class IPCThreadState;
-
- ProcessState();
- ~ProcessState();
-
- ProcessState(const ProcessState& o);
- ProcessState& operator=(const ProcessState& o);
-
- struct handle_entry {
- IBinder* binder;
- RefBase::weakref_type* refs;
- };
-
- handle_entry* lookupHandleLocked(int32_t handle);
-
- int mDriverFD;
- void* mVMStart;
-
- mutable Mutex mLock; // protects everything below.
-
- Vector<handle_entry>mHandleToObject;
-
- bool mManagesContexts;
- context_check_func mBinderContextCheckFunc;
- void* mBinderContextUserData;
-
- KeyedVector<String16, sp<IBinder> >
- mContexts;
-
-
- String8 mRootDir;
- bool mThreadPoolStarted;
- volatile int32_t mThreadPoolSeq;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbda0fd..bd7f28c 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -156,6 +156,10 @@
delete static_cast<const T*>(this);
}
}
+ //! DEBUGGING ONLY: Get current strong ref count.
+ inline int32_t getStrongCount() const {
+ return mCount;
+ }
protected:
inline ~LightRefBase() { }
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
new file mode 100644
index 0000000..bc7626a8
--- /dev/null
+++ b/include/utils/Singleton.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_UTILS_SINGLETON_H
+#define ANDROID_UTILS_SINGLETON_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <typename TYPE>
+class Singleton
+{
+public:
+ static TYPE& getInstance() {
+ Mutex::Autolock _l(sLock);
+ TYPE* instance = sInstance;
+ if (instance == 0) {
+ instance = new TYPE();
+ sInstance = instance;
+ }
+ return *instance;
+ }
+
+protected:
+ ~Singleton() { };
+ Singleton() { };
+
+private:
+ Singleton(const Singleton&);
+ Singleton& operator = (const Singleton&);
+ static Mutex sLock;
+ static TYPE* sInstance;
+};
+
+/*
+ * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
+ * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
+ * and avoid to have a copy of them in each compilation units Singleton<TYPE>
+ * is used.
+ */
+
+#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
+ template class Singleton< TYPE >; \
+ template< class TYPE > Mutex Singleton< TYPE >::sLock; \
+ template<> TYPE* Singleton< TYPE >::sInstance(0);
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UTILS_SINGLETON_H
+
diff --git a/include/utils/Socket.h b/include/utils/Socket.h
deleted file mode 100644
index 8b7f4061..0000000
--- a/include/utils/Socket.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Socket class. Modeled after Java classes.
-//
-#ifndef _RUNTIME_SOCKET_H
-#define _RUNTIME_SOCKET_H
-
-#include <utils/inet_address.h>
-#include <sys/types.h>
-
-namespace android {
-
-/*
- * Basic socket class, needed to abstract away the differences between
- * BSD sockets and WinSock. This establishes a streaming network
- * connection (TCP/IP) to somebody.
- */
-class Socket {
-public:
- Socket(void);
- ~Socket(void);
-
- // Create a connection to somewhere.
- // Return 0 on success.
- int connect(const char* host, int port);
- int connect(const InetAddress* addr, int port);
-
-
- // Close the socket. Don't try to use this object again after
- // calling this. Returns false on failure.
- bool close(void);
-
- // If we created the socket without an address, we can use these
- // to finish the connection. Returns 0 on success.
- int bind(const SocketAddress& bindPoint);
- int connect(const SocketAddress& endPoint);
-
- // Here we deviate from the traditional object-oriented fanciness
- // and just provide read/write operators instead of getters for
- // objects that abstract a stream.
- //
- // Standard read/write semantics.
- int read(void* buf, ssize_t len) const;
- int write(const void* buf, ssize_t len) const;
-
- // This must be called once, at program startup.
- static bool bootInit(void);
- static void finalShutdown(void);
-
-private:
- // Internal function that establishes a connection.
- int doConnect(const InetSocketAddress& addr);
-
- unsigned long mSock; // holds SOCKET or int
-
- static bool mBootInitialized;
-};
-
-
-// debug -- unit tests
-void TestSockets(void);
-
-}; // namespace android
-
-#endif // _RUNTIME_SOCKET_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index c8a6153..8beec57 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -141,8 +141,7 @@
: SortedVectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
diff --git a/include/utils/StringArray.h b/include/utils/StringArray.h
new file mode 100644
index 0000000..c244587
--- /dev/null
+++ b/include/utils/StringArray.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+#ifndef _LIBS_UTILS_STRING_ARRAY_H
+#define _LIBS_UTILS_STRING_ARRAY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+class StringArray {
+public:
+ StringArray();
+ virtual ~StringArray();
+
+ //
+ // Add a string. A copy of the string is made.
+ //
+ bool push_back(const char* str);
+
+ //
+ // Delete an entry.
+ //
+ void erase(int idx);
+
+ //
+ // Sort the array.
+ //
+ void sort(int (*compare)(const void*, const void*));
+
+ //
+ // Pass this to the sort routine to do an ascending alphabetical sort.
+ //
+ static int cmpAscendingAlpha(const void* pstr1, const void* pstr2);
+
+ //
+ // Get the #of items in the array.
+ //
+ inline int size(void) const { return mCurrent; }
+
+ //
+ // Return entry N.
+ // [should use operator[] here]
+ //
+ const char* getEntry(int idx) const {
+ return (unsigned(idx) >= unsigned(mCurrent)) ? NULL : mArray[idx];
+ }
+
+ //
+ // Set entry N to specified string.
+ // [should use operator[] here]
+ //
+ void setEntry(int idx, const char* str);
+
+private:
+ int mMax;
+ int mCurrent;
+ char** mArray;
+};
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/TextOutput.h b/include/utils/TextOutput.h
index d8d86ba..de2fbbe 100644
--- a/include/utils/TextOutput.h
+++ b/include/utils/TextOutput.h
@@ -28,8 +28,8 @@
class TextOutput
{
public:
- TextOutput() { }
- virtual ~TextOutput() { }
+ TextOutput();
+ virtual ~TextOutput();
virtual status_t print(const char* txt, size_t len) = 0;
virtual void moveIndent(int delta) = 0;
diff --git a/include/utils/TimerProbe.h b/include/utils/TimerProbe.h
deleted file mode 100644
index f2e32b2..0000000
--- a/include/utils/TimerProbe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_TIMER_PROBE_H
-#define ANDROID_TIMER_PROBE_H
-
-#if 0 && defined(HAVE_POSIX_CLOCKS)
-#define ENABLE_TIMER_PROBE 1
-#else
-#define ENABLE_TIMER_PROBE 0
-#endif
-
-#if ENABLE_TIMER_PROBE
-
-#include <time.h>
-#include <sys/time.h>
-#include <utils/Vector.h>
-
-#define TIMER_PROBE(tag) \
- static int _timer_slot_; \
- android::TimerProbe probe(tag, &_timer_slot_)
-#define TIMER_PROBE_END() probe.end()
-#else
-#define TIMER_PROBE(tag)
-#define TIMER_PROBE_END()
-#endif
-
-#if ENABLE_TIMER_PROBE
-namespace android {
-
-class TimerProbe {
-public:
- TimerProbe(const char tag[], int* slot);
- void end();
- ~TimerProbe();
-private:
- struct Bucket {
- int mStart, mReal, mProcess, mThread, mCount;
- const char* mTag;
- int* mSlotPtr;
- int mIndent;
- };
- static Vector<Bucket> gBuckets;
- static TimerProbe* gExecuteChain;
- static int gIndent;
- static timespec gRealBase;
- TimerProbe* mNext;
- static uint32_t ElapsedTime(const timespec& start, const timespec& end);
- void print(const timespec& r, const timespec& p, const timespec& t) const;
- timespec mRealStart, mPStart, mTStart;
- const char* mTag;
- int mIndent;
- int mBucket;
-};
-
-}; // namespace android
-
-#endif
-#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9610399..9a9e07c 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,9 +88,6 @@
nsecs_t systemTime(int clock);
#endif // def __cplusplus
-// return the system-time according to the specified clock
-int sleepForInterval(long interval, struct timeval* pNextTick);
-
#ifdef __cplusplus
} // extern "C"
#endif
@@ -108,15 +105,15 @@
*/
class DurationTimer {
public:
- DurationTimer(void) {}
- ~DurationTimer(void) {}
+ DurationTimer() {}
+ ~DurationTimer() {}
// Start the timer.
- void start(void);
+ void start();
// Stop the timer.
- void stop(void);
+ void stop();
// Get the duration in microseconds.
- long long durationUsecs(void) const;
+ long long durationUsecs() const;
// Subtract two timevals. Returns the difference (ptv1-ptv2) in
// microseconds.
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index c04c37f..2ff2749 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -29,35 +29,39 @@
/*
* Types traits
*/
-
-template <typename T> struct trait_trivial_ctor { enum { value = false }; };
-template <typename T> struct trait_trivial_dtor { enum { value = false }; };
-template <typename T> struct trait_trivial_copy { enum { value = false }; };
-template <typename T> struct trait_trivial_assign{ enum { value = false }; };
-template <typename T> struct trait_pointer { enum { value = false }; };
-template <typename T> struct trait_pointer<T*> { enum { value = true }; };
+template <typename T> struct trait_trivial_ctor { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor { enum { value = false }; };
+template <typename T> struct trait_trivial_copy { enum { value = false }; };
+template <typename T> struct trait_trivial_move { enum { value = false }; };
+template <typename T> struct trait_pointer { enum { value = false }; };
+template <typename T> struct trait_pointer<T*> { enum { value = true }; };
-#define ANDROID_BASIC_TYPES_TRAITS( T ) \
- template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = true }; };
+// sp<> can be trivially moved
+template <typename T> class sp;
+template <typename T> struct trait_trivial_move< sp<T> >{
+ enum { value = true };
+};
-#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
- template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
+// wp<> can be trivially moved
+template <typename T> class wp;
+template <typename T> struct trait_trivial_move< wp<T> >{
+ enum { value = true };
+};
template <typename TYPE>
struct traits {
enum {
+ // whether this type is a pointer
is_pointer = trait_pointer<TYPE>::value,
+ // whether this type's constructor is a no-op
has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
+ // whether this type's destructor is a no-op
has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
+ // whether this type type can be copy-constructed with memcpy
has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
- has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
+ // whether this type can be moved with memmove
+ has_trivial_move = is_pointer || trait_trivial_move<TYPE>::value
};
};
@@ -65,37 +69,47 @@
struct aggregate_traits {
enum {
is_pointer = false,
- has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
- has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
- has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
- has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
+ has_trivial_ctor =
+ traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+ has_trivial_dtor =
+ traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+ has_trivial_copy =
+ traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+ has_trivial_move =
+ traits<T>::has_trivial_move && traits<U>::has_trivial_move
};
};
+#define ANDROID_BASIC_TYPES_TRAITS( T ) \
+ template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_move< T > { enum { value = true }; };
+
// ---------------------------------------------------------------------------
/*
* basic types traits
*/
-
-ANDROID_BASIC_TYPES_TRAITS( void );
-ANDROID_BASIC_TYPES_TRAITS( bool );
-ANDROID_BASIC_TYPES_TRAITS( char );
-ANDROID_BASIC_TYPES_TRAITS( unsigned char );
-ANDROID_BASIC_TYPES_TRAITS( short );
-ANDROID_BASIC_TYPES_TRAITS( unsigned short );
-ANDROID_BASIC_TYPES_TRAITS( int );
-ANDROID_BASIC_TYPES_TRAITS( unsigned int );
-ANDROID_BASIC_TYPES_TRAITS( long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long );
-ANDROID_BASIC_TYPES_TRAITS( long long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
-ANDROID_BASIC_TYPES_TRAITS( float );
-ANDROID_BASIC_TYPES_TRAITS( double );
+
+ANDROID_BASIC_TYPES_TRAITS( void )
+ANDROID_BASIC_TYPES_TRAITS( bool )
+ANDROID_BASIC_TYPES_TRAITS( char )
+ANDROID_BASIC_TYPES_TRAITS( unsigned char )
+ANDROID_BASIC_TYPES_TRAITS( short )
+ANDROID_BASIC_TYPES_TRAITS( unsigned short )
+ANDROID_BASIC_TYPES_TRAITS( int )
+ANDROID_BASIC_TYPES_TRAITS( unsigned int )
+ANDROID_BASIC_TYPES_TRAITS( long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long )
+ANDROID_BASIC_TYPES_TRAITS( long long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
+ANDROID_BASIC_TYPES_TRAITS( float )
+ANDROID_BASIC_TYPES_TRAITS( double )
// ---------------------------------------------------------------------------
-
+
/*
* compare and order types
*/
@@ -111,9 +125,9 @@
}
/*
- * create, destroy, copy and assign types...
+ * create, destroy, copy and move types...
*/
-
+
template<typename TYPE> inline
void construct_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_ctor) {
@@ -146,17 +160,6 @@
}
template<typename TYPE> inline
-void assign_type(TYPE* d, const TYPE* s, size_t n) {
- if (!traits<TYPE>::has_trivial_assign) {
- while (n--) {
- *d++ = *s++;
- }
- } else {
- memcpy(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
void splat_type(TYPE* where, const TYPE* what, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
while (n--) {
@@ -164,15 +167,19 @@
where++;
}
} else {
- while (n--) {
- *where++ = *what;
+ while (n--) {
+ *where++ = *what;
}
}
}
template<typename TYPE> inline
void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
d += n;
s += n;
while (n--) {
@@ -180,35 +187,37 @@
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
template<typename TYPE> inline
void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
while (n--) {
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
d++, s++;
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
+
+
// ---------------------------------------------------------------------------
/*
@@ -242,8 +251,8 @@
{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
template<>
template <typename K, typename V>
-struct trait_trivial_assign< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
+struct trait_trivial_move< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_move }; };
// ---------------------------------------------------------------------------
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index be365d8..ad59fd6 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -175,8 +175,7 @@
: VectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index 2525229..49b03f1 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -44,7 +44,6 @@
HAS_TRIVIAL_CTOR = 0x00000001,
HAS_TRIVIAL_DTOR = 0x00000002,
HAS_TRIVIAL_COPY = 0x00000004,
- HAS_TRIVIAL_ASSIGN = 0x00000008
};
VectorImpl(size_t itemSize, uint32_t flags);
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
deleted file mode 100644
index e4698df..0000000
--- a/include/utils/ZipEntry.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// Zip archive entries.
-//
-// The ZipEntry class is tightly meshed with the ZipFile class.
-//
-#ifndef __LIBS_ZIPENTRY_H
-#define __LIBS_ZIPENTRY_H
-
-#include "Errors.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-namespace android {
-
-class ZipFile;
-
-/*
- * ZipEntry objects represent a single entry in a Zip archive.
- *
- * You can use one of these to get or set information about an entry, but
- * there are no functions here for accessing the data itself. (We could
- * tuck a pointer to the ZipFile in here for convenience, but that raises
- * the likelihood of using ZipEntry objects after discarding the ZipFile.)
- *
- * File information is stored in two places: next to the file data (the Local
- * File Header, and possibly a Data Descriptor), and at the end of the file
- * (the Central Directory Entry). The two must be kept in sync.
- */
-class ZipEntry {
-public:
- friend class ZipFile;
-
- ZipEntry(void)
- : mDeleted(false), mMarked(false)
- {}
- ~ZipEntry(void) {}
-
- /*
- * Returns "true" if the data is compressed.
- */
- bool isCompressed(void) const {
- return mCDE.mCompressionMethod != kCompressStored;
- }
- int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
-
- /*
- * Return the uncompressed length.
- */
- off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
-
- /*
- * Return the compressed length. For uncompressed data, this returns
- * the same thing as getUncompresesdLen().
- */
- off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
-
- /*
- * Return the absolute file offset of the start of the compressed or
- * uncompressed data.
- */
- off_t getFileOffset(void) const {
- return mCDE.mLocalHeaderRelOffset +
- LocalFileHeader::kLFHLen +
- mLFH.mFileNameLength +
- mLFH.mExtraFieldLength;
- }
-
- /*
- * Return the data CRC.
- */
- unsigned long getCRC32(void) const { return mCDE.mCRC32; }
-
- /*
- * Return file modification time in UNIX seconds-since-epoch.
- */
- time_t getModWhen(void) const;
-
- /*
- * Return the archived file name.
- */
- const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
-
- /*
- * Application-defined "mark". Can be useful when synchronizing the
- * contents of an archive with contents on disk.
- */
- bool getMarked(void) const { return mMarked; }
- void setMarked(bool val) { mMarked = val; }
-
- /*
- * Some basic functions for raw data manipulation. "LE" means
- * Little Endian.
- */
- static inline unsigned short getShortLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8);
- }
- static inline unsigned long getLongLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
- }
- static inline void putShortLE(unsigned char* buf, short val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- }
- static inline void putLongLE(unsigned char* buf, long val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- buf[2] = (unsigned char) (val >> 16);
- buf[3] = (unsigned char) (val >> 24);
- }
-
- /* defined for Zip archives */
- enum {
- kCompressStored = 0, // no compression
- // shrunk = 1,
- // reduced 1 = 2,
- // reduced 2 = 3,
- // reduced 3 = 4,
- // reduced 4 = 5,
- // imploded = 6,
- // tokenized = 7,
- kCompressDeflated = 8, // standard deflate
- // Deflate64 = 9,
- // lib imploded = 10,
- // reserved = 11,
- // bzip2 = 12,
- };
-
- /*
- * Deletion flag. If set, the entry will be removed on the next
- * call to "flush".
- */
- bool getDeleted(void) const { return mDeleted; }
-
-protected:
- /*
- * Initialize the structure from the file, which is pointing at
- * our Central Directory entry.
- */
- status_t initFromCDE(FILE* fp);
-
- /*
- * Initialize the structure for a new file. We need the filename
- * and comment so that we can properly size the LFH area. The
- * filename is mandatory, the comment is optional.
- */
- void initNew(const char* fileName, const char* comment);
-
- /*
- * Initialize the structure with the contents of a ZipEntry from
- * another file.
- */
- status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
-
- /*
- * Add some pad bytes to the LFH. We do this by adding or resizing
- * the "extra" field.
- */
- status_t addPadding(int padding);
-
- /*
- * Set information about the data for this entry.
- */
- void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod);
-
- /*
- * Set the modification date.
- */
- void setModWhen(time_t when);
-
- /*
- * Return the offset of the local file header.
- */
- off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
-
- /*
- * Set the offset of the local file header, relative to the start of
- * the current file.
- */
- void setLFHOffset(off_t offset) {
- mCDE.mLocalHeaderRelOffset = (long) offset;
- }
-
- /* mark for deletion; used by ZipFile::remove() */
- void setDeleted(void) { mDeleted = true; }
-
-private:
- /* these are private and not defined */
- ZipEntry(const ZipEntry& src);
- ZipEntry& operator=(const ZipEntry& src);
-
- /* returns "true" if the CDE and the LFH agree */
- bool compareHeaders(void) const;
- void copyCDEtoLFH(void);
-
- bool mDeleted; // set if entry is pending deletion
- bool mMarked; // app-defined marker
-
- /*
- * Every entry in the Zip archive starts off with one of these.
- */
- class LocalFileHeader {
- public:
- LocalFileHeader(void) :
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileName(NULL),
- mExtraField(NULL)
- {}
- virtual ~LocalFileHeader(void) {
- delete[] mFileName;
- delete[] mExtraField;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned char* mFileName;
- unsigned char* mExtraField;
-
- enum {
- kSignature = 0x04034b50,
- kLFHLen = 30, // LocalFileHdr len, excl. var fields
- };
-
- void dump(void) const;
- };
-
- /*
- * Every entry in the Zip archive has one of these in the "central
- * directory" at the end of the file.
- */
- class CentralDirEntry {
- public:
- CentralDirEntry(void) :
- mVersionMadeBy(0),
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileCommentLength(0),
- mDiskNumberStart(0),
- mInternalAttrs(0),
- mExternalAttrs(0),
- mLocalHeaderRelOffset(0),
- mFileName(NULL),
- mExtraField(NULL),
- mFileComment(NULL)
- {}
- virtual ~CentralDirEntry(void) {
- delete[] mFileName;
- delete[] mExtraField;
- delete[] mFileComment;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionMadeBy;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned short mFileCommentLength;
- unsigned short mDiskNumberStart;
- unsigned short mInternalAttrs;
- unsigned long mExternalAttrs;
- unsigned long mLocalHeaderRelOffset;
- unsigned char* mFileName;
- unsigned char* mExtraField;
- unsigned char* mFileComment;
-
- void dump(void) const;
-
- enum {
- kSignature = 0x02014b50,
- kCDELen = 46, // CentralDirEnt len, excl. var fields
- };
- };
-
- enum {
- //kDataDescriptorSignature = 0x08074b50, // currently unused
- kDataDescriptorLen = 16, // four 32-bit fields
-
- kDefaultVersion = 20, // need deflate, nothing much else
- kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
- kUsesDataDescr = 0x0008, // GPBitFlag bit 3
- };
-
- LocalFileHeader mLFH;
- CentralDirEntry mCDE;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
deleted file mode 100644
index 44df5bb..0000000
--- a/include/utils/ZipFile.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// General-purpose Zip archive access. This class allows both reading and
-// writing to Zip archives, including deletion of existing entries.
-//
-#ifndef __LIBS_ZIPFILE_H
-#define __LIBS_ZIPFILE_H
-
-#include "ZipEntry.h"
-#include "Vector.h"
-#include "Errors.h"
-#include <stdio.h>
-
-namespace android {
-
-/*
- * Manipulate a Zip archive.
- *
- * Some changes will not be visible in the until until "flush" is called.
- *
- * The correct way to update a file archive is to make all changes to a
- * copy of the archive in a temporary file, and then unlink/rename over
- * the original after everything completes. Because we're only interested
- * in using this for packaging, we don't worry about such things. Crashing
- * after making changes and before flush() completes could leave us with
- * an unusable Zip archive.
- */
-class ZipFile {
-public:
- ZipFile(void)
- : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
- {}
- ~ZipFile(void) {
- if (!mReadOnly)
- flush();
- if (mZipFp != NULL)
- fclose(mZipFp);
- discardEntries();
- }
-
- /*
- * Open a new or existing archive.
- */
- typedef enum {
- kOpenReadOnly = 0x01,
- kOpenReadWrite = 0x02,
- kOpenCreate = 0x04, // create if it doesn't exist
- kOpenTruncate = 0x08, // if it exists, empty it
- };
- status_t open(const char* zipFileName, int flags);
-
- /*
- * Add a file to the end of the archive. Specify whether you want the
- * library to try to store it compressed.
- *
- * If "storageName" is specified, the archive will use that instead
- * of "fileName".
- *
- * If there is already an entry with the same name, the call fails.
- * Existing entries with the same name must be removed first.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const char* fileName, int compressionMethod,
- ZipEntry** ppEntry)
- {
- return add(fileName, fileName, compressionMethod, ppEntry);
- }
- status_t add(const char* fileName, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * Add a file that is already compressed with gzip.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t addGzip(const char* fileName, const char* storageName,
- ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressDeflated,
- ZipEntry::kCompressDeflated, ppEntry);
- }
-
- /*
- * Add a file from an in-memory data buffer.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const void* data, size_t size, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(NULL, data, size, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * Add an entry by copying it from another zip file. If "padding" is
- * nonzero, the specified number of bytes will be added to the "extra"
- * field in the header.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry);
-
- /*
- * Mark an entry as having been removed. It is not actually deleted
- * from the archive or our internal data structures until flush() is
- * called.
- */
- status_t remove(ZipEntry* pEntry);
-
- /*
- * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
- */
- status_t flush(void);
-
- /*
- * Expand the data into the buffer provided. The buffer must hold
- * at least <uncompressed len> bytes. Variation expands directly
- * to a file.
- *
- * Returns "false" if an error was encountered in the compressed data.
- */
- //bool uncompress(const ZipEntry* pEntry, void* buf) const;
- //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
- void* uncompress(const ZipEntry* pEntry);
-
- /*
- * Get an entry, by name. Returns NULL if not found.
- *
- * Does not return entries pending deletion.
- */
- ZipEntry* getEntryByName(const char* fileName) const;
-
- /*
- * Get the Nth entry in the archive.
- *
- * This will return an entry that is pending deletion.
- */
- int getNumEntries(void) const { return mEntries.size(); }
- ZipEntry* getEntryByIndex(int idx) const;
-
-private:
- /* these are private and not defined */
- ZipFile(const ZipFile& src);
- ZipFile& operator=(const ZipFile& src);
-
- class EndOfCentralDir {
- public:
- EndOfCentralDir(void) :
- mDiskNumber(0),
- mDiskWithCentralDir(0),
- mNumEntries(0),
- mTotalNumEntries(0),
- mCentralDirSize(0),
- mCentralDirOffset(0),
- mCommentLen(0),
- mComment(NULL)
- {}
- virtual ~EndOfCentralDir(void) {
- delete[] mComment;
- }
-
- status_t readBuf(const unsigned char* buf, int len);
- status_t write(FILE* fp);
-
- //unsigned long mSignature;
- unsigned short mDiskNumber;
- unsigned short mDiskWithCentralDir;
- unsigned short mNumEntries;
- unsigned short mTotalNumEntries;
- unsigned long mCentralDirSize;
- unsigned long mCentralDirOffset; // offset from first disk
- unsigned short mCommentLen;
- unsigned char* mComment;
-
- enum {
- kSignature = 0x06054b50,
- kEOCDLen = 22, // EndOfCentralDir len, excl. comment
-
- kMaxCommentLen = 65535, // longest possible in ushort
- kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
-
- };
-
- void dump(void) const;
- };
-
-
- /* read all entries in the central dir */
- status_t readCentralDir(void);
-
- /* crunch deleted entries out */
- status_t crunchArchive(void);
-
- /* clean up mEntries */
- void discardEntries(void);
-
- /* common handler for all "add" functions */
- status_t addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry);
-
- /* copy all of "srcFp" into "dstFp" */
- status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
- /* copy all of "data" into "dstFp" */
- status_t copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32);
- /* copy some of "srcFp" into "dstFp" */
- status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32);
- /* like memmove(), but on parts of a single file */
- status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
- /* compress all of "srcFp" into "dstFp", using Deflate */
- status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
- const void* data, size_t size, unsigned long* pCRC32);
-
- /* get modification date from a file descriptor */
- time_t getModTime(int fd);
-
- /*
- * We use stdio FILE*, which gives us buffering but makes dealing
- * with files >2GB awkward. Until we support Zip64, we're fine.
- */
- FILE* mZipFp; // Zip file pointer
-
- /* one of these per file */
- EndOfCentralDir mEOCD;
-
- /* did we open this read-only? */
- bool mReadOnly;
-
- /* set this when we trash the central dir */
- bool mNeedCDRewrite;
-
- /*
- * One ZipEntry per entry in the zip file. I'm using pointers instead
- * of objects because it's easier than making operator= work for the
- * classes and sub-classes.
- */
- Vector<ZipEntry*> mEntries;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPFILE_H
diff --git a/include/utils/executablepath.h b/include/utils/executablepath.h
deleted file mode 100644
index c979432..0000000
--- a/include/utils/executablepath.h
+++ /dev/null
@@ -1,28 +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.
- */
-
-#ifndef _UTILS_EXECUTABLEPATH_H
-#define _UTILS_EXECUTABLEPATH_H
-
-#include <limits.h>
-
-// returns the path to this executable
-#if __cplusplus
-extern "C"
-#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _UTILS_EXECUTABLEPATH_H
diff --git a/include/utils/inet_address.h b/include/utils/inet_address.h
deleted file mode 100644
index dbd8672..0000000
--- a/include/utils/inet_address.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address classes. Modeled after Java classes.
-//
-#ifndef _RUNTIME_INET_ADDRESS_H
-#define _RUNTIME_INET_ADDRESS_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-
-namespace android {
-
-/*
- * This class holds Internet addresses. Perhaps more useful is its
- * ability to look up addresses by name.
- *
- * Invoke one of the static factory methods to create a new object.
- */
-class InetAddress {
-public:
- virtual ~InetAddress(void);
-
- // create from w.x.y.z or foo.bar.com notation
- static InetAddress* getByName(const char* host);
-
- // copy-construction
- InetAddress(const InetAddress& orig);
-
- const void* getAddress(void) const { return mAddress; }
- int getAddressLength(void) const { return mLength; }
- const char* getHostName(void) const { return mName; }
-
-private:
- InetAddress(void);
- // assignment (private)
- InetAddress& operator=(const InetAddress& addr);
-
- // use a void* here so we don't have to expose actual socket headers
- void* mAddress; // this is really a ptr to sockaddr_in
- int mLength;
- char* mName;
-};
-
-
-/*
- * Base class for socket addresses.
- */
-class SocketAddress {
-public:
- SocketAddress() {}
- virtual ~SocketAddress() {}
-};
-
-
-/*
- * Internet address class. This combines an InetAddress with a port.
- */
-class InetSocketAddress : public SocketAddress {
-public:
- InetSocketAddress() :
- mAddress(0), mPort(-1)
- {}
- ~InetSocketAddress(void) {
- delete mAddress;
- }
-
- // Create an address with a host wildcard (useful for servers).
- bool create(int port);
- // Create an address with the specified host and port.
- bool create(const InetAddress* addr, int port);
- // Create an address with the specified host and port. Does the
- // hostname lookup.
- bool create(const char* host, int port);
-
- const InetAddress* getAddress(void) const { return mAddress; }
- const int getPort(void) const { return mPort; }
- const char* getHostName(void) const { return mAddress->getHostName(); }
-
-private:
- InetAddress* mAddress;
- int mPort;
-};
-
-}; // namespace android
-
-#endif // _RUNTIME_INET_ADDRESS_H
diff --git a/include/utils/misc.h b/include/utils/misc.h
index 62e84b4..23f2a4c 100644
--- a/include/utils/misc.h
+++ b/include/utils/misc.h
@@ -21,7 +21,7 @@
#define _LIBS_UTILS_MISC_H
#include <sys/time.h>
-#include "utils/Endian.h"
+#include <utils/Endian.h>
namespace android {
diff --git a/include/utils/ported.h b/include/utils/ported.h
deleted file mode 100644
index eb3be01..0000000
--- a/include/utils/ported.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Standard functions ported to the current platform. Note these are NOT
-// in the "android" namespace.
-//
-#ifndef _LIBS_UTILS_PORTED_H
-#define _LIBS_UTILS_PORTED_H
-
-#include <sys/time.h> // for timeval
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* library replacement functions */
-#if defined(NEED_GETTIMEOFDAY)
-int gettimeofday(struct timeval* tv, struct timezone* tz);
-#endif
-#if defined(NEED_USLEEP)
-void usleep(unsigned long usec);
-#endif
-#if defined(NEED_PIPE)
-int pipe(int filedes[2]);
-#endif
-#if defined(NEED_SETENV)
-int setenv(const char* name, const char* value, int overwrite);
-void unsetenv(const char* name);
-char* getenv(const char* name);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _LIBS_UTILS_PORTED_H
diff --git a/include/utils/string_array.h b/include/utils/string_array.h
deleted file mode 100644
index 064dda2..0000000
--- a/include/utils/string_array.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Sortable array of strings. STL-ish, but STL-free.
-//
-#ifndef _LIBS_UTILS_STRING_ARRAY_H
-#define _LIBS_UTILS_STRING_ARRAY_H
-
-#include <stdlib.h>
-#include <string.h>
-
-namespace android {
-
-//
-// An expanding array of strings. Add, get, sort, delete.
-//
-class StringArray {
-public:
- StringArray()
- : mMax(0), mCurrent(0), mArray(NULL)
- {}
- virtual ~StringArray() {
- for (int i = 0; i < mCurrent; i++)
- delete[] mArray[i];
- delete[] mArray;
- }
-
- //
- // Add a string. A copy of the string is made.
- //
- bool push_back(const char* str) {
- if (mCurrent >= mMax) {
- char** tmp;
-
- if (mMax == 0)
- mMax = 16; // initial storage
- else
- mMax *= 2;
-
- tmp = new char*[mMax];
- if (tmp == NULL)
- return false;
-
- memcpy(tmp, mArray, mCurrent * sizeof(char*));
- delete[] mArray;
- mArray = tmp;
- }
-
- int len = strlen(str);
- mArray[mCurrent] = new char[len+1];
- memcpy(mArray[mCurrent], str, len+1);
- mCurrent++;
-
- return true;
- }
-
- //
- // Delete an entry.
- //
- void erase(int idx) {
- if (idx < 0 || idx >= mCurrent)
- return;
- delete[] mArray[idx];
- if (idx < mCurrent-1) {
- memmove(&mArray[idx], &mArray[idx+1],
- (mCurrent-1 - idx) * sizeof(char*));
- }
- mCurrent--;
- }
-
- //
- // Sort the array.
- //
- void sort(int (*compare)(const void*, const void*)) {
- qsort(mArray, mCurrent, sizeof(char*), compare);
- }
-
- //
- // Pass this to the sort routine to do an ascending alphabetical sort.
- //
- static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
- return strcmp(*(const char**)pstr1, *(const char**)pstr2);
- }
-
- //
- // Get the #of items in the array.
- //
- inline int size(void) const { return mCurrent; }
-
- //
- // Return entry N.
- // [should use operator[] here]
- //
- const char* getEntry(int idx) const {
- if (idx < 0 || idx >= mCurrent)
- return NULL;
- return mArray[idx];
- }
-
- //
- // Set entry N to specified string.
- // [should use operator[] here]
- //
- void setEntry(int idx, const char* str) {
- if (idx < 0 || idx >= mCurrent)
- return;
- delete[] mArray[idx];
- int len = strlen(str);
- mArray[idx] = new char[len+1];
- memcpy(mArray[idx], str, len+1);
- }
-
-private:
- int mMax;
- int mCurrent;
- char** mArray;
-};
-
-}; // namespace android
-
-#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/threads.h b/include/utils/threads.h
index b320915..e9b0788 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -21,6 +21,10 @@
#include <sys/types.h>
#include <time.h>
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
// ------------------------------------------------------------------
// C API
@@ -176,6 +180,8 @@
return androidGetThreadId();
}
+/*****************************************************************************/
+
/*
* Simple mutex class. The implementation is system-dependent.
*
@@ -184,8 +190,14 @@
*/
class Mutex {
public:
+ enum {
+ NORMAL = 0,
+ SHARED = 1
+ };
+
Mutex();
Mutex(const char* name);
+ Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
@@ -199,11 +211,11 @@
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
- inline Autolock(Mutex& mutex) : mpMutex(&mutex) { mutex.lock(); }
- inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
- inline ~Autolock() { mpMutex->unlock(); }
+ inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() { mLock.unlock(); }
private:
- Mutex* mpMutex;
+ Mutex& mLock;
};
private:
@@ -212,11 +224,49 @@
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
- void _init();
+#if defined(HAVE_PTHREADS)
+ pthread_mutex_t mMutex;
+#else
+ void _init();
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Mutex::Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(const char* name) {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(int type, const char* name) {
+ if (type == SHARED) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&mMutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ } else {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+}
+inline Mutex::~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+}
+inline status_t Mutex::lock() {
+ return -pthread_mutex_lock(&mMutex);
+}
+inline void Mutex::unlock() {
+ pthread_mutex_unlock(&mMutex);
+}
+inline status_t Mutex::tryLock() {
+ return -pthread_mutex_trylock(&mMutex);
+}
+
+#endif // HAVE_PTHREADS
+
/*
* Automatic mutex. Declare one of these at the top of a function.
* When the function returns, it will go out of scope, and release the
@@ -225,6 +275,7 @@
typedef Mutex::Autolock AutoMutex;
+/*****************************************************************************/
/*
* Condition variable class. The implementation is system-dependent.
@@ -240,9 +291,6 @@
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
- // Wait on the condition variable until the given time. Lock the mutex
- // before calling.
- status_t wait(Mutex& mutex, nsecs_t abstime);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
@@ -251,9 +299,60 @@
void broadcast();
private:
+#if defined(HAVE_PTHREADS)
+ pthread_cond_t mCond;
+#else
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Condition::Condition() {
+ pthread_cond_init(&mCond, NULL);
+}
+inline Condition::~Condition() {
+ pthread_cond_destroy(&mCond);
+}
+inline status_t Condition::wait(Mutex& mutex) {
+ return -pthread_cond_wait(&mCond, &mutex.mMutex);
+}
+inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
+ struct timespec ts;
+ ts.tv_sec = reltime/1000000000;
+ ts.tv_nsec = reltime%1000000000;
+ return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
+#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+ struct timespec ts;
+#if defined(HAVE_POSIX_CLOCKS)
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else // HAVE_POSIX_CLOCKS
+ // we don't support the clocks here.
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ ts.tv_sec = t.tv_sec;
+ ts.tv_nsec= t.tv_usec*1000;
+#endif // HAVE_POSIX_CLOCKS
+ ts.tv_sec += reltime/1000000000;
+ ts.tv_nsec+= reltime%1000000000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec += 1;
+ }
+ return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
+#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+}
+inline void Condition::signal() {
+ pthread_cond_signal(&mCond);
+}
+inline void Condition::broadcast() {
+ pthread_cond_broadcast(&mCond);
+}
+
+#endif // HAVE_PTHREADS
+
+/*****************************************************************************/
/*
* This is our spiffy thread object!
@@ -291,7 +390,7 @@
bool exitPending() const;
private:
- // Derived class must implemtent threadLoop(). The thread starts its life
+ // Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index dddf654..cefae40 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -121,15 +121,16 @@
Reply reply = new Reply();
if (!readBytes(buf, 4)) return null;
- reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) |
- ((((int) buf[2]) & 0xff) << 16) |
- ((((int) buf[3]) & 0xff) << 24);
+ reply.len = ((((int) buf[0]) & 0xff) << 24) |
+ ((((int) buf[1]) & 0xff) << 16) |
+ ((((int) buf[2]) & 0xff) << 8) |
+ (((int) buf[3]) & 0xff);
if (!readBytes(buf, 4)) return null;
- reply.returnCode = (((int) buf[0]) & 0xff) |
- ((((int) buf[1]) & 0xff) << 8) |
- ((((int) buf[2]) & 0xff) << 16) |
- ((((int) buf[3]) & 0xff) << 24);
+ reply.returnCode = ((((int) buf[0]) & 0xff) << 24) |
+ ((((int) buf[1]) & 0xff) << 16) |
+ ((((int) buf[2]) & 0xff) << 8) |
+ (((int) buf[3]) & 0xff);
if (reply.len > BUFFER_LENGTH) {
Log.e(mTag,"invalid reply length (" + reply.len + ")");
@@ -145,15 +146,15 @@
byte[] data = (_data == null) ? new byte[0] : _data.getBytes();
int len = data.length;
// the length of data
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- buf[2] = (byte) ((len >> 16) & 0xff);
- buf[3] = (byte) ((len >> 24) & 0xff);
+ buf[0] = (byte) ((len >> 24) & 0xff);
+ buf[1] = (byte) ((len >> 16) & 0xff);
+ buf[2] = (byte) ((len >> 8) & 0xff);
+ buf[3] = (byte) (len & 0xff);
// the opcode of the command
- buf[4] = (byte) (cmd & 0xff);
- buf[5] = (byte) ((cmd >> 8) & 0xff);
- buf[6] = (byte) ((cmd >> 16) & 0xff);
- buf[7] = (byte) ((cmd >> 24) & 0xff);
+ buf[4] = (byte) ((cmd >> 24) & 0xff);
+ buf[5] = (byte) ((cmd >> 16) & 0xff);
+ buf[6] = (byte) ((cmd >> 8) & 0xff);
+ buf[7] = (byte) (cmd & 0xff);
try {
mOut.write(buf, 0, 8);
mOut.write(data, 0, len);
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 16a4f2d..57a29f2 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -29,25 +29,41 @@
// ----------------------------------------------------------------------------
-A2dpAudioInterface::A2dpAudioInterface() :
- mOutput(0)
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+// AudioHardwareInterface* hw = 0;
+//
+// hw = AudioHardwareInterface::create();
+// LOGD("new A2dpAudioInterface(hw: %p)", hw);
+// hw = new A2dpAudioInterface(hw);
+// return hw;
+//}
+
+A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
+ mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true)
{
}
A2dpAudioInterface::~A2dpAudioInterface()
{
- delete mOutput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ delete mHardwareInterface;
}
status_t A2dpAudioInterface::initCheck()
{
- return 0;
+ if (mHardwareInterface == 0) return NO_INIT;
+ return mHardwareInterface->initCheck();
}
AudioStreamOut* A2dpAudioInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
- LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+ if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
+ LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
+ return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ }
+
status_t err = 0;
// only one output stream allowed
@@ -59,71 +75,127 @@
// create new output stream
A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
- if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+ if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
mOutput = out;
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
} else {
delete out;
}
-
+
if (status)
*status = err;
return mOutput;
}
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput == 0 || mOutput != out) {
+ mHardwareInterface->closeOutputStream(out);
+ }
+ else {
+ delete mOutput;
+ mOutput = 0;
+ }
+}
+
+
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
- status_t *status, AudioSystem::audio_in_acoustics acoustics)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
- if (status)
- *status = -1;
- return NULL;
+ return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+}
+
+void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
+{
+ return mHardwareInterface->closeInputStream(in);
+}
+
+status_t A2dpAudioInterface::setMode(int mode)
+{
+ return mHardwareInterface->setMode(mode);
}
status_t A2dpAudioInterface::setMicMute(bool state)
{
- return 0;
+ return mHardwareInterface->setMicMute(state);
}
status_t A2dpAudioInterface::getMicMute(bool* state)
{
- return 0;
+ return mHardwareInterface->getMicMute(state);
}
-status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
{
- LOGD("setParameter %s,%s\n", key, value);
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ status_t status = NO_ERROR;
- if (!key || !value)
- return -EINVAL;
+ LOGV("setParameters() %s", keyValuePairs.string());
- if (strcmp(key, "a2dp_sink_address") == 0) {
- return mOutput->setAddress(value);
- }
- if (strcmp(key, "bluetooth_enabled") == 0) {
- mOutput->setBluetoothEnabled(strcmp(value, "true") == 0);
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ mBluetoothEnabled = (value == "true");
+ if (mOutput) {
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
+ }
+ param.remove(key);
}
- return 0;
+ if (param.size()) {
+ status_t hwStatus = mHardwareInterface->setParameters(param.toString());
+ if (status == NO_ERROR) {
+ status = hwStatus;
+ }
+ }
+
+ return status;
+}
+
+String8 A2dpAudioInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter a2dpParam = AudioParameter();
+ String8 value;
+ String8 key;
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mBluetoothEnabled ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
+ }
+
+ String8 keyValuePairs = a2dpParam.toString();
+
+ if (param.size()) {
+ keyValuePairs += ";";
+ keyValuePairs += mHardwareInterface->getParameters(param.toString());
+ }
+
+ LOGV("getParameters() %s", keyValuePairs.string());
+ return keyValuePairs;
+}
+
+size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
}
status_t A2dpAudioInterface::setVoiceVolume(float v)
{
- return 0;
+ return mHardwareInterface->setVoiceVolume(v);
}
status_t A2dpAudioInterface::setMasterVolume(float v)
{
- return 0;
-}
-
-status_t A2dpAudioInterface::doRouting()
-{
- return 0;
+ return mHardwareInterface->setMasterVolume(v);
}
status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
{
- return 0;
+ return mHardwareInterface->dumpState(fd, args);
}
// ----------------------------------------------------------------------------
@@ -132,7 +204,7 @@
mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
// assume BT enabled to start, this is safe because its only the
// enabled->disabled transition we are worried about
- mBluetoothEnabled(true)
+ mBluetoothEnabled(true), mDevice(0), mClosing(false)
{
// use any address by default
strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -140,27 +212,43 @@
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
- int format, int channels, uint32_t rate)
+ uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())){
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mDevice = device;
return NO_ERROR;
}
A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
+ LOGV("A2dpAudioStreamOut destructor");
+ standby();
close();
+ LOGV("A2dpAudioStreamOut destructor returning from close()");
}
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
@@ -170,7 +258,7 @@
size_t remaining = bytes;
status_t status = -1;
- if (!mBluetoothEnabled) {
+ if (!mBluetoothEnabled || mClosing) {
LOGW("A2dpAudioStreamOut::write(), but bluetooth disabled");
goto Error;
}
@@ -219,6 +307,11 @@
{
int result = 0;
+ if (mClosing) {
+ LOGV("Ignore standby, closing");
+ return result;
+ }
+
Mutex::Autolock lock(mLock);
if (!mStandby) {
@@ -230,6 +323,64 @@
return result;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
+
+ if (param.get(key, value) == NO_ERROR) {
+ if (value.length() != strlen("00:00:00:00:00:00")) {
+ status = BAD_VALUE;
+ } else {
+ setAddress(value.string());
+ }
+ param.remove(key);
+ }
+ key = String8("closing");
+ if (param.get(key, value) == NO_ERROR) {
+ mClosing = (value == "true");
+ param.remove(key);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
+ mDevice = device;
+ status = NO_ERROR;
+ } else {
+ status = BAD_VALUE;
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+
+ if (param.get(key, value) == NO_ERROR) {
+ value = mA2dpAddress;
+ param.add(key, value);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
Mutex::Autolock lock(mLock);
@@ -260,12 +411,14 @@
status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
{
Mutex::Autolock lock(mLock);
+ LOGV("A2dpAudioStreamOut::close() calling close_l()");
return close_l();
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
{
if (mData) {
+ LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
a2dp_cleanup(mData);
mData = NULL;
}
@@ -277,5 +430,4 @@
return NO_ERROR;
}
-
}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 091e775..35a6e11 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -32,38 +32,44 @@
class A2dpAudioStreamOut;
public:
- A2dpAudioInterface();
+ A2dpAudioInterface(AudioHardwareInterface* hw);
virtual ~A2dpAudioInterface();
virtual status_t initCheck();
virtual status_t setVoiceVolume(float volume);
virtual status_t setMasterVolume(float volume);
+ virtual status_t setMode(int mode);
+
// mic mute
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- virtual status_t setParameter(const char *key, const char *value);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+// static AudioHardwareInterface* createA2dpInterface();
protected:
- virtual status_t doRouting();
virtual status_t dump(int fd, const Vector<String16>& args);
private:
@@ -71,19 +77,22 @@
public:
A2dpAudioStreamOut();
virtual ~A2dpAudioStreamOut();
- status_t set(int format,
- int channelCount,
- uint32_t sampleRate);
+ status_t set(uint32_t device,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
// SBC codec wants a multiple of 512
virtual size_t bufferSize() const { return 512 * 20; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
friend class A2dpAudioInterface;
@@ -102,11 +111,19 @@
void* mData;
Mutex mLock;
bool mBluetoothEnabled;
+ uint32_t mDevice;
+ bool mClosing;
};
+ friend class A2dpAudioStreamOut;
+
A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
};
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 50d516b..f5c03bb 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -1,16 +1,30 @@
LOCAL_PATH:= $(call my-dir)
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
include $(CLEAR_VARS)
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ ENABLE_AUDIO_DUMP := true
+endif
+
+
LOCAL_SRC_FILES:= \
AudioHardwareGeneric.cpp \
AudioHardwareStub.cpp \
- AudioDumpInterface.cpp \
AudioHardwareInterface.cpp
+ifeq ($(ENABLE_AUDIO_DUMP),true)
+ LOCAL_SRC_FILES += AudioDumpInterface.cpp
+ LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
+endif
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
libhardware_legacy
@@ -20,8 +34,44 @@
LOCAL_MODULE:= libaudiointerface
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+ LOCAL_SHARED_LIBRARIES += liba2dp
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez)
+endif
+
include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioPolicyManagerGeneric.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_MODULE:= libaudiopolicygeneric
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -29,28 +79,45 @@
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm
+ AudioResamplerCubic.cpp.arm \
+ AudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
- libhardware_legacy
+ libhardware_legacy \
+ libaudiopolicygeneric
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface
+ LOCAL_CFLAGS += -DGENERIC_AUDIO
else
- LOCAL_SHARED_LIBRARIES += libaudio
+ LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudioflinger
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
- LOCAL_SRC_FILES += A2dpAudioInterface.cpp
- LOCAL_SHARED_LIBRARIES += liba2dp
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
+ LOCAL_SHARED_LIBRARIES += liba2dp
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt -lpthread
+ endif
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index b4940cb..858e5aa 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "AudioFlingerDump"
+//#define LOG_NDEBUG 0
#include <stdint.h>
#include <sys/types.h>
@@ -28,68 +29,240 @@
namespace android {
-bool gFirst = true; // true if first write after a standby
-
// ----------------------------------------------------------------------------
AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+ : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8(""))
{
if(hw == 0) {
LOGE("Dump construct hw = 0");
}
mFinalInterface = hw;
- mStreamOut = 0;
+ LOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
}
AudioDumpInterface::~AudioDumpInterface()
{
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ closeOutputStream((AudioStreamOut *)mOutputs[i]);
+ }
if(mFinalInterface) delete mFinalInterface;
- if(mStreamOut) delete mStreamOut;
}
AudioStreamOut* AudioDumpInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
- AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
+ AudioStreamOut* outFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ uint32_t lRate = 44100;
- if(outFinal) {
- mStreamOut = new AudioStreamOutDump(outFinal);
- return mStreamOut;
+
+ if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) {
+ outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ if (outFinal != 0) {
+ lFormat = outFinal->format();
+ lChannels = outFinal->channels();
+ lRate = outFinal->sampleRate();
+ if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
+ mFirstHwOutput = false;
+ }
+ }
} else {
- LOGE("Dump outFinal=0");
- return 0;
+ if (format != 0 && *format != 0) {
+ lFormat = *format;
+ } else {
+ lFormat = AudioSystem::PCM_16_BIT;
+ }
+ if (channels != 0 && *channels != 0) {
+ lChannels = *channels;
+ } else {
+ lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ }
+ if (sampleRate != 0 && *sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ lRate = 44100;
+ }
+ if (status) *status = NO_ERROR;
}
+ LOGV("openOutputStream(), outFinal %p", outFinal);
+
+ AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal,
+ devices, lFormat, lChannels, lRate);
+ mOutputs.add(dumOutput);
+
+ return dumOutput;
}
+void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)
+{
+ AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out;
+
+ if (mOutputs.indexOf(dumpOut) < 0) {
+ LOGW("Attempt to close invalid output stream");
+ return;
+ }
+
+ LOGV("closeOutputStream() output %p", out);
+
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ mFirstHwOutput = true;
+ }
+
+ mOutputs.remove(dumpOut);
+ delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+ AudioStreamIn* inFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+ uint32_t lRate = 8000;
+
+
+ if (mInputs.size() == 0) {
+ inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ if (inFinal == 0) return 0;
+
+ lFormat = inFinal->format();
+ lChannels = inFinal->channels();
+ lRate = inFinal->sampleRate();
+ } else {
+ if (format != 0 && *format != 0) lFormat = *format;
+ if (channels != 0 && *channels != 0) lChannels = *channels;
+ if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+ if (status) *status = NO_ERROR;
+ }
+ LOGV("openInputStream(), inFinal %p", inFinal);
+
+ AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal,
+ devices, lFormat, lChannels, lRate);
+ mInputs.add(dumInput);
+
+ return dumInput;
+}
+void AudioDumpInterface::closeInputStream(AudioStreamIn* in)
+{
+ AudioStreamInDump *dumpIn = (AudioStreamInDump *)in;
+
+ if (mInputs.indexOf(dumpIn) < 0) {
+ LOGW("Attempt to close invalid input stream");
+ return;
+ }
+ dumpIn->standby();
+ if (dumpIn->finalStream() != NULL) {
+ mFinalInterface->closeInputStream(dumpIn->finalStream());
+ }
+
+ mInputs.remove(dumpIn);
+ delete dumpIn;
+}
+
+
+status_t AudioDumpInterface::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ LOGV("setParameters %s", keyValuePairs.string());
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ mFileName = value;
+ param.remove(String8("test_cmd_file_name"));
+ }
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ param.remove(String8("test_cmd_policy"));
+ mPolicyCommands = param.toString();
+ LOGV("test_cmd_policy command %s written", mPolicyCommands.string());
+ return NO_ERROR;
+ }
+
+ if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioDumpInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter response;
+ String8 value;
+
+// LOGV("getParameters %s", keys.string());
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ if (mPolicyCommands.length() != 0) {
+ response = AudioParameter(mPolicyCommands);
+ response.addInt(String8("test_cmd_policy"), 1);
+ } else {
+ response.addInt(String8("test_cmd_policy"), 0);
+ }
+ param.remove(String8("test_cmd_policy"));
+// LOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ }
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ response.add(String8("test_cmd_file_name"), mFileName);
+ param.remove(String8("test_cmd_file_name"));
+ }
+
+ String8 keyValuePairs = response.toString();
+
+ if (param.size() && mFinalInterface != 0 ) {
+ keyValuePairs += ";";
+ keyValuePairs += mFinalInterface->getParameters(param.toString());
+ }
+
+ return keyValuePairs;
+}
+
+
// ----------------------------------------------------------------------------
-AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0)
{
- mFinalStream = finalStream;
- mOutFile = 0;
+ LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
}
AudioStreamOutDump::~AudioStreamOutDump()
{
+ LOGV("AudioStreamOutDump destructor");
Close();
- delete mFinalStream;
}
ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
{
ssize_t ret;
- ret = mFinalStream->write(buffer, bytes);
- if(!mOutFile && gFirst) {
- gFirst = false;
- // check if dump file exist
- mOutFile = fopen(FLINGER_DUMP_NAME, "r");
- if(mOutFile) {
- fclose(mOutFile);
- mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ if (mFinalStream) {
+ ret = mFinalStream->write(buffer, bytes);
+ } else {
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+ ret = bytes;
+ }
+ if(!mOutFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mOutFile = fopen(name, "wb");
+ LOGV("Opening dump file %s, fh %p", name, mOutFile);
}
}
if (mOutFile) {
@@ -100,13 +273,105 @@
status_t AudioStreamOutDump::standby()
{
+ LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream);
+
Close();
- gFirst = true;
- return mFinalStream->standby();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
}
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
-void AudioStreamOutDump::Close(void)
+size_t AudioStreamOutDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->latency();
+ return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+ return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+ if (mFinalStream != 0 ) {
+ return mFinalStream->setParameters(keyValuePairs);
+ }
+
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ status_t status = NO_ERROR;
+
+ if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+ mId = valueInt;
+ }
+
+ if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+ if (mOutFile == 0) {
+ mFormat = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ }
+ if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+ if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+ mChannels = valueInt;
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+ if (valueInt > 0 && valueInt <= 48000) {
+ if (mOutFile == 0) {
+ mSampleRate = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ return status;
+}
+
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
{
if(mOutFile) {
fclose(mOutFile);
@@ -114,4 +379,141 @@
}
}
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mInFile(0)
+{
+ LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+ Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+ if (mFinalStream) {
+ return mFinalStream->read(buffer, bytes);
+ }
+
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+
+ if(!mInFile) {
+ char name[255];
+ strcpy(name, "/sdcard/music/sine440");
+ if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+ strcat(name, "_mo");
+ } else {
+ strcat(name, "_st");
+ }
+ if (format() == AudioSystem::PCM_16_BIT) {
+ strcat(name, "_16b");
+ } else {
+ strcat(name, "_8b");
+ }
+ if (sampleRate() < 16000) {
+ strcat(name, "_8k");
+ } else if (sampleRate() < 32000) {
+ strcat(name, "_22k");
+ } else if (sampleRate() < 48000) {
+ strcat(name, "_44k");
+ } else {
+ strcat(name, "_48k");
+ }
+ strcat(name, ".wav");
+ mInFile = fopen(name, "rb");
+ LOGV("Opening dump file %s, fh %p", name, mInFile);
+ if (mInFile) {
+ fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ }
+
+ }
+ if (mInFile) {
+ ssize_t bytesRead = fread(buffer, bytes, 1, mInFile);
+ if (bytesRead != bytes) {
+ fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile);
+ }
+ }
+ return bytes;
+}
+
+status_t AudioStreamInDump::standby()
+{
+ LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamInDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+ if(mInFile) {
+ fclose(mInFile);
+ mInFile = 0;
+ }
+}
}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index b72c94e..1136ce1 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -20,35 +20,95 @@
#include <stdint.h>
#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
#include <hardware_legacy/AudioHardwareBase.h>
namespace android {
-#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
class AudioStreamOutDump : public AudioStreamOut {
public:
- AudioStreamOutDump( AudioStreamOut* FinalStream);
+ AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
~AudioStreamOutDump();
- virtual ssize_t write(const void* buffer, size_t bytes);
- virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); }
- virtual size_t bufferSize() const { return mFinalStream->bufferSize(); }
- virtual int channelCount() const { return mFinalStream->channelCount(); }
- virtual int format() const { return mFinalStream->format(); }
- virtual uint32_t latency() const { return mFinalStream->latency(); }
- virtual status_t setVolume(float volume)
- { return mFinalStream->setVolume(volume); }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+ virtual uint32_t latency() const;
+ virtual status_t setVolume(float left, float right);
virtual status_t standby();
- virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
void Close(void);
+ AudioStreamOut* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+ int getId() { return mId; }
private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
AudioStreamOut *mFinalStream;
- FILE *mOutFile; // output file
+ FILE *mOutFile; // output file
+ int mFileCount;
};
+class AudioStreamInDump : public AudioStreamIn {
+public:
+ AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamInDump();
+
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+
+ virtual status_t setGain(float gain);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamIn* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamIn *mFinalStream;
+ FILE *mInFile; // output file
+};
class AudioDumpInterface : public AudioHardwareBase
{
@@ -56,10 +116,13 @@
public:
AudioDumpInterface(AudioHardwareInterface* hw);
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
virtual ~AudioDumpInterface();
virtual status_t initCheck()
@@ -75,21 +138,25 @@
virtual status_t getMicMute(bool* state)
{return mFinalInterface->getMicMute(state);}
- virtual status_t setParameter(const char* key, const char* value)
- {return mFinalInterface->setParameter(key, value);}
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
- virtual AudioStreamIn* openInputStream(int inputSource, int format, int channelCount,
- uint32_t sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
- { return mFinalInterface->openInputStream(inputSource, format, channelCount, sampleRate, status, acoustics); }
+ virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+ String8 fileName() const { return mFileName; }
protected:
- virtual status_t doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
- AudioHardwareInterface *mFinalInterface;
- AudioStreamOutDump *mStreamOut;
-
+ AudioHardwareInterface *mFinalInterface;
+ SortedVector<AudioStreamOutDump *> mOutputs;
+ bool mFirstHwOutput;
+ SortedVector<AudioStreamInDump *> mInputs;
+ Mutex mLock;
+ String8 mPolicyCommands;
+ String8 mFileName;
};
}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index da7cc8a..77a126c 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -24,10 +24,10 @@
#include <sys/time.h>
#include <sys/resource.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/threads.h>
@@ -71,15 +71,9 @@
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
-static const int kStartSleepTime = 30000;
-static const int kStopSleepTime = 30000;
-
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 20000;
-// Maximum number of pending buffers allocated by OutputTrack::write()
-static const uint8_t kMaxOutputTrackBuffers = 5;
-
#define AUDIOFLINGER_SECURITY_ENABLED 1
@@ -121,132 +115,32 @@
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
- mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
- mRouteRestoreTime(0), mMusicMuteSaved(false)
+ mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
{
mHardwareStatus = AUDIO_HW_IDLE;
+
mAudioHardware = AudioHardwareInterface::create();
+
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
- mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status_t status;
- AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mHardwareStatus = AUDIO_HW_IDLE;
- if (hwOutput) {
- mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
- } else {
- LOGE("Failed to initialize hardware output stream, status: %d", status);
- }
-
-#ifdef WITH_A2DP
- // Create A2DP interface
- mA2dpAudioInterface = new A2dpAudioInterface();
- AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- if (a2dpOutput) {
- mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
- if (hwOutput) {
- uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
- MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
- hwOutput->sampleRate(),
- AudioSystem::PCM_16_BIT,
- hwOutput->channelCount(),
- frameCount);
- mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
- }
- } else {
- LOGE("Failed to initialize A2DP output stream, status: %d", status);
- }
-#endif
-
- // FIXME - this should come from settings
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+
setMode(AudioSystem::MODE_NORMAL);
setMasterVolume(1.0f);
setMasterMute(false);
-
- // Start record thread
- mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
- }
- } else {
+ } else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
}
AudioFlinger::~AudioFlinger()
{
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->exit();
- mAudioRecordThread.clear();
- }
- mHardwareMixerThread.clear();
- delete mAudioHardware;
- // deleting mA2dpAudioInterface also deletes mA2dpOutput;
-#ifdef WITH_A2DP
- mA2dpMixerThread.clear();
- delete mA2dpAudioInterface;
-#endif
+ mRecordThreads.clear();
+ mPlaybackThreads.clear();
}
-#ifdef WITH_A2DP
-// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::setA2dpEnabled_l(bool enable)
-{
- SortedVector < sp<MixerThread::Track> > tracks;
- SortedVector < wp<MixerThread::Track> > activeTracks;
-
- LOGD_IF(enable, "set output to A2DP\n");
- LOGD_IF(!enable, "set output to hardware audio\n");
-
- // Transfer tracks playing on MUSIC stream from one mixer to the other
- if (enable) {
- mHardwareMixerThread->getTracks_l(tracks, activeTracks);
- mA2dpMixerThread->putTracks_l(tracks, activeTracks);
- } else {
- mA2dpMixerThread->getTracks_l(tracks, activeTracks);
- mHardwareMixerThread->putTracks_l(tracks, activeTracks);
- mA2dpMixerThread->mOutput->standby();
- }
- mA2dpEnabled = enable;
- mNotifyA2dpChange = true;
- mWaitWorkCV.broadcast();
-}
-
-// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::checkA2dpEnabledChange_l()
-{
- if (mNotifyA2dpChange) {
- // Notify AudioSystem of the A2DP activation/deactivation
- size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
- if (binder != NULL) {
- LOGV("Notifying output change to client %p", binder.get());
- sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
- client->a2dpEnabledChanged(mA2dpEnabled);
- }
- }
- mNotifyA2dpChange = false;
- }
-}
-#endif // WITH_A2DP
-
-bool AudioFlinger::streamForcedToSpeaker(int streamType)
-{
- // NOTE that streams listed here must not be routed to A2DP by default:
- // AudioSystem::routedToA2dpOutput(streamType) == false
- return (streamType == AudioSystem::RING ||
- streamType == AudioSystem::ALARM ||
- streamType == AudioSystem::NOTIFICATION ||
- streamType == AudioSystem::ENFORCED_AUDIBLE);
-}
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
@@ -276,10 +170,7 @@
char buffer[SIZE];
String8 result;
int hardwareStatus = mHardwareStatus;
-
- if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
- hardwareStatus = AUDIO_HW_STANDBY;
- }
+
snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
write(fd, result.string(), result.size());
@@ -337,13 +228,16 @@
dumpClients(fd, args);
dumpInternals(fd, args);
- mHardwareMixerThread->dump(fd, args);
-#ifdef WITH_A2DP
- mA2dpMixerThread->dump(fd, args);
-#endif
- // dump record client
- if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+ // dump playback threads
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->dump(fd, args);
+ }
+
+ // dump record threads
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->dump(fd, args);
+ }
if (mAudioHardware) {
mAudioHardware->dumpState(fd, args);
@@ -353,6 +247,7 @@
return NO_ERROR;
}
+
// IAudioFlinger interface
@@ -365,9 +260,10 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status)
{
- sp<MixerThread::Track> track;
+ sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
@@ -381,6 +277,12 @@
{
Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGE("unknown output thread");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
wclient = mClients.valueFor(pid);
@@ -390,16 +292,8 @@
client = new Client(this, pid);
mClients.add(pid, client);
}
-#ifdef WITH_A2DP
- if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
- track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- } else
-#endif
- {
- track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- }
+ track = thread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
}
if (lStatus == NO_ERROR) {
trackHandle = new TrackHandle(track);
@@ -416,52 +310,57 @@
uint32_t AudioFlinger::sampleRate(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->sampleRate();
- }
-#endif
- return mHardwareMixerThread->sampleRate();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("sampleRate() unknown thread %d", output);
+ return 0;
+ }
+ return thread->sampleRate();
}
int AudioFlinger::channelCount(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->channelCount();
- }
-#endif
- return mHardwareMixerThread->channelCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("channelCount() unknown thread %d", output);
+ return 0;
+ }
+ return thread->channelCount();
}
int AudioFlinger::format(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->format();
- }
-#endif
- return mHardwareMixerThread->format();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("format() unknown thread %d", output);
+ return 0;
+ }
+ return thread->format();
}
size_t AudioFlinger::frameCount(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->frameCount();
- }
-#endif
- return mHardwareMixerThread->frameCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("frameCount() unknown thread %d", output);
+ return 0;
+ }
+ return thread->frameCount();
}
uint32_t AudioFlinger::latency(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->latency();
- }
-#endif
- return mHardwareMixerThread->latency();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("latency() unknown thread %d", output);
+ return 0;
+ }
+ return thread->latency();
}
status_t AudioFlinger::setMasterVolume(float value)
@@ -478,96 +377,14 @@
value = 1.0f;
}
mHardwareStatus = AUDIO_HW_IDLE;
- mHardwareMixerThread->setMasterVolume(value);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterVolume(value);
-#endif
+
+ mMasterVolume = value;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMasterVolume(value);
return NO_ERROR;
}
-status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- status_t err = NO_ERROR;
-
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
- LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
- return BAD_VALUE;
- }
-
-#ifdef WITH_A2DP
- LOGV("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(),
- IPCThreadState::self()->getCallingPid());
- if (mode == AudioSystem::MODE_NORMAL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
- AutoMutex lock(&mLock);
-
- bool enableA2dp = false;
- if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
- enableA2dp = true;
- }
- if (mA2dpDisableCount > 0) {
- mA2dpSuppressed = enableA2dp;
- } else {
- setA2dpEnabled_l(enableA2dp);
- }
- LOGV("setOutput done\n");
- }
- // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when
- // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only
- // in this case to avoid doing it several times.
- if (mode == AudioSystem::MODE_IN_CALL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) {
- AutoMutex lock(&mLock);
- handleRouteDisablesA2dp_l(routes);
- }
-#endif
-
- // do nothing if only A2DP routing is affected
- mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
- if (mask) {
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- uint32_t r;
- err = mAudioHardware->getRouting(mode, &r);
- if (err == NO_ERROR) {
- r = (r & ~mask) | (routes & mask);
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- mSavedRoute = r;
- r |= mForcedRoute;
- LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
- }
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- err = mAudioHardware->setRouting(mode, r);
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- return err;
-}
-
-uint32_t AudioFlinger::getRouting(int mode) const
-{
- uint32_t routes = 0;
- if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- routes = mSavedRoute;
- } else {
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- mAudioHardware->getRouting(mode, &routes);
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- } else {
- LOGW("Illegal value: getRouting(%d)", mode);
- }
- return routes;
-}
-
status_t AudioFlinger::setMode(int mode)
{
// check calling permissions
@@ -586,15 +403,6 @@
return ret;
}
-int AudioFlinger::getMode() const
-{
- int mode = AudioSystem::MODE_INVALID;
- mHardwareStatus = AUDIO_HW_SET_MODE;
- mAudioHardware->getMode(&mode);
- mHardwareStatus = AUDIO_HW_IDLE;
- return mode;
-}
-
status_t AudioFlinger::setMicMute(bool state)
{
// check calling permissions
@@ -624,36 +432,46 @@
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- mHardwareMixerThread->setMasterMute(muted);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterMute(muted);
-#endif
+
+ mMasterMute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMasterMute(muted);
+
return NO_ERROR;
}
float AudioFlinger::masterVolume() const
{
- return mHardwareMixerThread->masterVolume();
+ return mMasterVolume;
}
bool AudioFlinger::masterMute() const
{
- return mHardwareMixerThread->masterMute();
+ return mMasterMute;
}
-status_t AudioFlinger::setStreamVolume(int stream, float value)
+status_t AudioFlinger::setStreamVolume(int stream, float value, int output)
{
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
- uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
+ PlaybackThread *thread = NULL;
+ if (output) {
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+ }
+
status_t ret = NO_ERROR;
+
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float hwValue;
@@ -670,12 +488,18 @@
mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
ret = mAudioHardware->setVoiceVolume(hwValue);
mHardwareStatus = AUDIO_HW_IDLE;
+
}
- mHardwareMixerThread->setStreamVolume(stream, value);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setStreamVolume(stream, value);
-#endif
+ mStreamTypes[stream].volume = value;
+
+ if (thread == NULL) {
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
+
+ } else {
+ thread->setStreamVolume(stream, value);
+ }
return ret;
}
@@ -687,82 +511,116 @@
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
return BAD_VALUE;
}
-#ifdef WITH_A2DP
- mA2dpMixerThread->setStreamMute(stream, muted);
-#endif
- if (stream == AudioSystem::MUSIC)
- {
- AutoMutex lock(&mHardwareLock);
- if (mForcedRoute != 0)
- mMusicMuteSaved = muted;
- else
- mHardwareMixerThread->setStreamMute(stream, muted);
- } else {
- mHardwareMixerThread->setStreamMute(stream, muted);
- }
+ mStreamTypes[stream].mute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
return NO_ERROR;
}
-float AudioFlinger::streamVolume(int stream) const
+float AudioFlinger::streamVolume(int stream, int output) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return 0.0f;
}
-
- float volume = mHardwareMixerThread->streamVolume(stream);
+
+ AutoMutex lock(mLock);
+ float volume;
+ if (output) {
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return 0.0f;
+ }
+ volume = thread->streamVolume(stream);
+ } else {
+ volume = mStreamTypes[stream].volume;
+ }
+
// remove correction applied by setStreamVolume()
if (stream == AudioSystem::VOICE_CALL) {
volume = (volume - 0.01) / 0.99 ;
}
-
+
return volume;
}
bool AudioFlinger::streamMute(int stream) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || stream >= (int)AudioSystem::NUM_STREAM_TYPES) {
return true;
}
-
- if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
- {
- return mMusicMuteSaved;
- }
- return mHardwareMixerThread->streamMute(stream);
+
+ return mStreamTypes[stream].mute;
}
bool AudioFlinger::isMusicActive() const
{
Mutex::Autolock _l(mLock);
- #ifdef WITH_A2DP
- if (isA2dpEnabled()) {
- return mA2dpMixerThread->isMusicActive_l();
- }
- #endif
- return mHardwareMixerThread->isMusicActive_l();
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->isMusicActive()) {
+ return true;
+ }
+ }
+ return false;
}
-status_t AudioFlinger::setParameter(const char* key, const char* value)
+status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
{
- status_t result, result2;
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_SET_PARAMETER;
-
- LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
- result = mAudioHardware->setParameter(key, value);
- if (mA2dpAudioInterface) {
- result2 = mA2dpAudioInterface->setParameter(key, value);
- if (result2)
- result = result2;
+ status_t result;
+
+ LOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
+ ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
}
- mHardwareStatus = AUDIO_HW_IDLE;
- return result;
+
+ // ioHandle == 0 means the parameters are global to the audio hardware interface
+ if (ioHandle == 0) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+ result = mAudioHardware->setParameters(keyValuePairs);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+ }
+
+ // Check if parameters are for an output
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->setParameters(keyValuePairs);
+ }
+
+ // Check if parameters are for an input
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->setParameters(keyValuePairs);
+ }
+
+ return BAD_VALUE;
+}
+
+String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
+{
+// LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
+
+ if (ioHandle == 0) {
+ return mAudioHardware->getParameters(keys);
+ }
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->getParameters(keys);
+ }
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->getParameters(keys);
+ }
+ return String8("");
}
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
@@ -772,7 +630,7 @@
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
{
-
+
LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
@@ -781,12 +639,21 @@
LOGV("Adding notification client %p", binder.get());
binder->linkToDeath(this);
mNotificationClients.add(binder);
- client->a2dpEnabledChanged(isA2dpEnabled());
+ }
+
+ // the config change is always sent from playback or record threads to avoid deadlock
+ // with AudioSystem::gLock
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+ }
+
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
}
}
void AudioFlinger::binderDied(const wp<IBinder>& who) {
-
+
LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
@@ -801,6 +668,36 @@
}
}
+void AudioFlinger::audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2) {
+ Mutex::Autolock _l(mLock);
+ int ioHandle = 0;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i) == thread) {
+ ioHandle = mPlaybackThreads.keyAt(i);
+ break;
+ }
+ }
+ if (ioHandle == 0) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i) == thread) {
+ ioHandle = mRecordThreads.keyAt(i);
+ break;
+ }
+ }
+ }
+
+ if (ioHandle != 0) {
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i);
+ LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->ioConfigChanged(event, ioHandle, param2);
+ }
+ }
+}
+
void AudioFlinger::removeClient(pid_t pid)
{
LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
@@ -808,147 +705,146 @@
mClients.removeItem(pid);
}
-bool AudioFlinger::isA2dpEnabled() const
+// ----------------------------------------------------------------------------
+
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger)
+ : Thread(false),
+ mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
+ mFormat(0), mFrameSize(1), mStandby(false)
{
- return mA2dpEnabled;
}
-void AudioFlinger::handleForcedSpeakerRoute(int command)
+AudioFlinger::ThreadBase::~ThreadBase()
{
- switch(command) {
- case ACTIVE_TRACK_ADDED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount++ == 0) {
- if (mForcedRoute == 0) {
- mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
- LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
- usleep(mHardwareMixerThread->latency()*1000);
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareStatus = AUDIO_HW_IDLE;
- // delay track start so that audio hardware has time to siwtch routes
- usleep(kStartSleepTime);
- }
- }
- mForcedRoute = AudioSystem::ROUTE_SPEAKER;
- mRouteRestoreTime = 0;
- }
- LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
- }
- break;
- case ACTIVE_TRACK_REMOVED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount > 0){
- if (--mForcedSpeakerCount == 0) {
- mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
- }
- LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
- } else {
- LOGE("mForcedSpeakerCount is already zero");
- }
- }
- break;
- case CHECK_ROUTE_RESTORE_TIME:
- case FORCE_ROUTE_RESTORE:
- if (mRouteRestoreTime) {
- AutoMutex lock(mHardwareLock);
- if (mRouteRestoreTime &&
- (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
- mForcedRoute = 0;
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
- mHardwareStatus = AUDIO_HW_IDLE;
- LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
- }
- mRouteRestoreTime = 0;
- }
- }
- break;
- }
+ mParamCond.broadcast();
+ mNewParameters.clear();
}
-#ifdef WITH_A2DP
-// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::handleRouteDisablesA2dp_l(int routes)
+void AudioFlinger::ThreadBase::exit()
{
- if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) {
- if (mA2dpDisableCount++ == 0) {
- if (mA2dpEnabled) {
- setA2dpEnabled_l(false);
- mA2dpSuppressed = true;
- }
- }
- LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
- } else {
- if (mA2dpDisableCount > 0) {
- if (--mA2dpDisableCount == 0) {
- if (mA2dpSuppressed) {
- setA2dpEnabled_l(true);
- mA2dpSuppressed = false;
- }
- }
- LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
- } else {
- LOGV("mA2dpDisableCount is already zero");
- }
+ // keep a strong ref on ourself so that we want get
+ // destroyed in the middle of requestExitAndWait()
+ sp <ThreadBase> strongMe = this;
+
+ LOGV("ThreadBase::exit");
+ {
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
}
+ requestExitAndWait();
}
-#endif
+
+uint32_t AudioFlinger::ThreadBase::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioFlinger::ThreadBase::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioFlinger::ThreadBase::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::ThreadBase::frameCount() const
+{
+ return mFrameCount;
+}
+
+status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
+{
+ status_t status;
+
+ LOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
+ Mutex::Autolock _l(mLock);
+
+ mNewParameters.add(keyValuePairs);
+ mWaitWorkCV.signal();
+ mParamCond.wait(mLock);
+ status = mParamStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
+{
+ Mutex::Autolock _l(mLock);
+ sendConfigEvent_l(event, param);
+}
+
+// sendConfigEvent_l() must be called with ThreadBase::mLock held
+void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
+{
+ ConfigEvent *configEvent = new ConfigEvent();
+ configEvent->mEvent = event;
+ configEvent->mParam = param;
+ mConfigEvents.add(configEvent);
+ LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
+ mWaitWorkCV.signal();
+}
+
+void AudioFlinger::ThreadBase::processConfigEvents()
+{
+ mLock.lock();
+ while(!mConfigEvents.isEmpty()) {
+ LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
+ ConfigEvent *configEvent = mConfigEvents[0];
+ mConfigEvents.removeAt(0);
+ // release mLock because audioConfigChanged() will call
+ // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating
+ // potential cross deadlock between AudioFlinger::mLock and mLock
+ mLock.unlock();
+ audioConfigChanged(configEvent->mEvent, configEvent->mParam);
+ delete configEvent;
+ mLock.lock();
+ }
+ mLock.unlock();
+}
+
// ----------------------------------------------------------------------------
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
- : Thread(false),
- mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false)
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : ThreadBase(audioFlinger),
+ mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
+ readOutputParameters();
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
+ mMasterVolume = mAudioFlinger->masterVolume();
+ mMasterMute = mAudioFlinger->masterMute();
+
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
+ mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
}
-
- mFormat = output->format();
- mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
- mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
-
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[mFrameCount * 2];
- memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+ // notify client processes that a new input has been opened
+ sendConfigEvent(AudioSystem::OUTPUT_OPENED);
}
-AudioFlinger::MixerThread::~MixerThread()
+AudioFlinger::PlaybackThread::~PlaybackThread()
{
delete [] mMixBuffer;
- delete mAudioMixer;
}
-status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
{
dumpInternals(fd, args);
dumpTracks(fd, args);
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mTracks.size(); ++i) {
@@ -959,7 +855,7 @@
}
}
- snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mActiveTracks.size(); ++i) {
@@ -976,15 +872,13 @@
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
- result.append(buffer);
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ snprintf(buffer, SIZE, "Output thread %p internals\n", this);
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -1001,275 +895,28 @@
}
// Thread virtuals
-bool AudioFlinger::MixerThread::threadLoop()
-{
- unsigned long sleepTime = kBufferRecoveryInUsecs;
- int16_t* curBuf = mMixBuffer;
- Vector< sp<Track> > tracksToRemove;
- size_t enabledTracks = 0;
- nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
- nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-
-#ifdef WITH_A2DP
- bool outputTrackActive = false;
-#endif
-
- do {
- enabledTracks = 0;
- { // scope for the AudioFlinger::mLock
-
- Mutex::Autolock _l(mAudioFlinger->mLock);
-
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
- }
- mAudioFlinger->checkA2dpEnabledChange_l();
-#endif
-
- const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
- // put audio hardware into standby after short delay
- if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
- // wait until we have something to do...
- LOGV("Audio hardware entering standby, output %d\n", mOutputType);
- if (!mStandby) {
- mOutput->standby();
- mStandby = true;
- }
-
-#ifdef WITH_A2DP
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
-#endif
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
- }
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
- LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
-
- if (mMasterMute == false) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.audio.silent", value, "0");
- if (atoi(value)) {
- LOGD("Silence is golden");
- setMasterMute(true);
- }
- }
-
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- continue;
- }
-
- // Forced route to speaker is handled by hardware mixer thread
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
- }
-
- // find out which tracks need to be processed
- size_t count = activeTracks.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<Track> t = activeTracks[i].promote();
- if (t == 0) continue;
-
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
-
- // The first time a track is added we wait
- // for all its buffers to be filled before processing it
- mAudioMixer->setActiveTrack(track->name());
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
- !track->isPaused())
- {
- //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
-
- // compute volume for this track
- int16_t left, right;
- if (track->isMuted() || mMasterMute || track->isPausing()) {
- left = right = 0;
- if (track->isPausing()) {
- LOGV("paused(%d)", track->name());
- track->setPaused();
- }
- } else {
- float typeVolume = mStreamTypes[track->type()].volume;
- float v = mMasterVolume * typeVolume;
- float v_clamped = v * cblk->volume[0];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = int16_t(v_clamped);
- v_clamped = v * cblk->volume[1];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = int16_t(v_clamped);
- }
-
- // XXX: these things DON'T need to be done each time
- mAudioMixer->setBufferProvider(track);
- mAudioMixer->enable(AudioMixer::MIXING);
-
- int param;
- if ( track->mFillingUpStatus == Track::FS_FILLED) {
- // no ramp for the first volume setting
- track->mFillingUpStatus = Track::FS_ACTIVE;
- if (track->mState == TrackBase::RESUMING) {
- track->mState = TrackBase::ACTIVE;
- param = AudioMixer::RAMP_VOLUME;
- } else {
- param = AudioMixer::VOLUME;
- }
- } else {
- param = AudioMixer::RAMP_VOLUME;
- }
- mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
- mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::FORMAT, track->format());
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::CHANNEL_COUNT, track->channelCount());
- mAudioMixer->setParameter(
- AudioMixer::RESAMPLE,
- AudioMixer::SAMPLE_RATE,
- int(cblk->sampleRate));
-
- // reset retry count
- track->mRetryCount = kMaxTrackRetries;
- enabledTracks++;
- } else {
- //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
- if (track->isStopped()) {
- track->reset();
- }
- if (track->isTerminated() || track->isStopped() || track->isPaused()) {
- // We have consumed all the buffers of this track.
- // Remove it from the list of active tracks.
- LOGV("remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- } else {
- // No buffers for this track. Give it a few chances to
- // fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- }
- }
- // LOGV("disable(%d)", track->name());
- mAudioMixer->disable(AudioMixer::MIXING);
- }
- }
-
- // remove all the tracks that need to be...
- count = tracksToRemove.size();
- if (UNLIKELY(count)) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<Track>& track = tracksToRemove[i];
- removeActiveTrack_l(track);
- if (track->isTerminated()) {
- mTracks.remove(track);
- deleteTrackName_l(track->mName);
- }
- }
- }
- }
-
- if (LIKELY(enabledTracks)) {
- // mix buffers...
- mAudioMixer->process(curBuf);
-
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (!outputTrackActive) {
- LOGV("starting output track in mixer for output %d", mOutputType);
- mOutputTrack->start();
- outputTrackActive = true;
- }
- mOutputTrack->write(curBuf, mFrameCount);
- }
-#endif
-
- // output audio to hardware
- mLastWriteTime = systemTime();
- mInWrite = true;
- mOutput->write(curBuf, mixBufferSize);
- mNumWrites++;
- mInWrite = false;
- mStandby = false;
- nsecs_t temp = systemTime();
- standbyTime = temp + kStandbyTimeInNsecs;
- nsecs_t delta = temp - mLastWriteTime;
- if (delta > maxPeriod) {
- LOGW("write blocked for %llu msecs", ns2ms(delta));
- mNumDelayedWrites++;
- }
- sleepTime = kBufferRecoveryInUsecs;
- } else {
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mOutputTrack->write(curBuf, 0);
- if (mOutputTrack->bufferQueueEmpty()) {
- mOutputTrack->stop();
- outputTrackActive = false;
- } else {
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- }
- }
- }
-#endif
- // There was nothing to mix this round, which means all
- // active tracks were late. Sleep a little bit to give
- // them another chance. If we're too late, the audio
- // hardware will zero-fill for us.
- //LOGV("no buffers - usleep(%lu)", sleepTime);
- usleep(sleepTime);
- if (sleepTime < kMaxBufferRecoveryInUsecs) {
- sleepTime += kBufferRecoveryInUsecs;
- }
- }
-
- // finally let go of all our tracks, without the lock held
- // since we can't guarantee the destructors won't acquire that
- // same lock.
- tracksToRemove.clear();
- } while (true);
-
- return false;
-}
-
-status_t AudioFlinger::MixerThread::readyToRun()
+status_t AudioFlinger::PlaybackThread::readyToRun()
{
if (mSampleRate == 0) {
LOGE("No working audio driver found.");
return NO_INIT;
}
- LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+ LOGI("AudioFlinger's thread %p ready to run", this);
return NO_ERROR;
}
-void AudioFlinger::MixerThread::onFirstRef()
+void AudioFlinger::PlaybackThread::onFirstRef()
{
const size_t SIZE = 256;
char buffer[SIZE];
- snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+ snprintf(buffer, SIZE, "Playback Thread %p", this);
run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
}
-// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
+// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
const sp<AudioFlinger::Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1281,28 +928,39 @@
{
sp<Track> track;
status_t lStatus;
-
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
- lStatus = BAD_VALUE;
- goto Exit;
+
+ if (mType == DIRECT) {
+ if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) {
+ LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p",
+ sampleRate, format, channelCount, mOutput);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ } else {
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > mSampleRate*2) {
+ LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
}
-
- if (mSampleRate == 0) {
+ if (mOutput == 0) {
LOGE("Audio driver not initialized.");
lStatus = NO_INIT;
goto Exit;
}
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer);
- if (track->getCblk() == NULL) {
- lStatus = NO_MEMORY;
- goto Exit;
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+ mTracks.add(track);
}
- mTracks.add(track);
lStatus = NO_ERROR;
Exit:
@@ -1312,87 +970,7 @@
return track;
}
-// getTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::getTracks_l(
- SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks)
-{
- size_t size = mTracks.size();
- LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
- for (size_t i = 0; i < size; i++) {
- sp<Track> t = mTracks[i];
- if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
- tracks.add(t);
- int j = mActiveTracks.indexOf(t);
- if (j >= 0) {
- t = mActiveTracks[j].promote();
- if (t != NULL) {
- activeTracks.add(t);
- }
- }
- }
- }
-
- size = activeTracks.size();
- for (size_t i = 0; i < size; i++) {
- removeActiveTrack_l(activeTracks[i]);
- }
-
- size = tracks.size();
- for (size_t i = 0; i < size; i++) {
- sp<Track> t = tracks[i];
- mTracks.remove(t);
- deleteTrackName_l(t->name());
- }
-}
-
-// putTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::putTracks_l(
- SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks)
-{
-
- LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
-
- size_t size = tracks.size();
- for (size_t i = 0; i < size ; i++) {
- sp<Track> t = tracks[i];
- int name = getTrackName_l();
-
- if (name < 0) return;
-
- t->mName = name;
- t->mMixerThread = this;
- mTracks.add(t);
-
- int j = activeTracks.indexOf(t);
- if (j >= 0) {
- addActiveTrack_l(t);
- }
- }
-}
-
-uint32_t AudioFlinger::MixerThread::sampleRate() const
-{
- return mSampleRate;
-}
-
-int AudioFlinger::MixerThread::channelCount() const
-{
- return mChannelCount;
-}
-
-int AudioFlinger::MixerThread::format() const
-{
- return mFormat;
-}
-
-size_t AudioFlinger::MixerThread::frameCount() const
-{
- return mFrameCount;
-}
-
-uint32_t AudioFlinger::MixerThread::latency() const
+uint32_t AudioFlinger::PlaybackThread::latency() const
{
if (mOutput) {
return mOutput->latency();
@@ -1402,66 +980,66 @@
}
}
-status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
{
mMasterVolume = value;
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
mMasterMute = muted;
return NO_ERROR;
}
-float AudioFlinger::MixerThread::masterVolume() const
+float AudioFlinger::PlaybackThread::masterVolume() const
{
return mMasterVolume;
}
-bool AudioFlinger::MixerThread::masterMute() const
+bool AudioFlinger::PlaybackThread::masterMute() const
{
return mMasterMute;
}
-status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value)
{
mStreamTypes[stream].volume = value;
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted)
{
mStreamTypes[stream].mute = muted;
return NO_ERROR;
}
-float AudioFlinger::MixerThread::streamVolume(int stream) const
+float AudioFlinger::PlaybackThread::streamVolume(int stream) const
{
return mStreamTypes[stream].volume;
}
-bool AudioFlinger::MixerThread::streamMute(int stream) const
+bool AudioFlinger::PlaybackThread::streamMute(int stream) const
{
return mStreamTypes[stream].mute;
}
-// isMusicActive_l() must be called with AudioFlinger::mLock held
-bool AudioFlinger::MixerThread::isMusicActive_l() const
+bool AudioFlinger::PlaybackThread::isMusicActive() const
{
+ Mutex::Autolock _l(mLock);
size_t count = mActiveTracks.size();
for (size_t i = 0 ; i < count ; ++i) {
sp<Track> t = mActiveTracks[i].promote();
if (t == 0) continue;
Track* const track = t.get();
- if (t->mStreamType == AudioSystem::MUSIC)
+ if (t->type() == AudioSystem::MUSIC)
return true;
}
return false;
}
-// addTrack_l() must be called with AudioFlinger::mLock held
-status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+// addTrack_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
status_t status = ALREADY_EXISTS;
@@ -1482,18 +1060,18 @@
// effectively get the latency it requested.
track->mFillingUpStatus = Track::FS_FILLING;
track->mResetDone = false;
- addActiveTrack_l(track);
+ mActiveTracks.add(track);
status = NO_ERROR;
}
-
+
LOGV("mWaitWorkCV.broadcast");
- mAudioFlinger->mWaitWorkCV.broadcast();
+ mWaitWorkCV.broadcast();
return status;
}
-// destroyTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track)
{
track->mState = TrackBase::TERMINATED;
if (mActiveTracks.indexOf(track) < 0) {
@@ -1503,62 +1081,909 @@
}
}
-// addActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
+String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
{
- mActiveTracks.add(t);
+ return mOutput->getParameters(keys);
+}
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
-
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
- }
+void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
+ AudioSystem::OutputDescriptor desc;
+ void *param2 = 0;
+
+ LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param);
+
+ switch (event) {
+ case AudioSystem::OUTPUT_OPENED:
+ case AudioSystem::OUTPUT_CONFIG_CHANGED:
+ desc.channels = mChannelCount;
+ desc.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = latency();
+ param2 = &desc;
+ break;
+
+ case AudioSystem::STREAM_CONFIG_CHANGED:
+ param2 = ¶m;
+ case AudioSystem::OUTPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::PlaybackThread::readOutputParameters()
+{
+ mSampleRate = mOutput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mOutput->channels());
+
+ mFormat = mOutput->format();
+ mFrameSize = mOutput->frameSize();
+ mFrameCount = mOutput->bufferSize() / mFrameSize;
+
+ mMinBytesToWrite = (mOutput->latency() * mSampleRate * mFrameSize) / 1000;
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ if (mMixBuffer != NULL) delete mMixBuffer;
+ mMixBuffer = new int16_t[mFrameCount * 2];
+ memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mAudioMixer(0)
+{
+ mType = PlaybackThread::MIXER;
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
}
}
-// removeActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
+AudioFlinger::MixerThread::~MixerThread()
{
- mActiveTracks.remove(t);
+ delete mAudioMixer;
+}
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
+bool AudioFlinger::MixerThread::threadLoop()
+{
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks = 0;
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount * mFrameSize;
+ nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ enabledTracks = 0;
+ { // scope for mLock
+
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount * mFrameSize;
+ maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+ }
+
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+
+ if (exitPending()) break;
+
+ // wait until we have something to do...
+ LOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("MixerThread %p TID %d waking up\n", this, gettid());
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+ }
+
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
+ }
+
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+
+ // output audio to hardware
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+ if (bytesWritten > 0) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
+ }
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ // LOGV("thread %p no buffers - usleep(%lu)", this, sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ }
+
+ if (!mStandby) {
+ mOutput->standby();
+ }
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("MixerThread %p exiting", this);
+ return false;
+}
+
+// prepareTracks_l() must be called with ThreadBase::mLock held
+size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
+{
+
+ size_t enabledTracks = 0;
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ mAudioMixer->setActiveTrack(track->name());
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
+
+ // XXX: these things DON'T need to be done each time
+ mAudioMixer->setBufferProvider(track);
+ mAudioMixer->enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mAudioMixer->setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ tracksToRemove->add(track);
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove->add(track);
+ }
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer == 0) || (mBytesWritten >= mMinBytesToWrite)) {
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ enabledTracks++;
+ }
+ }
+ }
+ }
+
+ // remove all the tracks that need to be...
+ count = tracksToRemove->size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove->itemAt(i);
+ mActiveTracks.remove(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ deleteTrackName_l(track->mName);
+ }
+ }
+ }
+
+ return enabledTracks;
+}
+
+void AudioFlinger::MixerThread::getTracks(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks,
+ int streamType)
+{
+ LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.size());
+ Mutex::Autolock _l(mLock);
+ size_t size = mTracks.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = mTracks[i];
+ if (t->type() == streamType) {
+ tracks.add(t);
+ int j = mActiveTracks.indexOf(t);
+ if (j >= 0) {
+ t = mActiveTracks[j].promote();
+ if (t != NULL) {
+ activeTracks.add(t);
+ }
+ }
+ }
+ }
+
+ size = activeTracks.size();
+ for (size_t i = 0; i < size; i++) {
+ mActiveTracks.remove(activeTracks[i]);
+ }
+
+ size = tracks.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = tracks[i];
+ mTracks.remove(t);
+ deleteTrackName_l(t->name());
+ }
+}
+
+void AudioFlinger::MixerThread::putTracks(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks)
+{
+ LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this, tracks.size(), activeTracks.size());
+ Mutex::Autolock _l(mLock);
+ size_t size = tracks.size();
+ for (size_t i = 0; i < size ; i++) {
+ sp<Track> t = tracks[i];
+ int name = getTrackName_l();
+
+ if (name < 0) return;
+
+ t->mName = name;
+ t->mThread = this;
+ mTracks.add(t);
+
+ int j = activeTracks.indexOf(t);
+ if (j >= 0) {
+ mActiveTracks.add(t);
}
}
}
-// getTrackName_l() must be called with AudioFlinger::mLock held
+// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger::MixerThread::getTrackName_l()
{
return mAudioMixer->getTrackName();
}
-// deleteTrackName_l() must be called with AudioFlinger::mLock held
+// deleteTrackName_l() must be called with ThreadBase::mLock held
void AudioFlinger::MixerThread::deleteTrackName_l(int name)
{
mAudioMixer->deleteTrackName(name);
}
-size_t AudioFlinger::MixerThread::getOutputFrameCount()
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameters_l()
{
- return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ if (value != AudioSystem::PCM_16_BIT) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ if (value != AudioSystem::CHANNEL_OUT_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ if (status == NO_ERROR && reconfig) {
+ delete mAudioMixer;
+ readOutputParameters();
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ for (size_t i = 0; i < mTracks.size() ; i++) {
+ int name = getTrackName_l();
+ if (name < 0) break;
+ mTracks[i]->mName = name;
+ // limit track sample rate to 2 x new output sample rate
+ if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) {
+ mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
+ }
+ }
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ return reconfig;
+}
+
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ PlaybackThread::dumpInternals(fd, args);
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mLeftVolume (1.0), mRightVolume(1.0)
+{
+ mType = PlaybackThread::DIRECT;
+}
+
+AudioFlinger::DirectOutputThread::~DirectOutputThread()
+{
+}
+
+
+bool AudioFlinger::DirectOutputThread::threadLoop()
+{
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ sp<Track> trackToRemove;
+ sp<Track> activeTrack;
+ nsecs_t standbyTime = systemTime();
+ int8_t *curBuf;
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ // wait until we have something to do...
+ if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p\n", this);
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+
+ if (exitPending()) break;
+
+ LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+ }
+
+ // find out which tracks need to be processed
+ if (mActiveTracks.size() != 0) {
+ sp<Track> t = mActiveTracks[0].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ float left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = v_clamped/MAX_GAIN;
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = v_clamped/MAX_GAIN;
+ }
+
+ if (left != mLeftVolume || right != mRightVolume) {
+ mOutput->setVolume(left, right);
+ left = mLeftVolume;
+ right = mRightVolume;
+ }
+
+ if (track->mFillingUpStatus == Track::FS_FILLED) {
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ }
+ }
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ activeTrack = t;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ trackToRemove = track;
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ trackToRemove = track;
+ }
+
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer != 0) && (mBytesWritten < mMinBytesToWrite)) {
+ activeTrack = t;
+ }
+ }
+ }
+ }
+
+ // remove all the tracks that need to be...
+ if (UNLIKELY(trackToRemove != 0)) {
+ mActiveTracks.remove(trackToRemove);
+ if (trackToRemove->isTerminated()) {
+ mTracks.remove(trackToRemove);
+ deleteTrackName_l(trackToRemove->mName);
+ }
+ }
+ }
+
+ if (activeTrack != 0) {
+ AudioBufferProvider::Buffer buffer;
+ size_t frameCount = mFrameCount;
+ curBuf = (int8_t *)mMixBuffer;
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ while(frameCount) {
+ buffer.frameCount = frameCount;
+ activeTrack->getNextBuffer(&buffer);
+ if (UNLIKELY(buffer.raw == 0)) {
+ memset(curBuf, 0, frameCount * mFrameSize);
+ break;
+ }
+ memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+ frameCount -= buffer.frameCount;
+ curBuf += buffer.frameCount * mFrameSize;
+ activeTrack->releaseBuffer(&buffer);
+ }
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
+ if (bytesWritten) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ //LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of removed track, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ trackToRemove.clear();
+ activeTrack.clear();
+ }
+
+ if (!mStandby) {
+ mOutput->standby();
+ }
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("DirectOutputThread %p exiting", this);
+ return false;
+}
+
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::DirectOutputThread::getTrackName_l()
+{
+ return 0;
+}
+
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
+{
+}
+
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
+{
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters();
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ return reconfig;
}
// ----------------------------------------------------------------------------
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
+ : MixerThread(audioFlinger, mainThread->getOutput())
+{
+ mType = PlaybackThread::DUPLICATING;
+ addOutputTrack(mainThread);
+}
+
+AudioFlinger::DuplicatingThread::~DuplicatingThread()
+{
+ mOutputTracks.clear();
+}
+
+bool AudioFlinger::DuplicatingThread::threadLoop()
+{
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks = 0;
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+ SortedVector< sp<OutputTrack> > outputTracks;
+
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ enabledTracks = 0;
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
+
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ outputTracks.add(mOutputTracks[i]);
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ if (!mStandby) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->stop();
+ }
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ outputTracks.clear();
+
+ if (exitPending()) break;
+
+ LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ continue;
+ }
+ }
+
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
+ }
+
+ bool mustSleep = true;
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+ if (!mSuspended) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->write(curBuf, mFrameCount);
+ mustSleep = false;
+ }
+ mStandby = false;
+ mBytesWritten += mixBufferSize;
+ }
+ } else {
+ // flush remaining overflow buffers in output tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ if (outputTracks[i]->isActive()) {
+ outputTracks[i]->write(curBuf, 0);
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ mustSleep = false;
+ }
+ }
+ }
+ if (mustSleep) {
+// LOGV("threadLoop() sleeping %d", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ } else {
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ outputTracks.clear();
+ }
+
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+ if (!mStandby) {
+ LOGV("DuplicatingThread() exiting out of standby");
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ mOutputTracks[i]->destroy();
+ }
+ }
+ }
+
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ return false;
+}
+
+void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
+{
+ int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
+ OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
+ mSampleRate,
+ mFormat,
+ mChannelCount,
+ frameCount);
+ if (outputTrack->cblk() != NULL) {
+ thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
+ mOutputTracks.add(outputTrack);
+ LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+ }
+}
+
+void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
+{
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+ mOutputTracks[i]->destroy();
+ mOutputTracks.removeAt(i);
+ return;
+ }
+ }
+ LOGV("removeOutputTrack(): unkonwn thread: %p", thread);
+}
+
+
+// ----------------------------------------------------------------------------
+
// TrackBase constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::TrackBase::TrackBase(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::ThreadBase::TrackBase::TrackBase(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -1567,7 +1992,7 @@
uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mMixerThread(mixerThread),
+ mThread(thread),
mClient(client),
mFrameCount(0),
mState(IDLE),
@@ -1575,13 +2000,6 @@
mFormat(format),
mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
- mName = mixerThread->getTrackName_l();
- LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- if (mName < 0) {
- LOGE("no more track names availlable");
- return;
- }
-
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
@@ -1635,16 +2053,19 @@
}
}
-AudioFlinger::MixerThread::TrackBase::~TrackBase()
+AudioFlinger::PlaybackThread::TrackBase::~TrackBase()
{
if (mCblk) {
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mClient == NULL) {
+ delete mCblk;
+ }
}
mCblkMemory.clear(); // and free the shared memory
mClient.clear();
}
-void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1652,7 +2073,7 @@
buffer->frameCount = 0;
}
-bool AudioFlinger::MixerThread::TrackBase::step() {
+bool AudioFlinger::PlaybackThread::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1664,7 +2085,7 @@
return result;
}
-void AudioFlinger::MixerThread::TrackBase::reset() {
+void AudioFlinger::PlaybackThread::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
@@ -1675,27 +2096,27 @@
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
+int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const {
return (int)mCblk->sampleRate;
}
-int AudioFlinger::MixerThread::TrackBase::channelCount() const {
+int AudioFlinger::PlaybackThread::TrackBase::channelCount() const {
return (int)mCblk->channels;
}
-void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::PlaybackThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
- int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
- int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+ int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
+ int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;
// Check validity of returned pointer in case the track control block would have been corrupted.
- if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
- (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) {
+ if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
+ ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {
LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \
server %d, serverBase %d, user %d, userBase %d, channels %d",
bufferStart, bufferEnd, mBuffer, mBufferEnd,
@@ -1708,9 +2129,9 @@
// ----------------------------------------------------------------------------
-// Track constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::Track::Track(
- const sp<MixerThread>& mixerThread,
+// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
+AudioFlinger::PlaybackThread::Track::Track(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1718,40 +2139,58 @@
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+ : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
+ mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
{
+ sp<ThreadBase> baseThread = thread.promote();
+ if (baseThread != 0) {
+ PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
+ mName = playbackThread->getTrackName_l();
+ }
+ LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ if (mName < 0) {
+ LOGE("no more track names available");
+ }
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
- mMute = false;
- mSharedBuffer = sharedBuffer;
mStreamType = streamType;
+ // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
+ // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
+ mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
}
-AudioFlinger::MixerThread::Track::~Track()
+AudioFlinger::PlaybackThread::Track::~Track()
{
- wp<Track> weak(this); // never create a strong ref from the dtor
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mState = TERMINATED;
-}
-
-void AudioFlinger::MixerThread::Track::destroy()
-{
- // NOTE: destroyTrack_l() can remove a strong reference to this Track
- // by removing it from mTracks vector, so there is a risk that this Tracks's
- // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
- // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
- // here so that the destructor is called only when exiting this function.
- // On the other hand, as long as Track::destroy() is only called by
- // TrackHandle destructor, the TrackHandle still holds a strong ref on
- // this Track with its member mTrack.
- sp<Track> keep(this);
- { // scope for AudioFlinger::mLock
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->destroyTrack_l(this);
+ LOGV("PlaybackThread::Track destructor");
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ mState = TERMINATED;
}
}
-void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
+void AudioFlinger::PlaybackThread::Track::destroy()
+{
+ // NOTE: destroyTrack_l() can remove a strong reference to this Track
+ // by removing it from mTracks vector, so there is a risk that this Tracks's
+ // desctructor is called. As the destructor needs to lock mLock,
+ // we must acquire a strong reference on this Track before locking mLock
+ // here so that the destructor is called only when exiting this function.
+ // On the other hand, as long as Track::destroy() is only called by
+ // TrackHandle destructor, the TrackHandle still holds a strong ref on
+ // this Track with its member mTrack.
+ sp<Track> keep(this);
+ { // scope for mLock
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->destroyTrack_l(this);
+ }
+ }
+}
+
+void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
mName - AudioMixer::TRACK0,
@@ -1770,7 +2209,7 @@
mCblk->user);
}
-status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -1807,76 +2246,90 @@
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
+ LOGV("getNextBuffer() no more data");
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::MixerThread::Track::isReady() const {
+bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
mCblk->forceReady = 0;
- LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
return true;
}
return false;
}
-status_t AudioFlinger::MixerThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start()
{
- LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->addTrack_l(this);
+ LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->addTrack_l(this);
+ }
return NO_ERROR;
}
-void AudioFlinger::MixerThread::Track::stop()
+void AudioFlinger::PlaybackThread::Track::stop()
{
- LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState > STOPPED) {
- mState = STOPPED;
- // If the track is not active (PAUSED and buffers full), flush buffers
- if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
- reset();
+ LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState > STOPPED) {
+ mState = STOPPED;
+ // If the track is not active (PAUSED and buffers full), flush buffers
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+ reset();
+ }
+ LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
- LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
}
-void AudioFlinger::MixerThread::Track::pause()
+void AudioFlinger::PlaybackThread::Track::pause()
{
LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState == ACTIVE || mState == RESUMING) {
- mState = PAUSING;
- LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState == ACTIVE || mState == RESUMING) {
+ mState = PAUSING;
+ LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ }
}
}
-void AudioFlinger::MixerThread::Track::flush()
+void AudioFlinger::PlaybackThread::Track::flush()
{
LOGV("flush(%d)", mName);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
- return;
- }
- // No point remaining in PAUSED state after a flush => go to
- // STOPPED state
- mState = STOPPED;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+ return;
+ }
+ // No point remaining in PAUSED state after a flush => go to
+ // STOPPED state
+ mState = STOPPED;
- mCblk->lock.lock();
- // NOTE: reset() will reset cblk->user and cblk->server with
- // the risk that at the same time, the AudioMixer is trying to read
- // data. In this case, getNextBuffer() would return a NULL pointer
- // as audio buffer => the AudioMixer code MUST always test that pointer
- // returned by getNextBuffer() is not NULL!
- reset();
- mCblk->lock.unlock();
+ mCblk->lock.lock();
+ // NOTE: reset() will reset cblk->user and cblk->server with
+ // the risk that at the same time, the AudioMixer is trying to read
+ // data. In this case, getNextBuffer() would return a NULL pointer
+ // as audio buffer => the AudioMixer code MUST always test that pointer
+ // returned by getNextBuffer() is not NULL!
+ reset();
+ mCblk->lock.unlock();
+ }
}
-void AudioFlinger::MixerThread::Track::reset()
+void AudioFlinger::PlaybackThread::Track::reset()
{
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
@@ -1886,17 +2339,17 @@
// written to buffer
mCblk->flowControlFlag = 1;
mCblk->forceReady = 0;
- mFillingUpStatus = FS_FILLING;
+ mFillingUpStatus = FS_FILLING;
mResetDone = true;
}
}
-void AudioFlinger::MixerThread::Track::mute(bool muted)
+void AudioFlinger::PlaybackThread::Track::mute(bool muted)
{
mMute = muted;
}
-void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
+void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right)
{
mVolume[0] = left;
mVolume[1] = right;
@@ -1905,28 +2358,33 @@
// ----------------------------------------------------------------------------
// RecordTrack constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::RecordTrack::RecordTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::RecordThread::RecordTrack::RecordTrack(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
- int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags)
- : TrackBase(mixerThread, client, sampleRate, format,
+ : TrackBase(thread, client, sampleRate, format,
channelCount, frameCount, flags, 0),
- mOverflow(false), mInputSource(inputSource)
+ mOverflow(false)
+{
+ LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
+ if (format == AudioSystem::PCM_16_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int16_t);
+ } else if (format == AudioSystem::PCM_8_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int8_t);
+ } else {
+ mCblk->frameSize = sizeof(int8_t);
+ }
+}
+
+AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
{
}
-AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
-{
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->deleteTrackName_l(mName);
-}
-
-status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesAvail;
@@ -1965,180 +2423,234 @@
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::MixerThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start()
{
- return mMixerThread->mAudioFlinger->startRecord(this);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ return recordThread->start(this);
+ }
+ return NO_INIT;
}
-void AudioFlinger::MixerThread::RecordTrack::stop()
+void AudioFlinger::RecordThread::RecordTrack::stop()
{
- mMixerThread->mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ recordThread->stop(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
+ }
}
// ----------------------------------------------------------------------------
-AudioFlinger::MixerThread::OutputTrack::OutputTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
+ const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount)
- : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
- mOutputMixerThread(mixerThread)
+ : Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
+ mActive(false)
{
-
- mCblk->out = 1;
- mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
- mCblk->volume[0] = mCblk->volume[1] = 0x1000;
- mOutBuffer.frameCount = 0;
- mCblk->bufferTimeoutMs = 10;
-
- LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
- mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
-
+
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
+ if (mCblk != NULL) {
+ mCblk->out = 1;
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mOutBuffer.frameCount = 0;
+ mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
+ playbackThread->mTracks.add(this);
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+ } else {
+ LOGW("Error creating output track on thread %p", playbackThread);
+ }
}
-AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
{
- stop();
+ clearBufferQueue();
}
-status_t AudioFlinger::MixerThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start()
{
status_t status = Track::start();
-
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ mActive = true;
mRetryCount = 127;
return status;
}
-void AudioFlinger::MixerThread::OutputTrack::stop()
+void AudioFlinger::PlaybackThread::OutputTrack::stop()
{
Track::stop();
clearBufferQueue();
mOutBuffer.frameCount = 0;
+ mActive = false;
}
-void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames)
{
Buffer *pInBuffer;
Buffer inBuffer;
uint32_t channels = mCblk->channels;
-
+ bool outputBufferFull = false;
inBuffer.frameCount = frames;
inBuffer.i16 = data;
-
- if (mCblk->user == 0) {
- mOutputMixerThread->mAudioFlinger->mLock.lock();
- bool isMusicActive = mOutputMixerThread->isMusicActive_l();
- mOutputMixerThread->mAudioFlinger->mLock.unlock();
- if (isMusicActive) {
- mCblk->forceReady = 1;
- LOGV("OutputTrack::start() force ready");
- } else if (mCblk->frameCount > frames){
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
- uint32_t startFrames = (mCblk->frameCount - frames);
- LOGV("OutputTrack::start() write %d frames", startFrames);
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[startFrames * channels];
- pInBuffer->frameCount = startFrames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
- } else {
- LOGW ("OutputTrack::write() no more buffers");
+
+ uint32_t waitTimeLeftMs = mWaitTimeMs;
+
+ if (!mActive) {
+ start();
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ MixerThread *mixerThread = (MixerThread *)thread.get();
+ if (mCblk->frameCount > frames){
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
+ uint32_t startFrames = (mCblk->frameCount - frames);
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[startFrames * channels];
+ pInBuffer->frameCount = startFrames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW ("OutputTrack::write() %p no more buffers in queue", this);
+ }
}
- }
+ }
}
- while (1) {
+ while (waitTimeLeftMs) {
// First write pending buffers, then new data
if (mBufferQueue.size()) {
pInBuffer = mBufferQueue.itemAt(0);
} else {
pInBuffer = &inBuffer;
}
-
+
if (pInBuffer->frameCount == 0) {
break;
}
-
+
if (mOutBuffer.frameCount == 0) {
mOutBuffer.frameCount = pInBuffer->frameCount;
- if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ nsecs_t startTime = systemTime();
+ if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ LOGV ("OutputTrack::write() %p no more output buffers", this);
+ outputBufferFull = true;
break;
}
+ uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
+// LOGV("OutputTrack::write() waitTimeMs %d waitTimeLeftMs %d", waitTimeMs, waitTimeLeftMs)
+ if (waitTimeLeftMs >= waitTimeMs) {
+ waitTimeLeftMs -= waitTimeMs;
+ } else {
+ waitTimeLeftMs = 0;
+ }
}
-
+
uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
mCblk->stepUser(outFrames);
pInBuffer->frameCount -= outFrames;
pInBuffer->i16 += outFrames * channels;
mOutBuffer.frameCount -= outFrames;
- mOutBuffer.i16 += outFrames * channels;
-
+ mOutBuffer.i16 += outFrames * channels;
+
if (pInBuffer->frameCount == 0) {
if (mBufferQueue.size()) {
mBufferQueue.removeAt(0);
delete [] pInBuffer->mBuffer;
delete pInBuffer;
+ LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size());
} else {
break;
}
}
}
-
+
// If we could not write all frames, allocate a buffer and queue it for next time.
if (inBuffer.frameCount) {
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
pInBuffer->frameCount = inBuffer.frameCount;
pInBuffer->i16 = pInBuffer->mBuffer;
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
mBufferQueue.add(pInBuffer);
+ LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size());
} else {
- LOGW("OutputTrack::write() no more buffers");
+ LOGW("OutputTrack::write() %p no more overflow buffers", this);
}
}
-
+
// Calling write() with a 0 length buffer, means that no more data will be written:
- // If no more buffers are pending, fill output track buffer to make sure it is started
+ // If no more buffers are pending, fill output track buffer to make sure it is started
// by output mixer.
- if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
- frames = mCblk->frameCount - mCblk->user;
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[frames * channels];
- pInBuffer->frameCount = frames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
+ if (frames == 0 && mBufferQueue.size() == 0) {
+ if (mCblk->user < mCblk->frameCount) {
+ frames = mCblk->frameCount - mCblk->user;
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[frames * channels];
+ pInBuffer->frameCount = frames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ stop();
+ }
}
+ return outputBufferFull;
}
-status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
{
int active;
- int timeout = 0;
status_t result;
audio_track_cblk_t* cblk = mCblk;
uint32_t framesReq = buffer->frameCount;
- LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+// LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
buffer->frameCount = 0;
-
+
uint32_t framesAvail = cblk->framesAvailable();
+
if (framesAvail == 0) {
- return AudioTrack::NO_MORE_BUFFERS;
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (framesAvail == 0) {
+ active = mActive;
+ if (UNLIKELY(!active)) {
+ LOGV("Not active and NO_MORE_BUFFERS");
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ if (result != NO_ERROR) {
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ // read the server count again
+ start_loop_here:
+ framesAvail = cblk->framesAvailable_l();
+ }
}
+// if (framesAvail < framesReq) {
+// return AudioTrack::NO_MORE_BUFFERS;
+// }
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -2156,11 +2668,11 @@
}
-void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
{
size_t size = mBufferQueue.size();
Buffer *pBuffer;
-
+
for (size_t i = 0; i < size; i++) {
pBuffer = mBufferQueue.itemAt(i);
delete [] pBuffer->mBuffer;
@@ -2192,7 +2704,7 @@
// ----------------------------------------------------------------------------
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
: BnAudioTrack(),
mTrack(track)
{
@@ -2244,7 +2756,7 @@
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -2252,14 +2764,13 @@
uint32_t flags,
status_t *status)
{
- sp<MixerThread::RecordTrack> recordTrack;
+ sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
wp<Client> wclient;
- AudioStreamIn* input = 0;
- int inFrameCount;
- size_t inputBufferSize;
status_t lStatus;
+ RecordThread *thread;
+ size_t inFrameCount;
// check calling permissions
if (!recordingAllowed()) {
@@ -2267,30 +2778,15 @@
goto Exit;
}
- if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) {
- LOGE("invalid stream type");
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
- if (mAudioRecordThread == 0) {
- LOGE("Audio record thread not started");
- lStatus = NO_INIT;
- goto Exit;
- }
-
-
- // Check that audio input stream accepts requested audio parameters
- inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
- if (inputBufferSize == 0) {
- lStatus = BAD_VALUE;
- LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
- goto Exit;
- }
-
// add client to list
{ // scope for mLock
Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
client = wclient.promote();
@@ -2299,12 +2795,8 @@
mClients.add(pid, client);
}
- // frameCount must be a multiple of input buffer size
- inFrameCount = inputBufferSize/channelCount/sizeof(short);
- frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate,
+ recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
format, channelCount, frameCount, flags);
}
if (recordTrack->getCblk() == NULL) {
@@ -2324,22 +2816,9 @@
return recordHandle;
}
-status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- return mAudioRecordThread->start(recordTrack);
- }
- return NO_INIT;
-}
-
-void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->stop(recordTrack);
- }
-}
-
// ----------------------------------------------------------------------------
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack)
: BnAudioRecord(),
mRecordTrack(recordTrack)
{
@@ -2371,86 +2850,164 @@
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
- const sp<AudioFlinger>& audioFlinger) :
- mAudioHardware(audioHardware),
- mAudioFlinger(audioFlinger),
- mActive(false)
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels) :
+ ThreadBase(audioFlinger),
+ mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
+ mReqChannelCount = AudioSystem::popCount(channels);
+ mReqSampleRate = sampleRate;
+ readInputParameters();
+ sendConfigEvent(AudioSystem::INPUT_OPENED);
}
-AudioFlinger::AudioRecordThread::~AudioRecordThread()
+
+AudioFlinger::RecordThread::~RecordThread()
{
+ delete[] mRsmpInBuffer;
+ if (mResampler != 0) {
+ delete mResampler;
+ delete[] mRsmpOutBuffer;
+ }
}
-bool AudioFlinger::AudioRecordThread::threadLoop()
+void AudioFlinger::RecordThread::onFirstRef()
{
- LOGV("AudioRecordThread: start record loop");
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Record Thread %p", this);
+
+ run(buffer, PRIORITY_URGENT_AUDIO);
+}
+bool AudioFlinger::RecordThread::threadLoop()
+{
AudioBufferProvider::Buffer buffer;
- int inBufferSize = 0;
- int inFrameCount = 0;
- AudioStreamIn* input = 0;
+ sp<RecordTrack> activeTrack;
- mActive = 0;
-
// start recording
while (!exitPending()) {
- if (!mActive) {
- mLock.lock();
- if (!mActive && !exitPending()) {
- LOGV("AudioRecordThread: loop stopping");
- if (input) {
- delete input;
- input = 0;
- }
- mRecordTrack.clear();
- mStopped.signal();
+ processConfigEvents();
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ checkForNewParameters_l();
+ if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
+ if (!mStandby) {
+ mInput->standby();
+ mStandby = true;
+ }
+
+ if (exitPending()) break;
+
+ LOGV("RecordThread: loop stopping");
+ // go to sleep
mWaitWorkCV.wait(mLock);
-
- LOGV("AudioRecordThread: loop starting");
- if (mRecordTrack != 0) {
- input = mAudioHardware->openInputStream(
- mRecordTrack->inputSource(),
- mRecordTrack->format(),
- mRecordTrack->channelCount(),
- mRecordTrack->sampleRate(),
- &mStartStatus,
- (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
- if (input != 0) {
- inBufferSize = input->bufferSize();
- inFrameCount = inBufferSize/input->frameSize();
+ LOGV("RecordThread: loop starting");
+ continue;
+ }
+ if (mActiveTrack != 0) {
+ if (mActiveTrack->mState == TrackBase::PAUSING) {
+ mActiveTrack.clear();
+ mStartStopCond.broadcast();
+ } else if (mActiveTrack->mState == TrackBase::RESUMING) {
+ mRsmpInIndex = mFrameCount;
+ if (mReqChannelCount != mActiveTrack->channelCount()) {
+ mActiveTrack.clear();
+ } else {
+ mActiveTrack->mState = TrackBase::ACTIVE;
+ }
+ mStartStopCond.broadcast();
+ }
+ mStandby = false;
+ }
+ }
+
+ if (mActiveTrack != 0) {
+ buffer.frameCount = mFrameCount;
+ if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ size_t framesOut = buffer.frameCount;
+ if (mResampler == 0) {
+ // no resampling
+ while (framesOut) {
+ size_t framesIn = mFrameCount - mRsmpInIndex;
+ if (framesIn) {
+ int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
+ int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize;
+ if (framesIn > framesOut)
+ framesIn = framesOut;
+ mRsmpInIndex += framesIn;
+ framesOut -= framesIn;
+ if (mChannelCount == mReqChannelCount ||
+ mFormat != AudioSystem::PCM_16_BIT) {
+ memcpy(dst, src, framesIn * mFrameSize);
+ } else {
+ int16_t *src16 = (int16_t *)src;
+ int16_t *dst16 = (int16_t *)dst;
+ if (mChannelCount == 1) {
+ while (framesIn--) {
+ *dst16++ = *src16;
+ *dst16++ = *src16++;
+ }
+ } else {
+ while (framesIn--) {
+ *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
+ src16 += 2;
+ }
+ }
+ }
+ }
+ if (framesOut && mFrameCount == mRsmpInIndex) {
+ ssize_t bytesRead;
+ if (framesOut == mFrameCount &&
+ (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
+ bytesRead = mInput->read(buffer.raw, mInputBytes);
+ framesOut = 0;
+ } else {
+ bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ mRsmpInIndex = 0;
+ }
+ if (bytesRead < 0) {
+ LOGE("Error reading audio input");
+ sleep(1);
+ mRsmpInIndex = mFrameCount;
+ framesOut = 0;
+ buffer.frameCount = 0;
+ }
+ }
}
} else {
- mStartStatus = NO_INIT;
- }
- if (mStartStatus !=NO_ERROR) {
- LOGW("record start failed, status %d", mStartStatus);
- mActive = false;
- mRecordTrack.clear();
- }
- mWaitWorkCV.signal();
- }
- mLock.unlock();
- } else if (mRecordTrack != 0) {
+ // resampling
- buffer.frameCount = inFrameCount;
- if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
- (int)buffer.frameCount == inFrameCount)) {
- LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
- ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
- if (bytesRead < 0) {
- LOGE("Error reading audio input");
- sleep(1);
- }
- mRecordTrack->releaseBuffer(&buffer);
- mRecordTrack->overflow();
- }
+ memset(mRsmpOutBuffer, 0, framesOut * 2 * sizeof(int32_t));
+ // alter output frame count as if we were expecting stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ framesOut >>= 1;
+ }
+ mResampler->resample(mRsmpOutBuffer, framesOut, this);
+ // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
+ // are 32 bit aligned which should be always true.
+ if (mChannelCount == 2 && mReqChannelCount == 1) {
+ AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
+ // the resampler always outputs stereo samples: do post stereo to mono conversion
+ int16_t *src = (int16_t *)mRsmpOutBuffer;
+ int16_t *dst = buffer.i16;
+ while (framesOut--) {
+ *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
+ src += 2;
+ }
+ } else {
+ AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+ }
+ }
+ mActiveTrack->releaseBuffer(&buffer);
+ mActiveTrack->overflow();
+ }
// client isn't retrieving buffers fast enough
else {
- if (!mRecordTrack->setOverflow())
- LOGW("AudioRecordThread: buffer overflow");
+ if (!mActiveTrack->setOverflow())
+ LOGW("RecordThread: buffer overflow");
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
@@ -2459,65 +3016,64 @@
}
}
-
- if (input) {
- delete input;
+ if (!mStandby) {
+ mInput->standby();
}
- mRecordTrack.clear();
-
+ mActiveTrack.clear();
+
+ sendConfigEvent(AudioSystem::INPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("RecordThread %p exiting", this);
return false;
}
-status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
{
- LOGV("AudioRecordThread::start");
+ LOGV("RecordThread::start");
AutoMutex lock(&mLock);
- mActive = true;
- // If starting the active track, just reset mActive in case a stop
- // was pending and exit
- if (recordTrack == mRecordTrack.get()) return NO_ERROR;
- if (mRecordTrack != 0) return -EBUSY;
+ if (mActiveTrack != 0) {
+ if (recordTrack != mActiveTrack.get()) return -EBUSY;
- mRecordTrack = recordTrack;
+ if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
+ return NO_ERROR;
+ }
+
+ mActiveTrack = recordTrack;
+ mActiveTrack->mState = TrackBase::RESUMING;
// signal thread to start
LOGV("Signal record thread");
mWaitWorkCV.signal();
- mWaitWorkCV.wait(mLock);
- LOGV("Record started, status %d", mStartStatus);
- return mStartStatus;
+ mStartStopCond.wait(mLock);
+ if (mActiveTrack != 0) {
+ LOGV("Record started OK");
+ return NO_ERROR;
+ } else {
+ LOGV("Record failed to start");
+ return BAD_VALUE;
+ }
}
-void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
- LOGV("AudioRecordThread::stop");
+void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
+ LOGV("RecordThread::stop");
AutoMutex lock(&mLock);
- if (mActive && (recordTrack == mRecordTrack.get())) {
- mActive = false;
- mStopped.wait(mLock);
+ if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
+ mActiveTrack->mState = TrackBase::PAUSING;
+ mStartStopCond.wait(mLock);
}
}
-void AudioFlinger::AudioRecordThread::exit()
-{
- LOGV("AudioRecordThread::exit");
- {
- AutoMutex lock(&mLock);
- requestExit();
- mWaitWorkCV.signal();
- }
- requestExitAndWait();
-}
-
-status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
pid_t pid = 0;
- if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
- snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+ if (mActiveTrack != 0 && mActiveTrack->mClient != 0) {
+ snprintf(buffer, SIZE, "Record client pid: %d\n", mActiveTrack->mClient->pid());
result.append(buffer);
} else {
result.append("No record client\n");
@@ -2526,6 +3082,468 @@
return NO_ERROR;
}
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ size_t framesReq = buffer->frameCount;
+ size_t framesReady = mFrameCount - mRsmpInIndex;
+ int channelCount;
+
+ if (framesReady == 0) {
+ ssize_t bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ if (bytesRead < 0) {
+ LOGE("RecordThread::getNextBuffer() Error reading audio input");
+ sleep(1);
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+ }
+ mRsmpInIndex = 0;
+ framesReady = mFrameCount;
+ }
+
+ if (framesReq > framesReady) {
+ framesReq = framesReady;
+ }
+
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount;
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+}
+
+void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ mRsmpInIndex += buffer->frameCount;
+ buffer->frameCount = 0;
+}
+
+bool AudioFlinger::RecordThread::checkForNewParameters_l()
+{
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+ int reqFormat = mFormat;
+ int reqSamplingRate = mReqSampleRate;
+ int reqChannelCount = mReqChannelCount;
+
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reqSamplingRate = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ reqFormat = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ reqChannelCount = AudioSystem::popCount(value);
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (mActiveTrack != 0) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mInput->setParameters(keyValuePair);
+ if (status == INVALID_OPERATION) {
+ mInput->standby();
+ status = mInput->setParameters(keyValuePair);
+ }
+ if (reconfig) {
+ if (status == BAD_VALUE &&
+ reqFormat == mInput->format() && reqFormat == AudioSystem::PCM_16_BIT &&
+ ((int)mInput->sampleRate() <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(mInput->channels()) < 3) && (reqChannelCount < 3)) {
+ status = NO_ERROR;
+ }
+ if (status == NO_ERROR) {
+ readInputParameters();
+ sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
+ }
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ return reconfig;
+}
+
+String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
+{
+ return mInput->getParameters(keys);
+}
+
+void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) {
+ AudioSystem::OutputDescriptor desc;
+ void *param2 = 0;
+
+ switch (event) {
+ case AudioSystem::INPUT_OPENED:
+ case AudioSystem::INPUT_CONFIG_CHANGED:
+ desc.channels = mChannelCount;
+ desc.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = 0;
+ param2 = &desc;
+ break;
+
+ case AudioSystem::INPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::RecordThread::readInputParameters()
+{
+ if (mRsmpInBuffer) delete mRsmpInBuffer;
+ if (mRsmpOutBuffer) delete mRsmpOutBuffer;
+ if (mResampler) delete mResampler;
+ mResampler = 0;
+
+ mSampleRate = mInput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mInput->channels());
+ mFormat = mInput->format();
+ mFrameSize = mInput->frameSize();
+ mInputBytes = mInput->bufferSize();
+ mFrameCount = mInputBytes / mFrameSize;
+ mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
+
+ if (mSampleRate != mReqSampleRate && mChannelCount < 3 && mReqChannelCount < 3)
+ {
+ int channelCount;
+ // optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid
+ // stereo to mono post process as the resampler always outputs stereo.
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ mResampler = AudioResampler::create(16, channelCount, mReqSampleRate);
+ mResampler->setSampleRate(mSampleRate);
+ mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+ mRsmpOutBuffer = new int32_t[mFrameCount * 2];
+
+ // optmization: if mono to mono, alter input frame count as if we were inputing stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ mFrameCount >>= 1;
+ }
+
+ }
+ mRsmpInIndex = mFrameCount;
+}
+
+// ----------------------------------------------------------------------------
+
+int AudioFlinger::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags)
+{
+ status_t status;
+ PlaybackThread *thread = NULL;
+ mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
+ LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
+ pDevices ? *pDevices : 0,
+ samplingRate,
+ format,
+ channels,
+ flags);
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status);
+ LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
+ output,
+ samplingRate,
+ format,
+ channels,
+ status);
+
+ mHardwareStatus = AUDIO_HW_IDLE;
+ if (output != 0) {
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != AudioSystem::PCM_16_BIT) ||
+ (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ thread = new DirectOutputThread(this, output);
+ LOGV("openOutput() created direct output: ID %d thread %p", (mNextThreadId + 1), thread);
+ } else {
+ thread = new MixerThread(this, output);
+ LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
+ }
+ mPlaybackThreads.add(++mNextThreadId, thread);
+
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = channels;
+ if (pLatencyMs) *pLatencyMs = thread->latency();
+ }
+
+ return mNextThreadId;
+}
+
+int AudioFlinger::openDuplicateOutput(int output1, int output2)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *thread1 = checkMixerThread_l(output1);
+ MixerThread *thread2 = checkMixerThread_l(output2);
+
+ if (thread1 == NULL || thread2 == NULL) {
+ LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
+ return 0;
+ }
+
+
+ DuplicatingThread *thread = new DuplicatingThread(this, thread1);
+ thread->addOutputTrack(thread2);
+ mPlaybackThreads.add(++mNextThreadId, thread);
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeOutput(int output)
+{
+ // keep strong reference on the playback thread so that
+ // it is not destroyed while exit() is executed
+ sp <PlaybackThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeOutput() %d", output);
+
+ if (thread->type() == PlaybackThread::MIXER) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+ DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
+ dupThread->removeOutputTrack((MixerThread *)thread.get());
+ }
+ }
+ }
+ mPlaybackThreads.removeItem(output);
+ }
+ thread->exit();
+
+ if (thread->type() != PlaybackThread::DUPLICATING) {
+ mAudioHardware->closeOutputStream(thread->getOutput());
+ }
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::suspendOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("suspendOutput() %d", output);
+ thread->suspend();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::restoreOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("restoreOutput() %d", output);
+
+ thread->restore();
+
+ return NO_ERROR;
+}
+
+int AudioFlinger::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ status_t status;
+ RecordThread *thread = NULL;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t reqSamplingRate = samplingRate;
+ uint32_t reqFormat = format;
+ uint32_t reqChannels = channels;
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamIn *input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
+ input,
+ samplingRate,
+ format,
+ channels,
+ acoustics,
+ status);
+
+ // If the input could not be opened with the requested parameters and we can handle the conversion internally,
+ // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
+ // or stereo to mono conversions on 16 bit PCM inputs.
+ if (input == 0 && status == BAD_VALUE &&
+ reqFormat == format && format == AudioSystem::PCM_16_BIT &&
+ (samplingRate <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(channels) < 3) && (AudioSystem::popCount(reqChannels) < 3)) {
+ LOGV("openInput() reopening with proposed sampling rate and channels");
+ input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ }
+
+ if (input != 0) {
+ // Start record thread
+ thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
+ mRecordThreads.add(++mNextThreadId, thread);
+ LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
+ if (pSamplingRate) *pSamplingRate = reqSamplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = reqChannels;
+
+ input->standby();
+ }
+
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeInput(int input)
+{
+ // keep strong reference on the record thread so that
+ // it is not destroyed while exit() is executed
+ sp <RecordThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeInput() %d", input);
+ mRecordThreads.removeItem(input);
+ }
+ thread->exit();
+
+ mAudioHardware->closeInputStream(thread->getInput());
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *dstThread = checkMixerThread_l(output);
+ if (dstThread == NULL) {
+ LOGW("setStreamOutput() bad output id %d", output);
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamOutput() stream %d to output %d", stream, output);
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ if (thread != dstThread &&
+ thread->type() != PlaybackThread::DIRECT) {
+ MixerThread *srcThread = (MixerThread *)thread;
+ SortedVector < sp<MixerThread::Track> > tracks;
+ SortedVector < wp<MixerThread::Track> > activeTracks;
+ srcThread->getTracks(tracks, activeTracks, stream);
+ if (tracks.size()) {
+ dstThread->putTracks(tracks, activeTracks);
+ }
+ dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
+{
+ PlaybackThread *thread = NULL;
+ if (mPlaybackThreads.indexOfKey(output) >= 0) {
+ thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
+ }
+ return thread;
+}
+
+// checkMixerThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
+{
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread != NULL) {
+ if (thread->type() == PlaybackThread::DIRECT) {
+ thread = NULL;
+ }
+ }
+ return (MixerThread *)thread;
+}
+
+// checkRecordThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
+{
+ RecordThread *thread = NULL;
+ if (mRecordThreads.indexOfKey(input) >= 0) {
+ thread = (RecordThread *)mRecordThreads.valueFor(input).get();
+ }
+ return thread;
+}
+
+// ----------------------------------------------------------------------------
+
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -2533,6 +3551,7 @@
}
// ----------------------------------------------------------------------------
+
void AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_flinger"), new AudioFlinger());
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 634934e..65c148e 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -30,8 +30,7 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/MemoryDealer.h>
-#include <utils/KeyedVector.h>
+#include <binder/MemoryDealer.h>
#include <utils/SortedVector.h>
#include <utils/Vector.h>
@@ -44,6 +43,7 @@
class audio_track_cblk_t;
class AudioMixer;
class AudioBuffer;
+class AudioResampler;
// ----------------------------------------------------------------------------
@@ -56,7 +56,7 @@
static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
{
public:
static void instantiate();
@@ -73,6 +73,7 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status);
virtual uint32_t sampleRate(int output) const;
@@ -87,33 +88,51 @@
virtual float masterVolume() const;
virtual bool masterMute() const;
- virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamVolume(int stream, float value, int output);
virtual status_t setStreamMute(int stream, bool muted);
- virtual float streamVolume(int stream) const;
+ virtual float streamVolume(int stream, int output) const;
virtual bool streamMute(int stream) const;
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask);
- virtual uint32_t getRouting(int mode) const;
-
virtual status_t setMode(int mode);
- virtual int getMode() const;
virtual status_t setMicMute(bool state);
virtual bool getMicMute() const;
virtual bool isMusicActive() const;
- virtual bool isA2dpEnabled() const;
-
- virtual status_t setParameter(const char* key, const char* value);
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(int ioHandle, const String8& keys);
virtual void registerClient(const sp<IAudioFlingerClient>& client);
-
+
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
-
- virtual void wakeUp() { mWaitWorkCV.broadcast(); }
-
+
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags);
+
+ virtual int openDuplicateOutput(int output1, int output2);
+
+ virtual status_t closeOutput(int output);
+
+ virtual status_t suspendOutput(int output);
+
+ virtual status_t restoreOutput(int output);
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+
+ virtual status_t closeInput(int input);
+
+ virtual status_t setStreamOutput(uint32_t stream, int output);
+
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -139,7 +158,7 @@
// record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -156,27 +175,7 @@
private:
AudioFlinger();
virtual ~AudioFlinger();
-
- void setOutput(int outputType);
- void doSetOutput(int outputType);
-#ifdef WITH_A2DP
- void setA2dpEnabled_l(bool enable);
- void checkA2dpEnabledChange_l();
-#endif
- static bool streamForcedToSpeaker(int streamType);
-
- // Management of forced route to speaker for certain track types.
- enum force_speaker_command {
- ACTIVE_TRACK_ADDED = 0,
- ACTIVE_TRACK_REMOVED,
- CHECK_ROUTE_RESTORE_TIME,
- FORCE_ROUTE_RESTORE
- };
- void handleForcedSpeakerRoute(int command);
-#ifdef WITH_A2DP
- void handleRouteDisablesA2dp_l(int routes);
-#endif
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -201,14 +200,17 @@
class TrackHandle;
class RecordHandle;
- class AudioRecordThread;
+ class RecordThread;
+ class PlaybackThread;
+ class MixerThread;
+ class DirectOutputThread;
+ class Track;
+ class RecordTrack;
-
- // --- MixerThread ---
- class MixerThread : public Thread {
+ class ThreadBase : public Thread {
public:
-
- // --- Track ---
+ ThreadBase (const sp<AudioFlinger>& audioFlinger);
+ virtual ~ThreadBase();
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -230,7 +232,7 @@
// The upper 16 bits are used for track-specific flags.
};
- TrackBase(const sp<MixerThread>& mixerThread,
+ TrackBase(const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -243,11 +245,15 @@
virtual status_t start() = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const;
+ audio_track_cblk_t* cblk() const { return mCblk; }
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class RecordHandle;
- friend class AudioRecordThread;
+ friend class PlaybackThread;
+ friend class RecordThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
TrackBase(const TrackBase&);
TrackBase& operator = (const TrackBase&);
@@ -255,10 +261,6 @@
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
int format() const {
return mFormat;
}
@@ -269,10 +271,6 @@
void* getBuffer(uint32_t offset, uint32_t frames) const;
- int name() const {
- return mName;
- }
-
bool isStopped() const {
return mState == STOPPED;
}
@@ -284,14 +282,13 @@
bool step();
void reset();
- sp<MixerThread> mMixerThread;
+ wp<ThreadBase> mThread;
sp<Client> mClient;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk;
void* mBuffer;
void* mBufferEnd;
uint32_t mFrameCount;
- int mName;
// we don't really need a lock for these
int mState;
int mClientTid;
@@ -299,10 +296,69 @@
uint32_t mFlags;
};
+ class ConfigEvent {
+ public:
+ ConfigEvent() : mEvent(0), mParam(0) {}
+
+ int mEvent;
+ int mParam;
+ };
+
+ uint32_t sampleRate() const;
+ int channelCount() const;
+ int format() const;
+ size_t frameCount() const;
+ void wakeUp() { mWaitWorkCV.broadcast(); }
+ void exit();
+ virtual bool checkForNewParameters_l() = 0;
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys) = 0;
+ virtual void audioConfigChanged(int event, int param = 0) = 0;
+ void sendConfigEvent(int event, int param = 0);
+ void sendConfigEvent_l(int event, int param = 0);
+ void processConfigEvents();
+
+ mutable Mutex mLock;
+
+ protected:
+
+ friend class Track;
+ friend class TrackBase;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+ friend class RecordThread;
+ friend class RecordTrack;
+
+ Condition mWaitWorkCV;
+ sp<AudioFlinger> mAudioFlinger;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ uint32_t mFrameSize;
+ Condition mParamCond;
+ Vector<String8> mNewParameters;
+ status_t mParamStatus;
+ Vector<ConfigEvent *> mConfigEvents;
+ bool mStandby;
+ };
+
+ // --- PlaybackThread ---
+ class PlaybackThread : public ThreadBase {
+ public:
+
+ enum type {
+ MIXER,
+ DIRECT,
+ DUPLICATING
+ };
+
// playback track
class Track : public TrackBase {
public:
- Track( const sp<MixerThread>& mixerThread,
+ Track( const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -321,6 +377,9 @@
void destroy();
void mute(bool);
void setVolume(float left, float right);
+ int name() const {
+ return mName;
+ }
int type() const {
return mStreamType;
@@ -328,29 +387,25 @@
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class AudioFlinger;
- friend class AudioFlinger::TrackHandle;
+ friend class TrackHandle;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
Track(const Track&);
Track& operator = (const Track&);
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool isMuted() const {
- return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
- }
-
+ bool isMuted() { return mMute; }
bool isPausing() const {
return mState == PAUSING;
}
-
bool isPaused() const {
return mState == PAUSED;
}
-
bool isReady() const;
-
void setPaused() { mState = PAUSED; }
void reset();
@@ -364,54 +419,20 @@
sp<IMemory> mSharedBuffer;
bool mResetDone;
int mStreamType;
+ int mName;
}; // end of Track
- // record track
- class RecordTrack : public TrackBase {
- public:
- RecordTrack(const sp<MixerThread>& mixerThread,
- const sp<Client>& client,
- int inputSource,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- uint32_t flags);
- ~RecordTrack();
-
- virtual status_t start();
- virtual void stop();
-
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
- bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
- int inputSource() const { return mInputSource; }
-
- private:
- friend class AudioFlinger;
- friend class AudioFlinger::RecordHandle;
- friend class AudioFlinger::AudioRecordThread;
- friend class MixerThread;
-
- RecordTrack(const Track&);
- RecordTrack& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool mOverflow;
- int mInputSource;
- };
// playback track
class OutputTrack : public Track {
public:
-
+
class Buffer: public AudioBufferProvider::Buffer {
public:
int16_t *mBuffer;
};
-
- OutputTrack( const sp<MixerThread>& mixerThread,
+
+ OutputTrack( const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
@@ -420,35 +441,35 @@
virtual status_t start();
virtual void stop();
- void write(int16_t* data, uint32_t frames);
+ bool write(int16_t* data, uint32_t frames);
bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+ bool isActive() { return mActive; }
+ wp<ThreadBase>& thread() { return mThread; }
private:
- status_t obtainBuffer(AudioBufferProvider::Buffer* buffer);
+ status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs);
void clearBufferQueue();
-
- sp<MixerThread> mOutputMixerThread;
+
+ // Maximum number of pending buffers allocated by OutputTrack::write()
+ static const uint8_t kMaxOverFlowBuffers = 3;
+
Vector < Buffer* > mBufferQueue;
AudioBufferProvider::Buffer mOutBuffer;
- uint32_t mFramesWritten;
-
- }; // end of OutputTrack
+ uint32_t mWaitTimeMs;
+ bool mActive;
- MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
- virtual ~MixerThread();
+ }; // end of OutputTrack
+
+ PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args);
// Thread virtuals
- virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
- virtual uint32_t sampleRate() const;
- virtual int channelCount() const;
- virtual int format() const;
- virtual size_t frameCount() const;
virtual uint32_t latency() const;
virtual status_t setMasterVolume(float value);
@@ -463,9 +484,8 @@
virtual float streamVolume(int stream) const;
virtual bool streamMute(int stream) const;
- bool isMusicActive_l() const;
-
-
+ bool isMusicActive() const;
+
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
int streamType,
@@ -475,13 +495,15 @@
int frameCount,
const sp<IMemory>& sharedBuffer,
status_t *status);
-
- void getTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void putTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
-
+
+ AudioStreamOut* getOutput() { return mOutput; }
+
+ virtual int type() const { return mType; }
+ void suspend() { mSuspended++; }
+ void restore() { if (mSuspended) mSuspended--; }
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+
struct stream_type_t {
stream_type_t()
: volume(1.0f),
@@ -492,56 +514,115 @@
bool mute;
};
+ protected:
+ int mType;
+ int16_t* mMixBuffer;
+ int mSuspended;
+ int mBytesWritten;
+ bool mMasterMute;
+ SortedVector< wp<Track> > mActiveTracks;
+
private:
-
friend class AudioFlinger;
+ friend class OutputTrack;
friend class Track;
friend class TrackBase;
- friend class RecordTrack;
-
- MixerThread(const Client&);
- MixerThread& operator = (const MixerThread&);
-
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+
+ PlaybackThread(const Client&);
+ PlaybackThread& operator = (const PlaybackThread&);
+
status_t addTrack_l(const sp<Track>& track);
void destroyTrack_l(const sp<Track>& track);
- int getTrackName_l();
- void deleteTrackName_l(int name);
- void addActiveTrack_l(const wp<Track>& t);
- void removeActiveTrack_l(const wp<Track>& t);
- size_t getOutputFrameCount();
+ virtual int getTrackName_l() = 0;
+ virtual void deleteTrackName_l(int name) = 0;
+ void readOutputParameters();
- status_t dumpInternals(int fd, const Vector<String16>& args);
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
-
- sp<AudioFlinger> mAudioFlinger;
- SortedVector< wp<Track> > mActiveTracks;
+
SortedVector< sp<Track> > mTracks;
- stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
- AudioMixer* mAudioMixer;
+ // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
+ stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES + 1];
AudioStreamOut* mOutput;
- int mOutputType;
- uint32_t mSampleRate;
- size_t mFrameCount;
- int mChannelCount;
- int mFormat;
- int16_t* mMixBuffer;
float mMasterVolume;
- bool mMasterMute;
nsecs_t mLastWriteTime;
int mNumWrites;
int mNumDelayedWrites;
- bool mStandby;
bool mInWrite;
- sp <OutputTrack> mOutputTrack;
+ int mMinBytesToWrite;
};
-
+ class MixerThread : public PlaybackThread {
+ public:
+ MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~MixerThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ void getTracks(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks,
+ int streamType);
+ void putTracks(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ protected:
+ size_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
+
+ AudioMixer* mAudioMixer;
+ };
+
+ class DirectOutputThread : public PlaybackThread {
+ public:
+
+ DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ ~DirectOutputThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+
+ private:
+ float mLeftVolume;
+ float mRightVolume;
+ };
+
+ class DuplicatingThread : public MixerThread {
+ public:
+ DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread);
+ ~DuplicatingThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ void addOutputTrack(MixerThread* thread);
+ void removeOutputTrack(MixerThread* thread);
+
+ private:
+ SortedVector < sp<OutputTrack> > mOutputTracks;
+ };
+
+ PlaybackThread *checkPlaybackThread_l(int output) const;
+ MixerThread *checkMixerThread_l(int output) const;
+ RecordThread *checkRecordThread_l(int input) const;
+ float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
+ void audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2);
+
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
public:
- TrackHandle(const sp<MixerThread::Track>& track);
+ TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual status_t start();
virtual void stop();
@@ -553,20 +634,91 @@
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::Track> mTrack;
+ sp<PlaybackThread::Track> mTrack;
};
friend class Client;
- friend class MixerThread::Track;
+ friend class PlaybackThread::Track;
void removeClient(pid_t pid);
+ // record thread
+ class RecordThread : public ThreadBase, public AudioBufferProvider
+ {
+ public:
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack(const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class RecordThread;
+
+ RecordTrack(const RecordTrack&);
+ RecordTrack& operator = (const RecordTrack&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
+ };
+
+
+ RecordThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamIn *input,
+ uint32_t sampleRate,
+ uint32_t channels);
+ ~RecordThread();
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun() { return NO_ERROR; }
+ virtual void onFirstRef();
+
+ status_t start(RecordTrack* recordTrack);
+ void stop(RecordTrack* recordTrack);
+ status_t dump(int fd, const Vector<String16>& args);
+ AudioStreamIn* getInput() { return mInput; }
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual bool checkForNewParameters_l();
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+ void readInputParameters();
+
+ private:
+ RecordThread();
+ AudioStreamIn *mInput;
+ sp<RecordTrack> mActiveTrack;
+ Condition mStartStopCond;
+ AudioResampler *mResampler;
+ int32_t *mRsmpOutBuffer;
+ int16_t *mRsmpInBuffer;
+ size_t mRsmpInIndex;
+ size_t mInputBytes;
+ int mReqChannelCount;
+ uint32_t mReqSampleRate;
+ };
class RecordHandle : public android::BnAudioRecord {
public:
- RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
+ RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual status_t start();
virtual void stop();
@@ -574,66 +726,31 @@
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::RecordTrack> mRecordTrack;
+ sp<RecordThread::RecordTrack> mRecordTrack;
};
- // record thread
- class AudioRecordThread : public Thread
- {
- public:
- AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
- virtual ~AudioRecordThread();
- virtual bool threadLoop();
- virtual status_t readyToRun() { return NO_ERROR; }
- virtual void onFirstRef() {}
+ friend class RecordThread;
+ friend class PlaybackThread;
- status_t start(MixerThread::RecordTrack* recordTrack);
- void stop(MixerThread::RecordTrack* recordTrack);
- void exit();
- status_t dump(int fd, const Vector<String16>& args);
- private:
- AudioRecordThread();
- AudioHardwareInterface *mAudioHardware;
- sp<AudioFlinger> mAudioFlinger;
- sp<MixerThread::RecordTrack> mRecordTrack;
- Mutex mLock;
- Condition mWaitWorkCV;
- Condition mStopped;
- volatile bool mActive;
- status_t mStartStatus;
- };
-
- friend class AudioRecordThread;
- friend class MixerThread;
-
- status_t startRecord(MixerThread::RecordTrack* recordTrack);
- void stopRecord(MixerThread::RecordTrack* recordTrack);
-
- mutable Mutex mHardwareLock;
mutable Mutex mLock;
- mutable Condition mWaitWorkCV;
DefaultKeyedVector< pid_t, wp<Client> > mClients;
- sp<MixerThread> mA2dpMixerThread;
- sp<MixerThread> mHardwareMixerThread;
+ mutable Mutex mHardwareLock;
AudioHardwareInterface* mAudioHardware;
- AudioHardwareInterface* mA2dpAudioInterface;
- sp<AudioRecordThread> mAudioRecordThread;
- bool mA2dpEnabled;
- bool mNotifyA2dpChange;
mutable int mHardwareStatus;
- SortedVector< wp<IBinder> > mNotificationClients;
- int mForcedSpeakerCount;
- int mA2dpDisableCount;
- // true if A2DP should resume when mA2dpDisableCount returns to zero
- bool mA2dpSuppressed;
- uint32_t mSavedRoute;
- uint32_t mForcedRoute;
- nsecs_t mRouteRestoreTime;
- bool mMusicMuteSaved;
+
+ DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads;
+ PlaybackThread::stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ float mMasterVolume;
+ bool mMasterMute;
+
+ DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
+
+ SortedVector< sp<IBinder> > mNotificationClients;
+ int mNextThreadId;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 1e159b8..57874f3 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -49,8 +49,8 @@
AudioHardwareGeneric::~AudioHardwareGeneric()
{
if (mFd >= 0) ::close(mFd);
- delete mOutput;
- delete mInput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ closeInputStream((AudioStreamIn *)mInput);
}
status_t AudioHardwareGeneric::initCheck()
@@ -63,7 +63,7 @@
}
AudioStreamOut* AudioHardwareGeneric::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AutoMutex lock(mLock);
@@ -77,7 +77,7 @@
// create new output stream
AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
- status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+ status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -89,17 +89,19 @@
return mOutput;
}
-void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
- if (out == mOutput) mOutput = 0;
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput && out == mOutput) {
+ delete mOutput;
+ mOutput = 0;
+ }
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
@@ -115,7 +117,7 @@
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -127,8 +129,11 @@
return mInput;
}
-void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
- if (in == mInput) mInput = 0;
+void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
+ if (mInput && in == mInput) {
+ delete mInput;
+ mInput = 0;
+ }
}
status_t AudioHardwareGeneric::setVoiceVolume(float v)
@@ -185,30 +190,42 @@
status_t AudioStreamOutGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate)
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate)
{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
AudioStreamOutGeneric::~AudioStreamOutGeneric()
{
- if (mAudioHardware)
- mAudioHardware->closeOutputStream(this);
}
ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
@@ -234,10 +251,12 @@
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -246,29 +265,68 @@
return NO_ERROR;
}
+status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamOutGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
// record functions
status_t AudioStreamInGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+ if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
+ LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate())) {
+ if ((*pFormat != format()) ||
+ (*pChannels != channels()) ||
+ (*pRate != sampleRate())) {
LOGE("Error opening input channel");
+ *pFormat = format();
+ *pChannels = channels();
+ *pRate = sampleRate();
return BAD_VALUE;
}
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
@@ -276,14 +334,12 @@
{
// FIXME: remove logging
LOGD("AudioStreamInGeneric destructor");
- if (mAudioHardware)
- mAudioHardware->closeInputStream(this);
}
ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+ LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, (int)bytes, mFd);
AutoMutex lock(mLock);
if (mFd < 0) {
LOGE("Attempt to read from unopened device");
@@ -303,10 +359,12 @@
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -315,6 +373,39 @@
return NO_ERROR;
}
+status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamInGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index c89df87..42da413 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -39,24 +39,28 @@
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate);
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 20; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
class AudioStreamInGeneric : public AudioStreamIn {
@@ -67,24 +71,28 @@
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics);
- uint32_t sampleRate() const { return 8000; }
+ virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return INVALID_OPERATION; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
@@ -101,28 +109,27 @@
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
private:
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index cc1bd8f..9a4a7f9 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -18,6 +18,7 @@
#include <cutils/properties.h>
#include <string.h>
#include <unistd.h>
+//#define LOG_NDEBUG 0
#define LOG_TAG "AudioHardwareInterface"
#include <utils/Log.h>
@@ -25,15 +26,17 @@
#include "AudioHardwareStub.h"
#include "AudioHardwareGeneric.h"
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
-//#define DUMP_FLINGER_OUT // if defined allows recording samples in a file
-#ifdef DUMP_FLINGER_OUT
+#ifdef ENABLE_AUDIO_DUMP
#include "AudioDumpInterface.h"
#endif
// change to 1 to log routing calls
-#define LOG_ROUTING_CALLS 0
+#define LOG_ROUTING_CALLS 1
namespace android {
@@ -48,14 +51,6 @@
"IN_CALL"
};
-static const char* routeStrings[] =
-{
- "EARPIECE ",
- "SPEAKER ",
- "BLUETOOTH ",
- "HEADSET ",
- "BLUETOOTH_A2DP "
-};
static const char* routeNone = "NONE";
static const char* displayMode(int mode)
@@ -64,22 +59,6 @@
return routingModeStrings[0];
return routingModeStrings[mode+3];
}
-
-static const char* displayRoutes(uint32_t routes)
-{
- static char routeStr[80];
- if (routes == 0)
- return routeNone;
- routeStr[0] = 0;
- int bitMask = 1;
- for (int i = 0; i < 4; ++i, bitMask <<= 1) {
- if (routes & bitMask) {
- strcat(routeStr, routeStrings[i]);
- }
- }
- routeStr[strlen(routeStr)-1] = 0;
- return routeStr;
-}
#endif
// ----------------------------------------------------------------------------
@@ -112,13 +91,17 @@
hw = new AudioHardwareStub();
}
-#ifdef DUMP_FLINGER_OUT
+#ifdef WITH_A2DP
+ hw = new A2dpAudioInterface(hw);
+#endif
+
+#ifdef ENABLE_AUDIO_DUMP
// This code adds a record of buffers in a file to write calls made by AudioFlinger.
// It replaces the current AudioHardwareInterface object by an intermediate one which
// will record buffers in a file (after sending them to hardware) for testing purpose.
- // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
- // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
-
+ // This feature is enabled by defining symbol ENABLE_AUDIO_DUMP.
+ // The output file is set with setParameters("test_cmd_file_name=<name>"). Pause are not recorded in the file.
+ LOGV("opening PCM dump interface");
hw = new AudioDumpInterface(hw); // replace interface
#endif
return hw;
@@ -132,48 +115,9 @@
AudioHardwareBase::AudioHardwareBase()
{
- // force a routing update on initialization
- memset(&mRoutes, 0, sizeof(mRoutes));
mMode = 0;
}
-// generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
-{
-#if LOG_ROUTING_CALLS
- LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
-#endif
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- uint32_t old = mRoutes[mode];
- mRoutes[mode] = routes;
- if ((mode != mMode) || (old == routes))
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- const char* oldRouteStr = strdup(displayRoutes(old));
- LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
- displayMode(mode), oldRouteStr, displayRoutes(routes));
- delete oldRouteStr;
-#endif
- return doRouting();
-}
-
-status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
-{
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- *routes = mRoutes[mode];
-#if LOG_ROUTING_CALLS
- LOGD("getRouting: mode=%s, routes=[%s]",
- displayMode(mode), displayRoutes(*routes));
-#endif
- return NO_ERROR;
-}
-
status_t AudioHardwareBase::setMode(int mode)
{
#if LOG_ROUTING_CALLS
@@ -182,28 +126,23 @@
if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
return BAD_VALUE;
if (mMode == mode)
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
- displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
-#endif
+ return ALREADY_EXISTS;
mMode = mode;
- return doRouting();
-}
-
-status_t AudioHardwareBase::getMode(int* mode)
-{
- // Implement: set audio routing
- *mode = mMode;
return NO_ERROR;
}
-status_t AudioHardwareBase::setParameter(const char* key, const char* value)
+// default implementation
+status_t AudioHardwareBase::setParameters(const String8& keyValuePairs)
{
- // default implementation is to ignore
return NO_ERROR;
}
+// default implementation
+String8 AudioHardwareBase::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
// default implementation
size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
@@ -233,10 +172,6 @@
result.append(buffer);
snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
result.append(buffer);
- for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
- snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
- result.append(buffer);
- }
::write(fd, result.string(), result.size());
dump(fd, args); // Dump the state of the concrete child.
return NO_ERROR;
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0ab4c60..ae391ee 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -43,10 +43,10 @@
}
AudioStreamOut* AudioHardwareStub::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AudioStreamOutStub* out = new AudioStreamOutStub();
- status_t lStatus = out->set(format, channelCount, sampleRate);
+ status_t lStatus = out->set(format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -56,18 +56,22 @@
return 0;
}
+void AudioHardwareStub::closeOutputStream(AudioStreamOut* out)
+{
+ delete out;
+}
+
AudioStreamIn* AudioHardwareStub::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
AudioStreamInStub* in = new AudioStreamInStub();
- status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -77,6 +81,11 @@
return 0;
}
+void AudioHardwareStub::closeInputStream(AudioStreamIn* in)
+{
+ delete in;
+}
+
status_t AudioHardwareStub::setVoiceVolume(float volume)
{
return NO_ERROR;
@@ -107,24 +116,19 @@
// ----------------------------------------------------------------------------
-status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- // fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
{
// fake timing for audio output
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
return bytes;
}
@@ -141,29 +145,31 @@
snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
::write(fd, result.string(), result.size());
return NO_ERROR;
}
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
{
// fake timing for audio input
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
memset(buffer, 0, bytes);
return bytes;
}
@@ -179,7 +185,7 @@
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
@@ -187,6 +193,12 @@
return NO_ERROR;
}
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index bf63cc5..583f852 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -29,29 +29,33 @@
class AudioStreamOutStub : public AudioStreamOut {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 0; }
- virtual status_t setVolume(float volume) { return NO_ERROR; }
+ virtual status_t setVolume(float left, float right) { return NO_ERROR; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys);
};
class AudioStreamInStub : public AudioStreamIn {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics);
virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return NO_ERROR; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys);
};
class AudioHardwareStub : public AudioHardwareBase
@@ -67,26 +71,25 @@
virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
- AudioSystem::audio_in_acoustics acoustics);
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
bool mMicMute;
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index b02efcc..19a442a 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -610,7 +610,6 @@
t->in = in;
}
-inline
void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
{
for (size_t i=0 ; i<c ; i++) {
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 72ca28a..15766cd 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -85,6 +85,8 @@
uint32_t trackNames() const { return mTrackNames; }
+ static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
private:
enum {
@@ -176,7 +178,6 @@
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
static void process__validate(state_t* state, void* output);
static void process__nop(state_t* state, void* output);
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
new file mode 100644
index 0000000..6323859
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
@@ -0,0 +1,826 @@
+/*
+ * 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_TAG "AudioPolicyManagerGeneric"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManagerGeneric.h"
+#include <media/mediarecorder.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+
+ LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ LOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (AudioSystem::isOutputDevice(device)) {
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() connecting device %x", device);
+
+ // register new device as available
+ mAvailableOutputDevices |= device;
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableOutputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+ // handle input devices
+ if (AudioSystem::isInputDevice(device)) {
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableInputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices |= device;
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableInputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+
+ LOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (AudioSystem::isOutputDevice(device)) {
+ if (device & mAvailableOutputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (AudioSystem::isInputDevice(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+void AudioPolicyManagerGeneric::setPhoneState(int state)
+{
+ LOGV("setPhoneState() state %d", state);
+ uint32_t newDevice = 0;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ LOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ LOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+
+ // if leaving or entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (state == AudioSystem::MODE_IN_CALL ||
+ oldState == AudioSystem::MODE_IN_CALL) {
+ bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false;
+ LOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, starting);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ LOGV("setRingerMode() mode %x, mask %x", mode, mask);
+
+ mRingerMode = mode;
+}
+
+void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+ mForceUse[usage] = config;
+}
+
+AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage)
+{
+ return mForceUse[usage];
+}
+
+void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value)
+{
+ LOGV("setSystemProperty() property %s, value %s", property, value);
+ if (strcmp(property, "ro.camera.sound.forced") == 0) {
+ if (atoi(value)) {
+ LOGV("ENFORCED_AUDIBLE cannot be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
+ } else {
+ LOGV("ENFORCED_AUDIBLE can be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
+ }
+ }
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mCurOutput != 0) {
+ LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+ if (mTestOutputs[mCurOutput] == 0) {
+ LOGV("getOutput() opening test output");
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = mTestDevice;
+ outputDesc->mSamplingRate = mTestSamplingRate;
+ outputDesc->mFormat = mTestFormat;
+ outputDesc->mChannels = mTestChannels;
+ outputDesc->mLatency = mTestLatencyMs;
+ outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+ outputDesc->mRefCount[stream] = 0;
+ mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mTestOutputs[mCurOutput]) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"),mCurOutput);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+ mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
+ }
+ }
+ return mTestOutputs[mCurOutput];
+ }
+#endif //AUDIO_POLICY_TEST
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != 0 && !AudioSystem::isLinearPCM(format)) ||
+ (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ return 0;
+ }
+
+ return mHardwareOutput;
+}
+
+status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("startOutput() output %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("startOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, true);
+ }
+
+ // incremenent usage count for this stream on the requested output:
+ outputDesc->changeRefCount(stream, 1);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("stopOutput() output %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("stopOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, false);
+ }
+
+ if (outputDesc->isUsedByStream(stream)) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ return NO_ERROR;
+ } else {
+ LOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
+{
+ LOGV("releaseOutput() %d", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("releaseOutput() releasing unknown output %d", output);
+ return;
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ int testIndex = testOutputIndex(output);
+ if (testIndex != 0) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ if (outputDesc->refCount() == 0) {
+ mpClientInterface->closeOutput(output);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mTestOutputs[testIndex] = 0;
+ }
+ }
+#endif //AUDIO_POLICY_TEST
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ uint32_t device;
+
+ LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
+ inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = format;
+ inputDesc->mChannels = channels;
+ inputDesc->mAcoustics = acoustics;
+ inputDesc->mRefCount = 0;
+ input = mpClientInterface->openInput(&inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannels,
+ inputDesc->mAcoustics);
+
+ // only accept input with the exact requested set of parameters
+ if ((samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channels != inputDesc->mChannels)) {
+ LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d",
+ samplingRate, format, channels);
+ mpClientInterface->closeInput(input);
+ delete inputDesc;
+ return 0;
+ }
+ mInputs.add(input, inputDesc);
+ return input;
+}
+
+status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
+{
+ LOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("startInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+ {
+ // refuse 2 active AudioRecord clients at the same time
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ if (mInputs.valueAt(i)->mRefCount > 0) {
+ LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i));
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
+{
+ LOGV("stopInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("stopInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ LOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ inputDesc->mRefCount = 0;
+ return NO_ERROR;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
+{
+ LOGV("releaseInput() %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("releaseInput() releasing unknown input %d", input);
+ return;
+ }
+ mpClientInterface->closeInput(input);
+ delete mInputs.valueAt(index);
+ mInputs.removeItem(input);
+}
+
+
+
+void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ mStreams[stream].mIndexMin = indexMin;
+ mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+
+ if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
+ mStreams[stream].mIndexCur = index;
+
+ // do not change actual stream volume if the stream is muted
+ if (mStreams[stream].mMuteCount != 0) {
+ return NO_ERROR;
+ }
+
+ // Do not changed in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ // compute and apply stream volume on all outputs according to connected device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ uint32_t device = outputDesc->device();
+
+ float volume = computeVolume((int)stream, index, device);
+
+ LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
+ mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (index == 0) {
+ return BAD_VALUE;
+ }
+ LOGV("getStreamVolumeIndex() stream %d", stream);
+ *index = mStreams[stream].mIndexCur;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerGeneric
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface)
+ :
+#ifdef AUDIO_POLICY_TEST
+ Thread(false),
+#endif //AUDIO_POLICY_TEST
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0)
+{
+ mpClientInterface = clientInterface;
+
+ for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+ mForceUse[i] = AudioSystem::FORCE_NONE;
+ }
+
+ // devices available by default are speaker, ear piece and microphone
+ mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER;
+ mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+
+ // open hardware output
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+
+ if (mHardwareOutput == 0) {
+ LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+
+ mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ mTestLatencyMs = 0;
+ mCurOutput = 0;
+ mDirectOutput = false;
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ mTestOutputs[i] = 0;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric()
+{
+#ifdef AUDIO_POLICY_TEST
+ exit();
+#endif //AUDIO_POLICY_TEST
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ mpClientInterface->closeOutput(mOutputs.keyAt(i));
+ delete mOutputs.valueAt(i);
+ }
+ mOutputs.clear();
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mpClientInterface->closeInput(mInputs.keyAt(i));
+ delete mInputs.valueAt(i);
+ }
+ mInputs.clear();
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerGeneric::threadLoop()
+{
+ LOGV("entering threadLoop()");
+ while (!exitPending())
+ {
+ String8 command;
+ int valueInt;
+ String8 value;
+
+ Mutex::Autolock _l(mLock);
+ mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+ command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+ AudioParameter param = AudioParameter(command);
+
+ if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+ valueInt != 0) {
+ LOGV("Test command %s received", command.string());
+ String8 target;
+ if (param.get(String8("target"), target) != NO_ERROR) {
+ target = "Manager";
+ }
+ if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_output"));
+ mCurOutput = valueInt;
+ }
+ if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_direct"));
+ if (value == "false") {
+ mDirectOutput = false;
+ } else if (value == "true") {
+ mDirectOutput = true;
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_input"));
+ mTestInput = valueInt;
+ }
+
+ if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_format"));
+ int format = AudioSystem::INVALID_FORMAT;
+ if (value == "PCM 16 bits") {
+ format = AudioSystem::PCM_16_BIT;
+ } else if (value == "PCM 8 bits") {
+ format = AudioSystem::PCM_8_BIT;
+ } else if (value == "Compressed MP3") {
+ format = AudioSystem::MP3;
+ }
+ if (format != AudioSystem::INVALID_FORMAT) {
+ if (target == "Manager") {
+ mTestFormat = format;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("format"), format);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_channels"));
+ int channels = 0;
+
+ if (value == "Channels Stereo") {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
+ } else if (value == "Channels Mono") {
+ channels = AudioSystem::CHANNEL_OUT_MONO;
+ }
+ if (channels != 0) {
+ if (target == "Manager") {
+ mTestChannels = channels;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("channels"), channels);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_sampleRate"));
+ if (valueInt >= 0 && valueInt <= 96000) {
+ int samplingRate = valueInt;
+ if (target == "Manager") {
+ mTestSamplingRate = samplingRate;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("sampling_rate"), samplingRate);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+
+ if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_reopen"));
+
+ mpClientInterface->closeOutput(mHardwareOutput);
+ delete mOutputs.valueFor(mHardwareOutput);
+ mOutputs.removeItem(mHardwareOutput);
+
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mHardwareOutput == 0) {
+ LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+ }
+
+
+ mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+ }
+ }
+ return false;
+}
+
+void AudioPolicyManagerGeneric::exit()
+{
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output)
+{
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ if (output == mTestOutputs[i]) return i;
+ }
+ return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream)
+{
+ // stream to strategy mapping
+ switch (stream) {
+ case AudioSystem::VOICE_CALL:
+ case AudioSystem::BLUETOOTH_SCO:
+ return STRATEGY_PHONE;
+ case AudioSystem::RING:
+ case AudioSystem::NOTIFICATION:
+ case AudioSystem::ALARM:
+ case AudioSystem::ENFORCED_AUDIBLE:
+ return STRATEGY_SONIFICATION;
+ case AudioSystem::DTMF:
+ return STRATEGY_DTMF;
+ default:
+ LOGE("unknown stream type");
+ case AudioSystem::SYSTEM:
+ // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+ // while key clicks are played produces a poor result
+ case AudioSystem::TTS:
+ case AudioSystem::MUSIC:
+ return STRATEGY_MEDIA;
+ }
+}
+
+
+float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device)
+{
+ float volume = 1.0;
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ // Force max volume if stream cannot be muted
+ if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax;
+
+ int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
+ volume = AudioSystem::linearToLog(volInt);
+
+ return volume;
+}
+
+void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
+{
+ LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output);
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ if (on) {
+ if (streamDesc.mMuteCount++ == 0) {
+ if (streamDesc.mCanBeMuted) {
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output);
+ }
+ }
+ } else {
+ if (streamDesc.mMuteCount == 0) {
+ LOGW("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if (--streamDesc.mMuteCount == 0) {
+ uint32_t device = mOutputs.valueFor(output)->mDevice;
+ float volume = computeVolume(stream, streamDesc.mIndexCur, device);
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting)
+{
+ // if the stream pertains to sonification strategy and we are in call we must
+ // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+ // in the device used for phone strategy and play the tone if the selected device does not
+ // interfere with the device used for phone strategy
+ if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
+ LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice);
+ if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) {
+ if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+ LOGV("handleIncallSonification() low visibility");
+ setStreamMute(stream, starting, mHardwareOutput);
+ } else {
+ if (starting) {
+ mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+ } else {
+ mpClientInterface->stopTone();
+ }
+ }
+ }
+ }
+}
+
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
+ mFlags((AudioSystem::output_flags)0), mDevice(0)
+{
+ // clear usage count for all stream types
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ mRefCount[i] = 0;
+ }
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device()
+{
+ return mDevice;
+}
+
+void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+ if ((delta + (int)mRefCount[stream]) < 0) {
+ LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount()
+{
+ uint32_t refcount = 0;
+ for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+ refcount += mRefCount[i];
+ }
+ return refcount;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
+{
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
new file mode 100644
index 0000000..d904520
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.h
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+#define NUM_TEST_OUTPUTS 5
+
+class AudioPolicyManagerGeneric: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+ AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface);
+ virtual ~AudioPolicyManagerGeneric();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual void setPhoneState(int state);
+ virtual void setRingerMode(uint32_t mode, uint32_t mask);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics);
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual void initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+private:
+
+ enum routing_strategy {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_DTMF,
+ NUM_STRATEGIES
+ };
+
+ // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+ // and keep track of the usage of this output by each audio stream type.
+ class AudioOutputDescriptor
+ {
+ public:
+ AudioOutputDescriptor();
+
+
+ uint32_t device();
+ void changeRefCount(AudioSystem::stream_type, int delta);
+ bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; }
+ uint32_t refCount();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ AudioSystem::output_flags mFlags; //
+ uint32_t mDevice; // current device this output is routed to
+ uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
+ };
+
+ // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+ // and keep track of the usage of this input.
+ class AudioInputDescriptor
+ {
+ public:
+ AudioInputDescriptor();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; // input configuration
+ uint32_t mChannels; //
+ AudioSystem::audio_in_acoustics mAcoustics; //
+ uint32_t mDevice; // current device this input is routed to
+ uint32_t mRefCount; // number of AudioRecord clients using this output
+ };
+
+ // stream descriptor used for volume control
+ class StreamDescriptor
+ {
+ public:
+ StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {}
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ int mIndexCur; // current volume index
+ int mMuteCount; // mute request counter
+ bool mCanBeMuted; // true is the stream can be muted
+ };
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+ // return the output handle of an output routed to the specified device, 0 if no output
+ // is routed to the device
+ float computeVolume(int stream, int index, uint32_t device);
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(int stream, bool on, audio_io_handle_t output);
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(int stream, bool starting);
+
+
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+
+ AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
+ audio_io_handle_t mHardwareOutput; // hardware output handler
+
+ KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; // list ot output descritors
+ KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors
+ uint32_t mAvailableOutputDevices; // bit field of all available output devices
+ uint32_t mAvailableInputDevices; // bit field of all available input devices
+ int mPhoneState; // current phone state
+ uint32_t mRingerMode; // current ringer mode
+ AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
+
+ StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannels;
+ uint32_t mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+};
+
+};
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
new file mode 100644
index 0000000..ae17d76
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -0,0 +1,650 @@
+/*
+ * 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_TAG "AudioPolicyService"
+//#define LOG_NDEBUG 0
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <binder/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include "AudioPolicyService.h"
+#include "AudioPolicyManagerGeneric.h"
+#include <cutils/properties.h>
+#include <dlfcn.h>
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+namespace android {
+
+static bool checkPermission() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+ if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioPolicyService::AudioPolicyService()
+ : BnAudioPolicyService() , mpPolicyManager(NULL)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ // start tone playback thread
+ mTonePlaybacThread = new AudioCommandThread();
+ // start audio commands thread
+ mAudioCommandThread = new AudioCommandThread();
+
+#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ LOGV("build for GENERIC_AUDIO - using generic audio policy");
+#else
+ // if running in emulation - use the emulator driver
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ LOGV("Running in emulation - using generic audio policy");
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ }
+ else {
+ LOGV("Using hardware specific audio policy");
+ mpPolicyManager = createAudioPolicyManager(this);
+ }
+#endif
+
+ // load properties
+ property_get("ro.camera.sound.forced", value, "0");
+ mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+}
+
+AudioPolicyService::~AudioPolicyService()
+{
+ mTonePlaybacThread->exit();
+ mTonePlaybacThread.clear();
+ mAudioCommandThread->exit();
+ mAudioCommandThread.clear();
+
+ if (mpPolicyManager) {
+ delete mpPolicyManager;
+ }
+}
+
+
+status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
+ return BAD_VALUE;
+ }
+ if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setDeviceConnectionState() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ return mpPolicyManager->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioPolicyService::setPhoneState(int state)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setPhoneState() tid %d", gettid());
+
+ // TODO: check if it is more appropriate to do it in platform specific policy manager
+ AudioSystem::setMode(state);
+
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setPhoneState(state);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+
+ mpPolicyManager->setRingerMode(mode, mask);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return BAD_VALUE;
+ }
+ if (config < 0 || config >= AudioSystem::NUM_FORCE_CONFIG) {
+ return BAD_VALUE;
+ }
+ LOGV("setForceUse() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setForceUse(usage, config);
+ return NO_ERROR;
+}
+
+AudioSystem::forced_config AudioPolicyService::getForceUse(AudioSystem::force_use usage)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return AudioSystem::FORCE_NONE;
+ }
+ return mpPolicyManager->getForceUse(usage);
+}
+
+audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ if (mpPolicyManager == NULL) {
+ return 0;
+ }
+ LOGV("getOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);
+}
+
+status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("startOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startOutput(output, stream);
+}
+
+status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("stopOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopOutput(output, stream);
+}
+
+void AudioPolicyService::releaseOutput(audio_io_handle_t output)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ LOGV("releaseOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ if (mpPolicyManager == NULL) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+
+status_t AudioPolicyService::startInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startInput(input);
+}
+
+status_t AudioPolicyService::stopInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopInput(input);
+}
+
+void AudioPolicyService::releaseInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseInput(input);
+}
+
+status_t AudioPolicyService::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ mpPolicyManager->initStreamVolume(stream, indexMin, indexMax);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+ return mpPolicyManager->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ return mpPolicyManager->getStreamVolumeIndex(stream, index);
+}
+
+void AudioPolicyService::binderDied(const wp<IBinder>& who) {
+ LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+}
+
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd, args);
+ } else {
+
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioPolicyService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioPolicyService::onTransact(code, data, reply, flags);
+}
+
+
+// ----------------------------------------------------------------------------
+void AudioPolicyService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.audio_policy"), new AudioPolicyService());
+}
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyClientInterface implementation
+// ----------------------------------------------------------------------------
+
+
+audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openOutput() could not get AudioFlinger");
+ return 0;
+ }
+
+ return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
+}
+
+audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openDuplicateOutput() could not get AudioFlinger");
+ return 0;
+ }
+ return af->openDuplicateOutput(output1, output2);
+}
+
+status_t AudioPolicyService::closeOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeOutput(output);
+}
+
+
+status_t AudioPolicyService::suspendOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("suspendOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->suspendOutput(output);
+}
+
+status_t AudioPolicyService::restoreOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("restoreOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->restoreOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openInput() could not get AudioFlinger");
+ return 0;
+ }
+
+ return af->openInput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, acoustics);
+}
+
+status_t AudioPolicyService::closeInput(audio_io_handle_t input)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeInput(input);
+}
+
+status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output)
+{
+ return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output);
+}
+
+status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->setStreamOutput(stream, output);
+}
+
+
+void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+{
+ mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs);
+}
+
+String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+ String8 result = AudioSystem::getParameters(ioHandle, keys);
+ return result;
+}
+
+status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
+{
+ mTonePlaybacThread->startToneCommand(tone, stream);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::stopTone()
+{
+ mTonePlaybacThread->stopToneCommand();
+ return NO_ERROR;
+}
+
+
+// ----------- AudioPolicyService::AudioCommandThread implementation ----------
+
+AudioPolicyService::AudioCommandThread::AudioCommandThread()
+ : Thread(false)
+{
+ mpToneGenerator = NULL;
+}
+
+
+AudioPolicyService::AudioCommandThread::~AudioCommandThread()
+{
+ mAudioCommands.clear();
+ if (mpToneGenerator != NULL) delete mpToneGenerator;
+}
+
+void AudioPolicyService::AudioCommandThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "AudioCommandThread");
+
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+}
+
+bool AudioPolicyService::AudioCommandThread::threadLoop()
+{
+ mLock.lock();
+ while (!exitPending())
+ {
+ while(!mAudioCommands.isEmpty()) {
+ AudioCommand *command = mAudioCommands[0];
+ mAudioCommands.removeAt(0);
+ switch (command->mCommand) {
+ case START_TONE: {
+ mLock.unlock();
+ ToneData *data = (ToneData *)command->mParam;
+ LOGV("AudioCommandThread() processing start tone %d on stream %d",
+ data->mType, data->mStream);
+ if (mpToneGenerator != NULL)
+ delete mpToneGenerator;
+ mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
+ mpToneGenerator->startTone(data->mType);
+ delete data;
+ mLock.lock();
+ }break;
+ case STOP_TONE: {
+ mLock.unlock();
+ LOGV("AudioCommandThread() processing stop tone");
+ if (mpToneGenerator != NULL) {
+ mpToneGenerator->stopTone();
+ delete mpToneGenerator;
+ mpToneGenerator = NULL;
+ }
+ mLock.lock();
+ }break;
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+ mCommandStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+ mCommandCond.signal();
+ mWaitWorkCV.wait(mLock);
+ delete data;
+ }break;
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
+ mCommandStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ mCommandCond.signal();
+ mWaitWorkCV.wait(mLock);
+ delete data;
+ }break;
+ default:
+ LOGW("AudioCommandThread() unknown command %d", command->mCommand);
+ }
+ delete command;
+ }
+ LOGV("AudioCommandThread() going to sleep");
+ mWaitWorkCV.wait(mLock);
+ LOGV("AudioCommandThread() waking up");
+ }
+ mLock.unlock();
+ return false;
+}
+
+void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stream)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = START_TONE;
+ ToneData *data = new ToneData();
+ data->mType = type;
+ data->mStream = stream;
+ command->mParam = (void *)data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
+ mWaitWorkCV.signal();
+}
+
+void AudioPolicyService::AudioCommandThread::stopToneCommand()
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = STOP_TONE;
+ command->mParam = NULL;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding tone stop");
+ mWaitWorkCV.signal();
+}
+
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_VOLUME;
+ VolumeData *data = new VolumeData();
+ data->mStream = stream;
+ data->mVolume = volume;
+ data->mIO = output;
+ command->mParam = data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
+ mWaitWorkCV.signal();
+ mCommandCond.wait(mLock);
+ status_t status = mCommandStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_PARAMETERS;
+ ParametersData *data = new ParametersData();
+ data->mIO = ioHandle;
+ data->mKeyValuePairs = keyValuePairs;
+ command->mParam = data;
+ mAudioCommands.add(command);
+ LOGV("AudioCommandThread() adding set parameter string %s, io %d", keyValuePairs.string(), ioHandle);
+ mWaitWorkCV.signal();
+ mCommandCond.wait(mLock);
+ status_t status = mCommandStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+void AudioPolicyService::AudioCommandThread::exit()
+{
+ LOGV("AudioCommandThread::exit");
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
new file mode 100644
index 0000000..3909fa4
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -0,0 +1,198 @@
+/*
+ * 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 ANDROID_AUDIOPOLICYSERVICE_H
+#define ANDROID_AUDIOPOLICYSERVICE_H
+
+#include <media/IAudioPolicyService.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <media/ToneGenerator.h>
+
+namespace android {
+
+class String8;
+
+// ----------------------------------------------------------------------------
+
+class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient
+{
+
+public:
+ static void instantiate();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ //
+ // BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
+ //
+
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual status_t setPhoneState(int state);
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask);
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0);
+ virtual status_t startInput(audio_io_handle_t input);
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags);
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ //
+ // AudioPolicyClientInterface
+ //
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags);
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2);
+ virtual status_t closeOutput(audio_io_handle_t output);
+ virtual status_t suspendOutput(audio_io_handle_t output);
+ virtual status_t restoreOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+ virtual status_t closeInput(audio_io_handle_t input);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output);
+ virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
+ virtual status_t stopTone();
+
+private:
+ AudioPolicyService();
+ virtual ~AudioPolicyService();
+
+ // Thread used for tone playback and to send audio config commands to audio flinger
+ // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because startTone()
+ // and stopTone() are normally called with mLock locked and requesting a tone start or stop will cause
+ // calls to AudioPolicyService and an attempt to lock mLock.
+ // For audio config commands, it is necessary because audio flinger requires that the calling process (user)
+ // has permission to modify audio settings.
+ class AudioCommandThread : public Thread {
+ public:
+
+ // commands for tone AudioCommand
+ enum {
+ START_TONE,
+ STOP_TONE,
+ SET_VOLUME,
+ SET_PARAMETERS
+ };
+
+ AudioCommandThread ();
+ virtual ~AudioCommandThread();
+
+ // Thread virtuals
+ virtual void onFirstRef();
+ virtual bool threadLoop();
+
+ void exit();
+ void startToneCommand(int type = 0, int stream = 0);
+ void stopToneCommand();
+ status_t volumeCommand(int stream, float volume, int output);
+ status_t parametersCommand(int ioHandle, const String8& keyValuePairs);
+
+ private:
+ // descriptor for requested tone playback event
+ class AudioCommand {
+ public:
+ int mCommand; // START_TONE, STOP_TONE ...
+ void *mParam;
+ };
+
+ class ToneData {
+ public:
+ int mType; // tone type (START_TONE only)
+ int mStream; // stream type (START_TONE only)
+ };
+
+ class VolumeData {
+ public:
+ int mStream;
+ float mVolume;
+ int mIO;
+ };
+ class ParametersData {
+ public:
+ int mIO;
+ String8 mKeyValuePairs;
+ };
+
+
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ Vector<AudioCommand *> mAudioCommands; // list of pending tone events
+ Condition mCommandCond;
+ status_t mCommandStatus;
+ ToneGenerator *mpToneGenerator; // the tone generator
+ };
+
+ // Internal dump utilities.
+ status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
+
+
+ Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing device
+ // connection stated our routing
+ AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
+ sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
+ sp <AudioCommandThread> mTonePlaybacThread; // tone playback thread
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYSERVICE_H
+
+
+
+
+
+
+
+
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
new file mode 100644
index 0000000..2df6775
--- /dev/null
+++ b/libs/binder/Android.mk
@@ -0,0 +1,45 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+ Binder.cpp \
+ BpBinder.cpp \
+ IInterface.cpp \
+ IMemory.cpp \
+ IPCThreadState.cpp \
+ IPermissionController.cpp \
+ IServiceManager.cpp \
+ MemoryDealer.cpp \
+ MemoryBase.cpp \
+ MemoryHeapBase.cpp \
+ MemoryHeapPmem.cpp \
+ Parcel.cpp \
+ Permission.cpp \
+ ProcessState.cpp \
+ Static.cpp
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libutils
+
+LOCAL_MODULE:= libbinder
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
new file mode 100644
index 0000000..0dd7622
--- /dev/null
+++ b/libs/binder/Binder.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+
+#include <utils/Atomic.h>
+#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+IBinder::IBinder()
+ : RefBase()
+{
+}
+
+IBinder::~IBinder()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
+{
+ return NULL;
+}
+
+BBinder* IBinder::localBinder()
+{
+ return NULL;
+}
+
+BpBinder* IBinder::remoteBinder()
+{
+ return NULL;
+}
+
+bool IBinder::checkSubclass(const void* /*subclassID*/) const
+{
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+class BBinder::Extras
+{
+public:
+ Mutex mLock;
+ BpBinder::ObjectManager mObjects;
+};
+
+// ---------------------------------------------------------------------------
+
+String16 BBinder::sEmptyDescriptor;
+
+BBinder::BBinder()
+ : mExtras(NULL)
+{
+}
+
+bool BBinder::isBinderAlive() const
+{
+ return true;
+}
+
+status_t BBinder::pingBinder()
+{
+ return NO_ERROR;
+}
+
+const String16& BBinder::getInterfaceDescriptor() const
+{
+ LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
+ return sEmptyDescriptor;
+}
+
+status_t BBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ data.setDataPosition(0);
+
+ status_t err = NO_ERROR;
+ switch (code) {
+ case PING_TRANSACTION:
+ reply->writeInt32(pingBinder());
+ break;
+ default:
+ err = onTransact(code, data, reply, flags);
+ break;
+ }
+
+ if (reply != NULL) {
+ reply->setDataPosition(0);
+ }
+
+ return err;
+}
+
+status_t BBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+void BBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ Extras* e = mExtras;
+
+ if (!e) {
+ e = new Extras;
+ if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
+ reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
+ delete e;
+ e = mExtras;
+ }
+ if (e == 0) return; // out of memory
+ }
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BBinder::findObject(const void* objectID) const
+{
+ Extras* e = mExtras;
+ if (!e) return NULL;
+
+ AutoMutex _l(e->mLock);
+ return e->mObjects.find(objectID);
+}
+
+void BBinder::detachObject(const void* objectID)
+{
+ Extras* e = mExtras;
+ if (!e) return;
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.detach(objectID);
+}
+
+BBinder* BBinder::localBinder()
+{
+ return this;
+}
+
+BBinder::~BBinder()
+{
+ if (mExtras) delete mExtras;
+}
+
+
+status_t BBinder::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ reply->writeString16(getInterfaceDescriptor());
+ return NO_ERROR;
+
+ case DUMP_TRANSACTION: {
+ int fd = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ return dump(fd, args);
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+ // This is used to transfer ownership of the remote binder from
+ // the BpRefBase object holding it (when it is constructed), to the
+ // owner of the BpRefBase object when it first acquires that BpRefBase.
+ kRemoteAcquired = 0x00000001
+};
+
+BpRefBase::BpRefBase(const sp<IBinder>& o)
+ : mRemote(o.get()), mRefs(NULL), mState(0)
+{
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+
+ if (mRemote) {
+ mRemote->incStrong(this); // Removed on first IncStrong().
+ mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
+ }
+}
+
+BpRefBase::~BpRefBase()
+{
+ if (mRemote) {
+ if (!(mState&kRemoteAcquired)) {
+ mRemote->decStrong(this);
+ }
+ mRefs->decWeak(this);
+ }
+}
+
+void BpRefBase::onFirstRef()
+{
+ android_atomic_or(kRemoteAcquired, &mState);
+}
+
+void BpRefBase::onLastStrongRef(const void* id)
+{
+ if (mRemote) {
+ mRemote->decStrong(this);
+ }
+}
+
+bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ return mRemote ? mRefs->attemptIncStrong(this) : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
new file mode 100644
index 0000000..5de87ec
--- /dev/null
+++ b/libs/binder/BpBinder.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BpBinder"
+//#define LOG_NDEBUG 0
+
+#include <binder/BpBinder.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+//#undef LOGV
+//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BpBinder::ObjectManager::ObjectManager()
+{
+}
+
+BpBinder::ObjectManager::~ObjectManager()
+{
+ kill();
+}
+
+void BpBinder::ObjectManager::attach(
+ const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func)
+{
+ entry_t e;
+ e.object = object;
+ e.cleanupCookie = cleanupCookie;
+ e.func = func;
+
+ if (mObjects.indexOfKey(objectID) >= 0) {
+ LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
+ objectID, this, object);
+ return;
+ }
+
+ mObjects.add(objectID, e);
+}
+
+void* BpBinder::ObjectManager::find(const void* objectID) const
+{
+ const ssize_t i = mObjects.indexOfKey(objectID);
+ if (i < 0) return NULL;
+ return mObjects.valueAt(i).object;
+}
+
+void BpBinder::ObjectManager::detach(const void* objectID)
+{
+ mObjects.removeItem(objectID);
+}
+
+void BpBinder::ObjectManager::kill()
+{
+ const size_t N = mObjects.size();
+ LOGV("Killing %d objects in manager %p", N, this);
+ for (size_t i=0; i<N; i++) {
+ const entry_t& e = mObjects.valueAt(i);
+ if (e.func != NULL) {
+ e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ }
+ }
+
+ mObjects.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+BpBinder::BpBinder(int32_t handle)
+ : mHandle(handle)
+ , mAlive(1)
+ , mObitsSent(0)
+ , mObituaries(NULL)
+{
+ LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ IPCThreadState::self()->incWeakHandle(handle);
+}
+
+bool BpBinder::isDescriptorCached() const {
+ Mutex::Autolock _l(mLock);
+ return mDescriptorCache.size() ? true : false;
+}
+
+const String16& BpBinder::getInterfaceDescriptor() const
+{
+ if (isDescriptorCached() == false) {
+ Parcel send, reply;
+ // do the IPC without a lock held.
+ status_t err = const_cast<BpBinder*>(this)->transact(
+ INTERFACE_TRANSACTION, send, &reply);
+ if (err == NO_ERROR) {
+ String16 res(reply.readString16());
+ Mutex::Autolock _l(mLock);
+ // mDescriptorCache could have been assigned while the lock was
+ // released.
+ if (mDescriptorCache.size() == 0)
+ mDescriptorCache = res;
+ }
+ }
+
+ // we're returning a reference to a non-static object here. Usually this
+ // is not something smart to do, however, with binder objects it is
+ // (usually) safe because they are reference-counted.
+
+ return mDescriptorCache;
+}
+
+bool BpBinder::isBinderAlive() const
+{
+ return mAlive != 0;
+}
+
+status_t BpBinder::pingBinder()
+{
+ Parcel send;
+ Parcel reply;
+ status_t err = transact(PING_TRANSACTION, send, &reply);
+ if (err != NO_ERROR) return err;
+ if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
+ return (status_t)reply.readInt32();
+}
+
+status_t BpBinder::dump(int fd, const Vector<String16>& args)
+{
+ Parcel send;
+ Parcel reply;
+ send.writeFileDescriptor(fd);
+ const size_t numArgs = args.size();
+ send.writeInt32(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ send.writeString16(args[i]);
+ }
+ status_t err = transact(DUMP_TRANSACTION, send, &reply);
+ return err;
+}
+
+status_t BpBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // Once a binder has died, it will never come back to life.
+ if (mAlive) {
+ status_t status = IPCThreadState::self()->transact(
+ mHandle, code, data, reply, flags);
+ if (status == DEAD_OBJECT) mAlive = 0;
+ return status;
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ Obituary ob;
+ ob.recipient = recipient;
+ ob.cookie = cookie;
+ ob.flags = flags;
+
+ LOG_ALWAYS_FATAL_IF(recipient == NULL,
+ "linkToDeath(): recipient must be non-NULL");
+
+ {
+ AutoMutex _l(mLock);
+
+ if (!mObitsSent) {
+ if (!mObituaries) {
+ mObituaries = new Vector<Obituary>;
+ if (!mObituaries) {
+ return NO_MEMORY;
+ }
+ LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+ getWeakRefs()->incWeak(this);
+ IPCThreadState* self = IPCThreadState::self();
+ self->requestDeathNotification(mHandle, this);
+ self->flushCommands();
+ }
+ ssize_t res = mObituaries->add(ob);
+ return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+ }
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ AutoMutex _l(mLock);
+
+ if (mObitsSent) {
+ return DEAD_OBJECT;
+ }
+
+ const size_t N = mObituaries ? mObituaries->size() : 0;
+ for (size_t i=0; i<N; i++) {
+ const Obituary& obit = mObituaries->itemAt(i);
+ if ((obit.recipient == recipient
+ || (recipient == NULL && obit.cookie == cookie))
+ && obit.flags == flags) {
+ const uint32_t allFlags = obit.flags|flags;
+ if (outRecipient != NULL) {
+ *outRecipient = mObituaries->itemAt(i).recipient;
+ }
+ mObituaries->removeAt(i);
+ if (mObituaries->size() == 0) {
+ LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ delete mObituaries;
+ mObituaries = NULL;
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpBinder::sendObituary()
+{
+ LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
+ this, mHandle, mObitsSent ? "true" : "false");
+
+ mAlive = 0;
+ if (mObitsSent) return;
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ mObituaries = NULL;
+ }
+ mObitsSent = 1;
+ mLock.unlock();
+
+ LOGV("Reporting death of proxy %p for %d recipients\n",
+ this, obits ? obits->size() : 0);
+
+ if (obits != NULL) {
+ const size_t N = obits->size();
+ for (size_t i=0; i<N; i++) {
+ reportOneDeath(obits->itemAt(i));
+ }
+
+ delete obits;
+ }
+}
+
+void BpBinder::reportOneDeath(const Obituary& obit)
+{
+ sp<DeathRecipient> recipient = obit.recipient.promote();
+ LOGV("Reporting death to recipient: %p\n", recipient.get());
+ if (recipient == NULL) return;
+
+ recipient->binderDied(this);
+}
+
+
+void BpBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ AutoMutex _l(mLock);
+ LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
+ mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BpBinder::findObject(const void* objectID) const
+{
+ AutoMutex _l(mLock);
+ return mObjects.find(objectID);
+}
+
+void BpBinder::detachObject(const void* objectID)
+{
+ AutoMutex _l(mLock);
+ mObjects.detach(objectID);
+}
+
+BpBinder* BpBinder::remoteBinder()
+{
+ return this;
+}
+
+BpBinder::~BpBinder()
+{
+ LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ if (ipc) ipc->clearDeathNotification(mHandle, this);
+ mObituaries = NULL;
+ }
+ mLock.unlock();
+
+ if (obits != NULL) {
+ // XXX Should we tell any remaining DeathRecipient
+ // objects that the last strong ref has gone away, so they
+ // are no longer linked?
+ delete obits;
+ }
+
+ if (ipc) {
+ ipc->expungeHandle(mHandle, this);
+ ipc->decWeakHandle(mHandle);
+ }
+}
+
+void BpBinder::onFirstRef()
+{
+ LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->incStrongHandle(mHandle);
+}
+
+void BpBinder::onLastStrongRef(const void* id)
+{
+ LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+ IF_LOGV() {
+ printRefs();
+ }
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->decStrongHandle(mHandle);
+}
+
+bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
new file mode 100644
index 0000000..29acf5d
--- /dev/null
+++ b/libs/binder/IInterface.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+IInterface::IInterface()
+ : RefBase() {
+}
+
+IInterface::~IInterface() {
+}
+
+sp<IBinder> IInterface::asBinder()
+{
+ return this ? onAsBinder() : NULL;
+}
+
+sp<const IBinder> IInterface::asBinder() const
+{
+ return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
new file mode 100644
index 0000000..6c1d225
--- /dev/null
+++ b/libs/binder/IMemory.cpp
@@ -0,0 +1,492 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IMemory"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <binder/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <binder/Parcel.h>
+#include <utils/CallStack.h>
+
+#define VERBOSE 0
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HeapCache : public IBinder::DeathRecipient
+{
+public:
+ HeapCache();
+ virtual ~HeapCache();
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
+ void pin_heap(const sp<IBinder>& binder);
+ void free_heap(const sp<IBinder>& binder);
+ sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
+ void dump_heaps();
+
+private:
+ // For IMemory.cpp
+ struct heap_info_t {
+ sp<IMemoryHeap> heap;
+ int32_t count;
+ };
+
+ void free_heap(const wp<IBinder>& binder);
+
+ Mutex mHeapCacheLock;
+ KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+};
+
+static sp<HeapCache> gHeapCache = new HeapCache();
+
+/******************************************************************************/
+
+enum {
+ HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemoryHeap : public BpInterface<IMemoryHeap>
+{
+public:
+ BpMemoryHeap(const sp<IBinder>& impl);
+ virtual ~BpMemoryHeap();
+
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+private:
+ friend class IMemory;
+ friend class HeapCache;
+
+ // for debugging in this module
+ static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
+ return gHeapCache->find_heap(binder);
+ }
+ static inline void free_heap(const sp<IBinder>& binder) {
+ gHeapCache->free_heap(binder);
+ }
+ static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
+ return gHeapCache->get_heap(binder);
+ }
+ static inline void dump_heaps() {
+ gHeapCache->dump_heaps();
+ }
+ void inline pin_heap() const {
+ gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
+ }
+
+ void assertMapped() const;
+ void assertReallyMapped() const;
+ void pinHeap() const;
+
+ mutable volatile int32_t mHeapId;
+ mutable void* mBase;
+ mutable size_t mSize;
+ mutable uint32_t mFlags;
+ mutable bool mRealHeap;
+ mutable Mutex mLock;
+};
+
+// ----------------------------------------------------------------------------
+
+enum {
+ GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemory : public BpInterface<IMemory>
+{
+public:
+ BpMemory(const sp<IBinder>& impl);
+ virtual ~BpMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
+
+private:
+ mutable sp<IMemoryHeap> mHeap;
+ mutable ssize_t mOffset;
+ mutable size_t mSize;
+};
+
+/******************************************************************************/
+
+void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
+{
+ sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
+ void* const base = realHeap->base();
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+void* IMemory::pointer() const {
+ ssize_t offset;
+ sp<IMemoryHeap> heap = getMemory(&offset);
+ void* const base = heap!=0 ? heap->base() : MAP_FAILED;
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+size_t IMemory::size() const {
+ size_t size;
+ getMemory(NULL, &size);
+ return size;
+}
+
+ssize_t IMemory::offset() const {
+ ssize_t offset;
+ getMemory(&offset);
+ return offset;
+}
+
+/******************************************************************************/
+
+BpMemory::BpMemory(const sp<IBinder>& impl)
+ : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
+{
+}
+
+BpMemory::~BpMemory()
+{
+}
+
+sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (mHeap == 0) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
+ if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
+ sp<IBinder> heap = reply.readStrongBinder();
+ ssize_t o = reply.readInt32();
+ size_t s = reply.readInt32();
+ if (heap != 0) {
+ mHeap = interface_cast<IMemoryHeap>(heap);
+ if (mHeap != 0) {
+ mOffset = o;
+ mSize = s;
+ }
+ }
+ }
+ }
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+
+BnMemory::BnMemory() {
+}
+
+BnMemory::~BnMemory() {
+}
+
+status_t BnMemory::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_MEMORY: {
+ CHECK_INTERFACE(IMemory, data, reply);
+ ssize_t offset;
+ size_t size;
+ reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
+ reply->writeInt32(offset);
+ reply->writeInt32(size);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+/******************************************************************************/
+
+BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
+ : BpInterface<IMemoryHeap>(impl),
+ mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
+{
+}
+
+BpMemoryHeap::~BpMemoryHeap() {
+ if (mHeapId != -1) {
+ close(mHeapId);
+ if (mRealHeap) {
+ // by construction we're the last one
+ if (mBase != MAP_FAILED) {
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+
+ if (VERBOSE) {
+ LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
+ binder.get(), this, mSize, mHeapId);
+ CallStack stack;
+ stack.update();
+ stack.dump("callstack");
+ }
+
+ munmap(mBase, mSize);
+ }
+ } else {
+ // remove from list only if it was mapped before
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertMapped() const
+{
+ if (mHeapId == -1) {
+ sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
+ sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+ heap->assertReallyMapped();
+ if (heap->mBase != MAP_FAILED) {
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mBase = heap->mBase;
+ mSize = heap->mSize;
+ android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+ }
+ } else {
+ // something went wrong
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertReallyMapped() const
+{
+ if (mHeapId == -1) {
+
+ // remote call without mLock held, worse case scenario, we end up
+ // calling transact() from multiple threads, but that's not a problem,
+ // only mmap below must be in the critical section.
+
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
+ status_t err = remote()->transact(HEAP_ID, data, &reply);
+ int parcel_fd = reply.readFileDescriptor();
+ ssize_t size = reply.readInt32();
+ uint32_t flags = reply.readInt32();
+
+ LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",
+ asBinder().get(), parcel_fd, size, err, strerror(-err));
+
+ int fd = dup( parcel_fd );
+ LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",
+ parcel_fd, size, err, strerror(errno));
+
+ int access = PROT_READ;
+ if (!(flags & READ_ONLY)) {
+ access |= PROT_WRITE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mRealHeap = true;
+ mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
+ if (mBase == MAP_FAILED) {
+ LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
+ asBinder().get(), size, fd, strerror(errno));
+ close(fd);
+ } else {
+ if (flags & MAP_ONCE) {
+ //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
+ // asBinder().get(), size, fd);
+ pin_heap();
+ }
+ mSize = size;
+ mFlags = flags;
+ android_atomic_write(fd, &mHeapId);
+ }
+ }
+ }
+}
+
+int BpMemoryHeap::getHeapID() const {
+ assertMapped();
+ return mHeapId;
+}
+
+void* BpMemoryHeap::getBase() const {
+ assertMapped();
+ return mBase;
+}
+
+size_t BpMemoryHeap::getSize() const {
+ assertMapped();
+ return mSize;
+}
+
+uint32_t BpMemoryHeap::getFlags() const {
+ assertMapped();
+ return mFlags;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+
+BnMemoryHeap::BnMemoryHeap() {
+}
+
+BnMemoryHeap::~BnMemoryHeap() {
+}
+
+status_t BnMemoryHeap::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case HEAP_ID: {
+ CHECK_INTERFACE(IMemoryHeap, data, reply);
+ reply->writeFileDescriptor(getHeapID());
+ reply->writeInt32(getSize());
+ reply->writeInt32(getFlags());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+/*****************************************************************************/
+
+HeapCache::HeapCache()
+ : DeathRecipient()
+{
+}
+
+HeapCache::~HeapCache()
+{
+}
+
+void HeapCache::binderDied(const wp<IBinder>& binder)
+{
+ //LOGD("binderDied binder=%p", binder.unsafe_get());
+ free_heap(binder);
+}
+
+sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info = mHeapCache.editValueAt(i);
+ LOGD_IF(VERBOSE,
+ "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ android_atomic_inc(&info.count);
+ return info.heap;
+ } else {
+ heap_info_t info;
+ info.heap = interface_cast<IMemoryHeap>(binder);
+ info.count = 1;
+ //LOGD("adding binder=%p, heap=%p, count=%d",
+ // binder.get(), info.heap.get(), info.count);
+ mHeapCache.add(binder, info);
+ return info.heap;
+ }
+}
+
+void HeapCache::pin_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ android_atomic_inc(&info.count);
+ binder->linkToDeath(this);
+ } else {
+ LOGE("pin_heap binder=%p not found!!!", binder.get());
+ }
+}
+
+void HeapCache::free_heap(const sp<IBinder>& binder) {
+ free_heap( wp<IBinder>(binder) );
+}
+
+void HeapCache::free_heap(const wp<IBinder>& binder)
+{
+ sp<IMemoryHeap> rel;
+ {
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ int32_t c = android_atomic_dec(&info.count);
+ if (c == 1) {
+ LOGD_IF(VERBOSE,
+ "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.unsafe_get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ rel = mHeapCache.valueAt(i).heap;
+ mHeapCache.removeItemsAt(i);
+ }
+ } else {
+ LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
+ }
+ }
+}
+
+sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
+{
+ sp<IMemoryHeap> realHeap;
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
+ else realHeap = interface_cast<IMemoryHeap>(binder);
+ return realHeap;
+}
+
+void HeapCache::dump_heaps()
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ int c = mHeapCache.size();
+ for (int i=0 ; i<c ; i++) {
+ const heap_info_t& info = mHeapCache.valueAt(i);
+ BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
+ LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
+ mHeapCache.keyAt(i).unsafe_get(),
+ info.heap.get(), info.count,
+ h->mHeapId, h->mBase, h->mSize);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
new file mode 100644
index 0000000..c371a23
--- /dev/null
+++ b/libs/binder/IPCThreadState.cpp
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/TextOutput.h>
+#include <utils/threads.h>
+
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
+
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_TRANSACTIONS() if (false)
+#define IF_LOG_COMMANDS() if (false)
+#define LOG_REMOTEREFS(...)
+#define IF_LOG_REMOTEREFS() if (false)
+#define LOG_THREADPOOL(...)
+#define LOG_ONEWAY(...)
+
+#else
+
+#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
+#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
+#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
+#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
+#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
+#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
+
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static const char* getReturnString(size_t idx);
+static const char* getCommandString(size_t idx);
+static const void* printReturnCommand(TextOutput& out, const void* _cmd);
+static const void* printCommand(TextOutput& out, const void* _cmd);
+
+// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
+// conditionals don't get stripped... but that is probably what we want.
+#if !LOG_NDEBUG
+static const char *kReturnStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BR_OK",
+ "BR_TIMEOUT",
+ "BR_WAKEUP",
+ "BR_TRANSACTION",
+ "BR_REPLY",
+ "BR_ACQUIRE_RESULT",
+ "BR_DEAD_REPLY",
+ "BR_TRANSACTION_COMPLETE",
+ "BR_INCREFS",
+ "BR_ACQUIRE",
+ "BR_RELEASE",
+ "BR_DECREFS",
+ "BR_ATTEMPT_ACQUIRE",
+ "BR_EVENT_OCCURRED",
+ "BR_NOOP",
+ "BR_SPAWN_LOOPER",
+ "BR_FINISHED",
+ "BR_DEAD_BINDER",
+ "BR_CLEAR_DEATH_NOTIFICATION_DONE"
+#endif
+};
+
+static const char *kCommandStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BC_NOOP",
+ "BC_TRANSACTION",
+ "BC_REPLY",
+ "BC_ACQUIRE_RESULT",
+ "BC_FREE_BUFFER",
+ "BC_TRANSACTION_COMPLETE",
+ "BC_INCREFS",
+ "BC_ACQUIRE",
+ "BC_RELEASE",
+ "BC_DECREFS",
+ "BC_INCREFS_DONE",
+ "BC_ACQUIRE_DONE",
+ "BC_ATTEMPT_ACQUIRE",
+ "BC_RETRIEVE_ROOT_OBJECT",
+ "BC_SET_THREAD_ENTRY",
+ "BC_REGISTER_LOOPER",
+ "BC_ENTER_LOOPER",
+ "BC_EXIT_LOOPER",
+ "BC_SYNC",
+ "BC_STOP_PROCESS",
+ "BC_STOP_SELF",
+ "BC_REQUEST_DEATH_NOTIFICATION",
+ "BC_CLEAR_DEATH_NOTIFICATION",
+ "BC_DEAD_BINDER_DONE"
+#endif
+};
+
+static const char* getReturnString(size_t idx)
+{
+ if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
+ return kReturnStrings[idx];
+ else
+ return "unknown";
+}
+
+static const char* getCommandString(size_t idx)
+{
+ if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
+ return kCommandStrings[idx];
+ else
+ return "unknown";
+}
+
+static const void* printBinderTransactionData(TextOutput& out, const void* data)
+{
+ const binder_transaction_data* btd =
+ (const binder_transaction_data*)data;
+ out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+ << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
+ << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
+ << " bytes)" << endl
+ << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
+ << " bytes)" << endl;
+ return btd+1;
+}
+
+static const void* printReturnCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code == BR_ERROR) {
+ out << "BR_ERROR: " << (void*)(*cmd++) << endl;
+ return cmd;
+ } else if (code < 0 || code >= N) {
+ out << "Unknown reply: " << code << endl;
+ return cmd;
+ }
+
+ out << kReturnStrings[code];
+ switch (code) {
+ case BR_TRANSACTION:
+ case BR_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BR_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BR_INCREFS:
+ case BR_ACQUIRE:
+ case BR_RELEASE:
+ case BR_DECREFS: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BR_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c
+ << "), pri=" << p;
+ } break;
+
+ case BR_DEAD_BINDER:
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+
+static const void* printCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code < 0 || code >= N) {
+ out << "Unknown command: " << code << endl;
+ return cmd;
+ }
+
+ out << kCommandStrings[code];
+ switch (code) {
+ case BC_TRANSACTION:
+ case BC_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BC_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BC_FREE_BUFFER: {
+ const int32_t buf = *cmd++;
+ out << ": buffer=" << (void*)buf;
+ } break;
+
+ case BC_INCREFS:
+ case BC_ACQUIRE:
+ case BC_RELEASE:
+ case BC_DECREFS: {
+ const int32_t d = *cmd++;
+ out << ": descriptor=" << (void*)d;
+ } break;
+
+ case BC_INCREFS_DONE:
+ case BC_ACQUIRE_DONE: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BC_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t d = *cmd++;
+ out << ": decriptor=" << (void*)d << ", pri=" << p;
+ } break;
+
+ case BC_REQUEST_DEATH_NOTIFICATION:
+ case BC_CLEAR_DEATH_NOTIFICATION: {
+ const int32_t h = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": handle=" << h << " (death cookie " << (void*)c << ")";
+ } break;
+
+ case BC_DEAD_BINDER_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+#endif
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+static bool gShutdown = false;
+
+IPCThreadState* IPCThreadState::self()
+{
+ if (gHaveTLS) {
+restart:
+ const pthread_key_t k = gTLS;
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
+ if (st) return st;
+ return new IPCThreadState;
+ }
+
+ if (gShutdown) return NULL;
+
+ pthread_mutex_lock(&gTLSMutex);
+ if (!gHaveTLS) {
+ if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+ pthread_mutex_unlock(&gTLSMutex);
+ return NULL;
+ }
+ gHaveTLS = true;
+ }
+ pthread_mutex_unlock(&gTLSMutex);
+ goto restart;
+}
+
+void IPCThreadState::shutdown()
+{
+ gShutdown = true;
+
+ if (gHaveTLS) {
+ // XXX Need to wait for all thread pool threads to exit!
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
+ if (st) {
+ delete st;
+ pthread_setspecific(gTLS, NULL);
+ }
+ gHaveTLS = false;
+ }
+}
+
+sp<ProcessState> IPCThreadState::process()
+{
+ return mProcess;
+}
+
+status_t IPCThreadState::clearLastError()
+{
+ const status_t err = mLastError;
+ mLastError = NO_ERROR;
+ return err;
+}
+
+int IPCThreadState::getCallingPid()
+{
+ return mCallingPid;
+}
+
+int IPCThreadState::getCallingUid()
+{
+ return mCallingUid;
+}
+
+int64_t IPCThreadState::clearCallingIdentity()
+{
+ int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+ clearCaller();
+ return token;
+}
+
+void IPCThreadState::restoreCallingIdentity(int64_t token)
+{
+ mCallingUid = (int)(token>>32);
+ mCallingPid = (int)token;
+}
+
+void IPCThreadState::clearCaller()
+{
+ mCallingPid = getpid();
+ mCallingUid = getuid();
+}
+
+void IPCThreadState::flushCommands()
+{
+ if (mProcess->mDriverFD <= 0)
+ return;
+ talkWithDriver(false);
+}
+
+void IPCThreadState::joinThreadPool(bool isMain)
+{
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
+
+ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+
+ status_t result;
+ do {
+ int32_t cmd;
+
+ // When we've cleared the incoming command queue, process any pending derefs
+ if (mIn.dataPosition() >= mIn.dataSize()) {
+ size_t numPending = mPendingWeakDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+ refs->decWeak(mProcess.get());
+ }
+ mPendingWeakDerefs.clear();
+ }
+
+ numPending = mPendingStrongDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ BBinder* obj = mPendingStrongDerefs[i];
+ obj->decStrong(mProcess.get());
+ }
+ mPendingStrongDerefs.clear();
+ }
+ }
+
+ // now get the next command to be processed, waiting if necessary
+ result = talkWithDriver();
+ if (result >= NO_ERROR) {
+ size_t IN = mIn.dataAvail();
+ if (IN < sizeof(int32_t)) continue;
+ cmd = mIn.readInt32();
+ IF_LOG_COMMANDS() {
+ alog << "Processing top-level Command: "
+ << getReturnString(cmd) << endl;
+ }
+ result = executeCommand(cmd);
+ }
+
+ // Let this thread exit the thread pool if it is no longer
+ // needed and it is not the main process thread.
+ if(result == TIMED_OUT && !isMain) {
+ break;
+ }
+ } while (result != -ECONNREFUSED && result != -EBADF);
+
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
+ (void*)pthread_self(), getpid(), (void*)result);
+
+ mOut.writeInt32(BC_EXIT_LOOPER);
+ talkWithDriver(false);
+}
+
+void IPCThreadState::stopProcess(bool immediate)
+{
+ //LOGI("**** STOPPING PROCESS");
+ flushCommands();
+ int fd = mProcess->mDriverFD;
+ mProcess->mDriverFD = -1;
+ close(fd);
+ //kill(getpid(), SIGKILL);
+}
+
+status_t IPCThreadState::transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags)
+{
+ status_t err = data.errorCheck();
+
+ flags |= TF_ACCEPT_FDS;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
+ << handle << " / code " << TypeCode(code) << ": "
+ << indent << data << dedent << endl;
+ }
+
+ if (err == NO_ERROR) {
+ LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+ (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+ err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
+ }
+
+ if (err != NO_ERROR) {
+ if (reply) reply->setError(err);
+ return (mLastError = err);
+ }
+
+ if ((flags & TF_ONE_WAY) == 0) {
+ if (reply) {
+ err = waitForResponse(reply);
+ } else {
+ Parcel fakeReply;
+ err = waitForResponse(&fakeReply);
+ }
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
+ << handle << ": ";
+ if (reply) alog << indent << *reply << dedent << endl;
+ else alog << "(none requested)" << endl;
+ }
+ } else {
+ err = waitForResponse(NULL, NULL);
+ }
+
+ return err;
+}
+
+void IPCThreadState::incStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_ACQUIRE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_RELEASE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::incWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_INCREFS);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_DECREFS);
+ mOut.writeInt32(handle);
+}
+
+status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
+{
+ mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
+ mOut.writeInt32(0); // xxx was thread priority
+ mOut.writeInt32(handle);
+ status_t result = UNKNOWN_ERROR;
+
+ waitForResponse(NULL, &result);
+
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+ handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
+#endif
+
+ return result;
+}
+
+void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
+{
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+#endif
+ self()->mProcess->expungeHandle(handle, binder);
+}
+
+status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+IPCThreadState::IPCThreadState()
+ : mProcess(ProcessState::self())
+{
+ pthread_setspecific(gTLS, this);
+ clearCaller();
+ mIn.setDataCapacity(256);
+ mOut.setDataCapacity(256);
+}
+
+IPCThreadState::~IPCThreadState()
+{
+}
+
+status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
+{
+ status_t err;
+ status_t statusBuffer;
+ err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
+ if (err < NO_ERROR) return err;
+
+ return waitForResponse(NULL, NULL);
+}
+
+status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
+{
+ int32_t cmd;
+ int32_t err;
+
+ while (1) {
+ if ((err=talkWithDriver()) < NO_ERROR) break;
+ err = mIn.errorCheck();
+ if (err < NO_ERROR) break;
+ if (mIn.dataAvail() == 0) continue;
+
+ cmd = mIn.readInt32();
+
+ IF_LOG_COMMANDS() {
+ alog << "Processing waitForResponse Command: "
+ << getReturnString(cmd) << endl;
+ }
+
+ switch (cmd) {
+ case BR_TRANSACTION_COMPLETE:
+ if (!reply && !acquireResult) goto finish;
+ break;
+
+ case BR_DEAD_REPLY:
+ err = DEAD_OBJECT;
+ goto finish;
+
+ case BR_FAILED_REPLY:
+ err = FAILED_TRANSACTION;
+ goto finish;
+
+ case BR_ACQUIRE_RESULT:
+ {
+ LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
+ const int32_t result = mIn.readInt32();
+ if (!acquireResult) continue;
+ *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
+ }
+ goto finish;
+
+ case BR_REPLY:
+ {
+ binder_transaction_data tr;
+ err = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
+ if (err != NO_ERROR) goto finish;
+
+ if (reply) {
+ if ((tr.flags & TF_STATUS_CODE) == 0) {
+ reply->ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t),
+ freeBuffer, this);
+ } else {
+ err = *static_cast<const status_t*>(tr.data.ptr.buffer);
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ }
+ } else {
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ continue;
+ }
+ }
+ goto finish;
+
+ default:
+ err = executeCommand(cmd);
+ if (err != NO_ERROR) goto finish;
+ break;
+ }
+ }
+
+finish:
+ if (err != NO_ERROR) {
+ if (acquireResult) *acquireResult = err;
+ if (reply) reply->setError(err);
+ mLastError = err;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::talkWithDriver(bool doReceive)
+{
+ LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
+
+ binder_write_read bwr;
+
+ // Is the read buffer empty?
+ const bool needRead = mIn.dataPosition() >= mIn.dataSize();
+
+ // We don't want to write anything if we are still reading
+ // from data left in the input buffer and the caller
+ // has requested to read the next data.
+ const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
+
+ bwr.write_size = outAvail;
+ bwr.write_buffer = (long unsigned int)mOut.data();
+
+ // This is what we'll read.
+ if (doReceive && needRead) {
+ bwr.read_size = mIn.dataCapacity();
+ bwr.read_buffer = (long unsigned int)mIn.data();
+ } else {
+ bwr.read_size = 0;
+ }
+
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ if (outAvail != 0) {
+ alog << "Sending commands to driver: " << indent;
+ const void* cmds = (const void*)bwr.write_buffer;
+ const void* end = ((const uint8_t*)cmds)+bwr.write_size;
+ alog << HexDump(cmds, bwr.write_size) << endl;
+ while (cmds < end) cmds = printCommand(alog, cmds);
+ alog << dedent;
+ }
+ alog << "Size of receive buffer: " << bwr.read_size
+ << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+ }
+
+ // Return immediately if there is nothing to do.
+ if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
+
+ bwr.write_consumed = 0;
+ bwr.read_consumed = 0;
+ status_t err;
+ do {
+ IF_LOG_COMMANDS() {
+ alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+ }
+#if defined(HAVE_ANDROID_OS)
+ if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
+ err = NO_ERROR;
+ else
+ err = -errno;
+#else
+ err = INVALID_OPERATION;
+#endif
+ IF_LOG_COMMANDS() {
+ alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+ }
+ } while (err == -EINTR);
+
+ IF_LOG_COMMANDS() {
+ alog << "Our err: " << (void*)err << ", write consumed: "
+ << bwr.write_consumed << " (of " << mOut.dataSize()
+ << "), read consumed: " << bwr.read_consumed << endl;
+ }
+
+ if (err >= NO_ERROR) {
+ if (bwr.write_consumed > 0) {
+ if (bwr.write_consumed < (ssize_t)mOut.dataSize())
+ mOut.remove(0, bwr.write_consumed);
+ else
+ mOut.setDataSize(0);
+ }
+ if (bwr.read_consumed > 0) {
+ mIn.setDataSize(bwr.read_consumed);
+ mIn.setDataPosition(0);
+ }
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ alog << "Remaining data size: " << mOut.dataSize() << endl;
+ alog << "Received commands from driver: " << indent;
+ const void* cmds = mIn.data();
+ const void* end = mIn.data() + mIn.dataSize();
+ alog << HexDump(cmds, mIn.dataSize()) << endl;
+ while (cmds < end) cmds = printReturnCommand(alog, cmds);
+ alog << dedent;
+ }
+ return NO_ERROR;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
+ int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
+{
+ binder_transaction_data tr;
+
+ tr.target.handle = handle;
+ tr.code = code;
+ tr.flags = binderFlags;
+
+ const status_t err = data.errorCheck();
+ if (err == NO_ERROR) {
+ tr.data_size = data.ipcDataSize();
+ tr.data.ptr.buffer = data.ipcData();
+ tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
+ tr.data.ptr.offsets = data.ipcObjects();
+ } else if (statusBuffer) {
+ tr.flags |= TF_STATUS_CODE;
+ *statusBuffer = err;
+ tr.data_size = sizeof(status_t);
+ tr.data.ptr.buffer = statusBuffer;
+ tr.offsets_size = 0;
+ tr.data.ptr.offsets = NULL;
+ } else {
+ return (mLastError = err);
+ }
+
+ mOut.writeInt32(cmd);
+ mOut.write(&tr, sizeof(tr));
+
+ return NO_ERROR;
+}
+
+sp<BBinder> the_context_object;
+
+void setTheContextObject(sp<BBinder> obj)
+{
+ the_context_object = obj;
+}
+
+status_t IPCThreadState::executeCommand(int32_t cmd)
+{
+ BBinder* obj;
+ RefBase::weakref_type* refs;
+ status_t result = NO_ERROR;
+
+ switch (cmd) {
+ case BR_ERROR:
+ result = mIn.readInt32();
+ break;
+
+ case BR_OK:
+ break;
+
+ case BR_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ obj->incStrong(mProcess.get());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
+ obj->printRefs();
+ }
+ mOut.writeInt32(BC_ACQUIRE_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_RELEASE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_RELEASE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
+ obj->printRefs();
+ }
+ mPendingStrongDerefs.push(obj);
+ break;
+
+ case BR_INCREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ refs->incWeak(mProcess.get());
+ mOut.writeInt32(BC_INCREFS_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_DECREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ // NOTE: This assertion is not valid, because the object may no
+ // longer exist (thus the (BBinder*)cast above resulting in a different
+ // memory address).
+ //LOG_ASSERT(refs->refBase() == obj,
+ // "BR_DECREFS: object %p does not match cookie %p (expected %p)",
+ // refs, obj, refs->refBase());
+ mPendingWeakDerefs.push(refs);
+ break;
+
+ case BR_ATTEMPT_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+
+ {
+ const bool success = refs->attemptIncStrong(mProcess.get());
+ LOG_ASSERT(success && refs->refBase() == obj,
+ "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+
+ mOut.writeInt32(BC_ACQUIRE_RESULT);
+ mOut.writeInt32((int32_t)success);
+ }
+ break;
+
+ case BR_TRANSACTION:
+ {
+ binder_transaction_data tr;
+ result = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(result == NO_ERROR,
+ "Not enough command data for brTRANSACTION");
+ if (result != NO_ERROR) break;
+
+ Parcel buffer;
+ buffer.ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), freeBuffer, this);
+
+ const pid_t origPid = mCallingPid;
+ const uid_t origUid = mCallingUid;
+
+ mCallingPid = tr.sender_pid;
+ mCallingUid = tr.sender_euid;
+
+ //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+
+ Parcel reply;
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_TRANSACTION thr " << (void*)pthread_self()
+ << " / obj " << tr.target.ptr << " / code "
+ << TypeCode(tr.code) << ": " << indent << buffer
+ << dedent << endl
+ << "Data addr = "
+ << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+ << ", offsets addr="
+ << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+ }
+ if (tr.target.ptr) {
+ sp<BBinder> b((BBinder*)tr.cookie);
+ const status_t error = b->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+
+ } else {
+ const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+ }
+
+ //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
+ // mCallingPid, origPid, origUid);
+
+ if ((tr.flags & TF_ONE_WAY) == 0) {
+ LOG_ONEWAY("Sending reply to %d!", mCallingPid);
+ sendReply(reply, 0);
+ } else {
+ LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
+ }
+
+ mCallingPid = origPid;
+ mCallingUid = origUid;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
+ << tr.target.ptr << ": " << indent << reply << dedent << endl;
+ }
+
+ }
+ break;
+
+ case BR_DEAD_BINDER:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->sendObituary();
+ mOut.writeInt32(BC_DEAD_BINDER_DONE);
+ mOut.writeInt32((int32_t)proxy);
+ } break;
+
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->getWeakRefs()->decWeak(proxy);
+ } break;
+
+ case BR_FINISHED:
+ result = TIMED_OUT;
+ break;
+
+ case BR_NOOP:
+ break;
+
+ case BR_SPAWN_LOOPER:
+ mProcess->spawnPooledThread(false);
+ break;
+
+ default:
+ printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+ result = UNKNOWN_ERROR;
+ break;
+ }
+
+ if (result != NO_ERROR) {
+ mLastError = result;
+ }
+
+ return result;
+}
+
+void IPCThreadState::threadDestructor(void *st)
+{
+ IPCThreadState* const self = static_cast<IPCThreadState*>(st);
+ if (self) {
+ self->flushCommands();
+#if defined(HAVE_ANDROID_OS)
+ ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
+#endif
+ delete self;
+ }
+}
+
+
+void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie)
+{
+ //LOGI("Freeing parcel %p", &parcel);
+ IF_LOG_COMMANDS() {
+ alog << "Writing BC_FREE_BUFFER for " << data << endl;
+ }
+ LOG_ASSERT(data != NULL, "Called with NULL data");
+ if (parcel != NULL) parcel->closeFileDescriptors();
+ IPCThreadState* state = self();
+ state->mOut.writeInt32(BC_FREE_BUFFER);
+ state->mOut.writeInt32((int32_t)data);
+}
+
+}; // namespace android
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
new file mode 100644
index 0000000..bff4c9b
--- /dev/null
+++ b/libs/binder/IPermissionController.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PermissionController"
+
+#include <binder/IPermissionController.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpPermissionController : public BpInterface<IPermissionController>
+{
+public:
+ BpPermissionController(const sp<IBinder>& impl)
+ : BpInterface<IPermissionController>(impl)
+ {
+ }
+
+ virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(permission);
+ data.writeInt32(pid);
+ data.writeInt32(uid);
+ remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readInt32() != 0) return 0;
+ return reply.readInt32() != 0;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+
+// ----------------------------------------------------------------------
+
+status_t BnPermissionController::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("PermissionController received: "); data.print();
+ switch(code) {
+ case CHECK_PERMISSION_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 permission = data.readString16();
+ int32_t pid = data.readInt32();
+ int32_t uid = data.readInt32();
+ bool res = checkPermission(permission, pid, uid);
+ // write exception
+ reply->writeInt32(0);
+ reply->writeInt32(res ? 1 : 0);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
new file mode 100644
index 0000000..0cf4158
--- /dev/null
+++ b/libs/binder/IServiceManager.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ServiceManager"
+
+#include <binder/IServiceManager.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+
+#include <private/binder/Static.h>
+
+#include <unistd.h>
+
+namespace android {
+
+sp<IServiceManager> defaultServiceManager()
+{
+ if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+
+ {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ if (gDefaultServiceManager == NULL) {
+ gDefaultServiceManager = interface_cast<IServiceManager>(
+ ProcessState::self()->getContextObject(NULL));
+ }
+ }
+
+ return gDefaultServiceManager;
+}
+
+bool checkCallingPermission(const String16& permission)
+{
+ return checkCallingPermission(permission, NULL, NULL);
+}
+
+static String16 _permission("permission");
+
+
+bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ if (outPid) *outPid = pid;
+ if (outUid) *outUid = uid;
+ return checkPermission(permission, pid, uid);
+}
+
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
+{
+ sp<IPermissionController> pc;
+ gDefaultServiceManagerLock.lock();
+ pc = gPermissionController;
+ gDefaultServiceManagerLock.unlock();
+
+ int64_t startTime = 0;
+
+ while (true) {
+ if (pc != NULL) {
+ bool res = pc->checkPermission(permission, pid, uid);
+ if (res) {
+ if (startTime != 0) {
+ LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
+ (int)((uptimeMillis()-startTime)/1000),
+ String8(permission).string(), uid, pid);
+ }
+ return res;
+ }
+
+ // Is this a permission failure, or did the controller go away?
+ if (pc->asBinder()->isBinderAlive()) {
+ LOGW("Permission failure: %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ return false;
+ }
+
+ // Object is dead!
+ gDefaultServiceManagerLock.lock();
+ if (gPermissionController == pc) {
+ gPermissionController = NULL;
+ }
+ gDefaultServiceManagerLock.unlock();
+ }
+
+ // Need to retrieve the permission controller.
+ sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
+ if (binder == NULL) {
+ // Wait for the permission controller to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ LOGI("Waiting to check permission %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ }
+ sleep(1);
+ } else {
+ pc = interface_cast<IPermissionController>(binder);
+ // Install the new permission controller, and try again.
+ gDefaultServiceManagerLock.lock();
+ gPermissionController = pc;
+ gDefaultServiceManagerLock.unlock();
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+
+class BpServiceManager : public BpInterface<IServiceManager>
+{
+public:
+ BpServiceManager(const sp<IBinder>& impl)
+ : BpInterface<IServiceManager>(impl)
+ {
+ }
+
+ virtual sp<IBinder> getService(const String16& name) const
+ {
+ unsigned n;
+ for (n = 0; n < 5; n++){
+ sp<IBinder> svc = checkService(name);
+ if (svc != NULL) return svc;
+ LOGI("Waiting for sevice %s...\n", String8(name).string());
+ sleep(1);
+ }
+ return NULL;
+ }
+
+ virtual sp<IBinder> checkService( const String16& name) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
+ return reply.readStrongBinder();
+ }
+
+ virtual status_t addService(const String16& name, const sp<IBinder>& service)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeStrongBinder(service);
+ status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
+ return err == NO_ERROR ? reply.readInt32() : err;
+ }
+
+ virtual Vector<String16> listServices()
+ {
+ Vector<String16> res;
+ int n = 0;
+
+ for (;;) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeInt32(n++);
+ status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
+ if (err != NO_ERROR)
+ break;
+ res.add(reply.readString16());
+ }
+ return res;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+
+// ----------------------------------------------------------------------
+
+status_t BnServiceManager::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("ServiceManager received: "); data.print();
+ switch(code) {
+ case GET_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case CHECK_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case ADD_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = data.readStrongBinder();
+ status_t err = addService(which, b);
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ case LIST_SERVICES_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ Vector<String16> list = listServices();
+ const size_t N = list.size();
+ reply->writeInt32(N);
+ for (size_t i=0; i<N; i++) {
+ reply->writeString16(list[i]);
+ }
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
new file mode 100644
index 0000000..033066b
--- /dev/null
+++ b/libs/binder/MemoryBase.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/MemoryBase.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : mSize(size), mOffset(offset), mHeap(heap)
+{
+}
+
+sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+MemoryBase::~MemoryBase()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
new file mode 100644
index 0000000..d5ffe7f
--- /dev/null
+++ b/libs/binder/MemoryDealer.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "MemoryDealer"
+
+#include <binder/MemoryDealer.h>
+
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <binder/MemoryBase.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+HeapInterface::HeapInterface() { }
+HeapInterface::~HeapInterface() { }
+
+// ----------------------------------------------------------------------------
+
+AllocatorInterface::AllocatorInterface() { }
+AllocatorInterface::~AllocatorInterface() { }
+
+// ----------------------------------------------------------------------------
+
+class SimpleMemory : public MemoryBase {
+public:
+ SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~SimpleMemory();
+};
+
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::Allocation::Allocation(
+ const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
+ const sp<IMemory>& memory)
+ : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
+{
+}
+
+MemoryDealer::Allocation::~Allocation()
+{
+ if (mSize) {
+ /* NOTE: it's VERY important to not free allocations of size 0 because
+ * they're special as they don't have any record in the allocator
+ * and could alias some real allocation (their offset is zero). */
+ mDealer->deallocate(mOffset);
+ }
+}
+
+sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ return mMemory->getMemory(offset, size);
+}
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
+ : mHeap(new SharedHeap(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size))
+{
+}
+
+MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
+ : mHeap(heap),
+ mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
+{
+}
+
+MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator)
+ : mHeap(heap), mAllocator(allocator)
+{
+}
+
+MemoryDealer::~MemoryDealer()
+{
+}
+
+sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
+{
+ sp<IMemory> memory;
+ const ssize_t offset = allocator()->allocate(size, flags);
+ if (offset >= 0) {
+ sp<IMemory> new_memory = heap()->mapMemory(offset, size);
+ if (new_memory != 0) {
+ memory = new Allocation(this, offset, size, new_memory);
+ } else {
+ LOGE("couldn't map [%8lx, %u]", offset, size);
+ if (size) {
+ /* NOTE: it's VERY important to not free allocations of size 0
+ * because they're special as they don't have any record in the
+ * allocator and could alias some real allocation
+ * (their offset is zero). */
+ allocator()->deallocate(offset);
+ }
+ }
+ }
+ return memory;
+}
+
+void MemoryDealer::deallocate(size_t offset)
+{
+ allocator()->deallocate(offset);
+}
+
+void MemoryDealer::dump(const char* what, uint32_t flags) const
+{
+ allocator()->dump(what, flags);
+}
+
+const sp<HeapInterface>& MemoryDealer::heap() const {
+ return mHeap;
+}
+
+const sp<AllocatorInterface>& MemoryDealer::allocator() const {
+ return mAllocator;
+}
+
+// ----------------------------------------------------------------------------
+
+// align all the memory blocks on a cache-line boundary
+const int SimpleBestFitAllocator::kMemoryAlign = 32;
+
+SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
+{
+ size_t pagesize = getpagesize();
+ mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
+
+ chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
+ mList.insertHead(node);
+}
+
+SimpleBestFitAllocator::~SimpleBestFitAllocator()
+{
+ while(!mList.isEmpty()) {
+ delete mList.remove(mList.head());
+ }
+}
+
+size_t SimpleBestFitAllocator::size() const
+{
+ return mHeapSize;
+}
+
+size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ ssize_t offset = alloc(size, flags);
+ return offset;
+}
+
+status_t SimpleBestFitAllocator::deallocate(size_t offset)
+{
+ Mutex::Autolock _l(mLock);
+ chunk_t const * const freed = dealloc(offset);
+ if (freed) {
+ return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
+{
+ if (size == 0) {
+ return 0;
+ }
+ size = (size + kMemoryAlign-1) / kMemoryAlign;
+ chunk_t* free_chunk = 0;
+ chunk_t* cur = mList.head();
+
+ size_t pagesize = getpagesize();
+ while (cur) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
+
+ // best fit
+ if (cur->free && (cur->size >= (size+extra))) {
+ if ((!free_chunk) || (cur->size < free_chunk->size)) {
+ free_chunk = cur;
+ }
+ if (cur->size == size) {
+ break;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (free_chunk) {
+ const size_t free_size = free_chunk->size;
+ free_chunk->free = 0;
+ free_chunk->size = size;
+ if (free_size > size) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
+ if (extra) {
+ chunk_t* split = new chunk_t(free_chunk->start, extra);
+ free_chunk->start += extra;
+ mList.insertBefore(free_chunk, split);
+ }
+
+ LOGE_IF((flags&PAGE_ALIGNED) &&
+ ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
+ "PAGE_ALIGNED requested, but page is not aligned!!!");
+
+ const ssize_t tail_free = free_size - (size+extra);
+ if (tail_free > 0) {
+ chunk_t* split = new chunk_t(
+ free_chunk->start + free_chunk->size, tail_free);
+ mList.insertAfter(free_chunk, split);
+ }
+ }
+ return (free_chunk->start)*kMemoryAlign;
+ }
+ return NO_MEMORY;
+}
+
+SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
+{
+ start = start / kMemoryAlign;
+ chunk_t* cur = mList.head();
+ while (cur) {
+ if (cur->start == start) {
+ LOG_FATAL_IF(cur->free,
+ "block at offset 0x%08lX of size 0x%08lX already freed",
+ cur->start*kMemoryAlign, cur->size*kMemoryAlign);
+
+ // merge freed blocks together
+ chunk_t* freed = cur;
+ cur->free = 1;
+ do {
+ chunk_t* const p = cur->prev;
+ chunk_t* const n = cur->next;
+ if (p && (p->free || !cur->size)) {
+ freed = p;
+ p->size += cur->size;
+ mList.remove(cur);
+ delete cur;
+ }
+ cur = n;
+ } while (cur && cur->free);
+
+ #ifndef NDEBUG
+ if (!freed->free) {
+ dump_l("dealloc (!freed->free)");
+ }
+ #endif
+ LOG_FATAL_IF(!freed->free,
+ "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+ freed->start * kMemoryAlign, freed->size * kMemoryAlign);
+
+ return freed;
+ }
+ cur = cur->next;
+ }
+ return 0;
+}
+
+void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
+{
+ String8 result;
+ dump_l(result, what, flags);
+ LOGD("%s", result.string());
+}
+
+void SimpleBestFitAllocator::dump(String8& result,
+ const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(result, what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(String8& result,
+ const char* what, uint32_t flags) const
+{
+ size_t size = 0;
+ int32_t i = 0;
+ chunk_t const* cur = mList.head();
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
+ what, this, (unsigned int)mHeapSize);
+
+ result.append(buffer);
+
+ while (cur) {
+ const char* errs[] = {"", "| link bogus NP",
+ "| link bogus PN", "| link bogus NP+PN" };
+ int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
+ int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
+
+ snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
+ i, int(cur), int(cur->start*kMemoryAlign),
+ int(cur->size*kMemoryAlign),
+ int(cur->free) ? "F" : "A",
+ errs[np|pn]);
+
+ result.append(buffer);
+
+ if (!cur->free)
+ size += cur->size*kMemoryAlign;
+
+ i++;
+ cur = cur->next;
+ }
+ snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
+ result.append(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedHeap::SharedHeap()
+ : HeapInterface(), MemoryHeapBase()
+{
+}
+
+SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
+ : MemoryHeapBase(size, flags, name)
+{
+}
+
+SharedHeap::~SharedHeap()
+{
+}
+
+sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
+{
+ return new SimpleMemory(this, offset, size);
+}
+
+
+SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : MemoryBase(heap, offset, size)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+}
+
+SimpleMemory::~SimpleMemory()
+{
+ size_t freedOffset = getOffset();
+ size_t freedSize = getSize();
+
+ // keep the size to unmap in excess
+ size_t pagesize = getpagesize();
+ size_t start = freedOffset;
+ size_t end = start + freedSize;
+ start &= ~(pagesize-1);
+ end = (end + pagesize-1) & ~(pagesize-1);
+
+ // give back to the kernel the pages we don't need
+ size_t free_start = freedOffset;
+ size_t free_end = free_start + freedSize;
+ if (start < free_start)
+ start = free_start;
+ if (end > free_end)
+ end = free_end;
+ start = (start + pagesize-1) & ~(pagesize-1);
+ end &= ~(pagesize-1);
+
+ if (start < end) {
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+ size_t size = end-start;
+
+#ifndef NDEBUG
+ memset(start_ptr, 0xdf, size);
+#endif
+
+ // MADV_REMOVE is not defined on Dapper based Goobuntu
+#ifdef MADV_REMOVE
+ if (size) {
+ int err = madvise(start_ptr, size, MADV_REMOVE);
+ LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+ start_ptr, size, err<0 ? strerror(errno) : "Ok");
+ }
+#endif
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
new file mode 100644
index 0000000..ac38f51
--- /dev/null
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapBase"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#include <binder/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapBase::MemoryHeapBase()
+ : mFD(-1), mSize(0), mBase(MAP_FAILED),
+ mDevice(NULL), mNeedUnmap(false)
+{
+}
+
+MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
+ LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
+ if (fd >= 0) {
+ if (mapfd(fd, size) == NO_ERROR) {
+ if (flags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
+ }
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
+ if (fd >= 0) {
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ if (mapfd(fd, size) == NO_ERROR) {
+ mDevice = device;
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
+ : 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);
+}
+
+status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+{
+ if (mFD != -1) {
+ return INVALID_OPERATION;
+ }
+ mFD = fd;
+ mBase = base;
+ mSize = size;
+ mFlags = flags;
+ mDevice = device;
+ return NO_ERROR;
+}
+
+status_t MemoryHeapBase::mapfd(int fd, size_t size)
+{
+ if (size == 0) {
+ // try to figure out the size automatically
+#if HAVE_ANDROID_OS
+ // first try the PMEM ioctl
+ pmem_region reg;
+ int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®);
+ if (err == 0)
+ size = reg.len;
+#endif
+ if (size == 0) { // try fstat
+ struct stat sb;
+ if (fstat(fd, &sb) == 0)
+ size = sb.st_size;
+ }
+ // if it didn't work, let mmap() fail.
+ }
+
+ if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+ void* base = (uint8_t*)mmap(0, size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (base == MAP_FAILED) {
+ LOGE("mmap(fd=%d, size=%u) failed (%s)",
+ fd, uint32_t(size), strerror(errno));
+ close(fd);
+ return -errno;
+ }
+ //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+ mBase = base;
+ mNeedUnmap = true;
+ } else {
+ mBase = 0; // not MAP_FAILED
+ mNeedUnmap = false;
+ }
+ mFD = fd;
+ mSize = size;
+ return NO_ERROR;
+}
+
+MemoryHeapBase::~MemoryHeapBase()
+{
+ dispose();
+}
+
+void MemoryHeapBase::dispose()
+{
+ int fd = android_atomic_or(-1, &mFD);
+ if (fd >= 0) {
+ if (mNeedUnmap) {
+ //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+ munmap(mBase, mSize);
+ }
+ mBase = 0;
+ mSize = 0;
+ close(fd);
+ }
+}
+
+int MemoryHeapBase::getHeapID() const {
+ return mFD;
+}
+
+void* MemoryHeapBase::getBase() const {
+ return mBase;
+}
+
+size_t MemoryHeapBase::getSize() const {
+ return mSize;
+}
+
+uint32_t MemoryHeapBase::getFlags() const {
+ return mFlags;
+}
+
+const char* MemoryHeapBase::getDevice() const {
+ return mDevice;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
new file mode 100644
index 0000000..3806a42
--- /dev/null
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MemoryHeapPmem"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+ : BnMemory(), mClientHeap(heap)
+{
+}
+
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+ if (mClientHeap != NULL) {
+ mClientHeap->remove(this);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
+public:
+ SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
+ virtual ~SubRegionMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+private:
+ friend class MemoryHeapPmem;
+ void revoke();
+ size_t mSize;
+ ssize_t mOffset;
+};
+
+SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
+ ssize_t offset, size_t size)
+ : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+
+#if HAVE_ANDROID_OS
+ if (size > 0) {
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = heap->heapID();
+ struct pmem_region sub = { offset, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+}
+#endif
+}
+
+sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return getHeap();
+}
+
+SubRegionMemory::~SubRegionMemory()
+{
+ revoke();
+}
+
+
+void SubRegionMemory::revoke()
+{
+ // NOTE: revoke() doesn't need to be protected by a lock because it
+ // can only be called from MemoryHeapPmem::revoke(), which means
+ // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
+ // which means MemoryHeapPmem::revoke() wouldn't have been able to
+ // promote() it.
+
+#if HAVE_ANDROID_OS
+ if (mSize != 0) {
+ const sp<MemoryHeapPmem>& heap(getHeap());
+ int our_fd = heap->heapID();
+ struct pmem_region sub;
+ sub.offset = mOffset;
+ sub.len = mSize;
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ mSize = 0;
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags)
+ : HeapInterface(), MemoryHeapBase()
+{
+ char const * const device = pmemHeap->getDevice();
+#if HAVE_ANDROID_OS
+ if (device) {
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
+ if (fd >= 0) {
+ int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
+ if (err < 0) {
+ LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
+ strerror(errno), fd, pmemHeap->heapID());
+ close(fd);
+ } else {
+ // everything went well...
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(fd,
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+ }
+ }
+ }
+#else
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(
+ dup(pmemHeap->heapID()),
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+#endif
+}
+
+MemoryHeapPmem::~MemoryHeapPmem()
+{
+}
+
+sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
+{
+ sp<MemoryPmem> memory = createMemory(offset, size);
+ if (memory != 0) {
+ Mutex::Autolock _l(mLock);
+ mAllocations.add(memory);
+ }
+ return memory;
+}
+
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+ size_t offset, size_t size)
+{
+ sp<SubRegionMemory> memory;
+ if (heapID() > 0)
+ memory = new SubRegionMemory(this, offset, size);
+ return memory;
+}
+
+status_t MemoryHeapPmem::slap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+status_t MemoryHeapPmem::unslap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+void MemoryHeapPmem::revoke()
+{
+ SortedVector< wp<MemoryPmem> > allocations;
+
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ allocations = mAllocations;
+ }
+
+ ssize_t count = allocations.size();
+ for (ssize_t i=0 ; i<count ; i++) {
+ sp<MemoryPmem> memory(allocations[i].promote());
+ if (memory != 0)
+ memory->revoke();
+ }
+}
+
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+ Mutex::Autolock _l(mLock);
+ mAllocations.remove(memory);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
new file mode 100644
index 0000000..e397bce
--- /dev/null
+++ b/libs/binder/Parcel.cpp
@@ -0,0 +1,1336 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Parcel"
+//#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <utils/Debug.h>
+#include <binder/ProcessState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/TextOutput.h>
+#include <utils/misc.h>
+
+#include <private/binder/binder_module.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define LOG_REFS(...)
+//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
+
+// ---------------------------------------------------------------------------
+
+#define PAD_SIZE(s) (((s)+3)&~3)
+
+// XXX This can be made public if we want to provide
+// support for typed data.
+struct small_flat_data
+{
+ uint32_t type;
+ uint32_t data;
+};
+
+namespace android {
+
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->incStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
+ b->incStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->incWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ // intentionally blank -- nothing to do to acquire this, but we do
+ // recognize it as a legitimate object type.
+ return;
+ }
+ }
+
+ LOGD("Invalid object type 0x%08lx", obj.type);
+}
+
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->decStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
+ b->decStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->decWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ if (obj.cookie != (void*)0) close(obj.handle);
+ return;
+ }
+ }
+
+ LOGE("Invalid object type 0x%08lx", obj.type);
+}
+
+inline static status_t finish_flatten_binder(
+ const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
+{
+ return out->writeObject(flat, false);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ IBinder *local = binder->localBinder();
+ if (!local) {
+ BpBinder *proxy = binder->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = local->getWeakRefs();
+ obj.cookie = local;
+ }
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ }
+
+ return finish_flatten_binder(binder, obj, out);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ sp<IBinder> real = binder.promote();
+ if (real != NULL) {
+ IBinder *local = real->localBinder();
+ if (!local) {
+ BpBinder *proxy = real->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_WEAK_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_WEAK_BINDER;
+ obj.binder = binder.get_refs();
+ obj.cookie = binder.unsafe_get();
+ }
+ return finish_flatten_binder(real, obj, out);
+ }
+
+ // XXX How to deal? In order to flatten the given binder,
+ // we need to probe it for information, which requires a primary
+ // reference... but we don't have one.
+ //
+ // The OpenBinder implementation uses a dynamic_cast<> here,
+ // but we can't do that with the different reference counting
+ // implementation we are using.
+ LOGE("Unable to unflatten Binder weak reference!");
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+ }
+}
+
+inline static status_t finish_unflatten_binder(
+ BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
+{
+ return NO_ERROR;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, sp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ *out = proc->getStrongProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, wp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_WEAK_BINDER:
+ if (flat->binder != NULL) {
+ out->set_object_and_refs(
+ static_cast<IBinder*>(flat->cookie),
+ static_cast<RefBase::weakref_type*>(flat->binder));
+ } else {
+ *out = NULL;
+ }
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ case BINDER_TYPE_WEAK_HANDLE:
+ *out = proc->getWeakProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+// ---------------------------------------------------------------------------
+
+Parcel::Parcel()
+{
+ initState();
+}
+
+Parcel::~Parcel()
+{
+ freeDataNoInit();
+}
+
+const uint8_t* Parcel::data() const
+{
+ return mData;
+}
+
+size_t Parcel::dataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+size_t Parcel::dataAvail() const
+{
+ // TODO: decide what to do about the possibility that this can
+ // report an available-data size that exceeds a Java int's max
+ // positive value, causing havoc. Fortunately this will only
+ // happen if someone constructs a Parcel containing more than two
+ // gigabytes of data, which on typical phone hardware is simply
+ // not possible.
+ return dataSize() - dataPosition();
+}
+
+size_t Parcel::dataPosition() const
+{
+ return mDataPos;
+}
+
+size_t Parcel::dataCapacity() const
+{
+ return mDataCapacity;
+}
+
+status_t Parcel::setDataSize(size_t size)
+{
+ status_t err;
+ err = continueWrite(size);
+ if (err == NO_ERROR) {
+ mDataSize = size;
+ LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
+ }
+ return err;
+}
+
+void Parcel::setDataPosition(size_t pos) const
+{
+ mDataPos = pos;
+ mNextObjectHint = 0;
+}
+
+status_t Parcel::setDataCapacity(size_t size)
+{
+ if (size > mDataSize) return continueWrite(size);
+ return NO_ERROR;
+}
+
+status_t Parcel::setData(const uint8_t* buffer, size_t len)
+{
+ status_t err = restartWrite(len);
+ if (err == NO_ERROR) {
+ memcpy(const_cast<uint8_t*>(data()), buffer, len);
+ mDataSize = len;
+ mFdsKnown = false;
+ }
+ return err;
+}
+
+status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ status_t err;
+ uint8_t *data = parcel->mData;
+ size_t *objects = parcel->mObjects;
+ size_t size = parcel->mObjectsSize;
+ int startPos = mDataPos;
+ int firstIndex = -1, lastIndex = -2;
+
+ if (len == 0) {
+ return NO_ERROR;
+ }
+
+ // range checks against the source parcel size
+ if ((offset > parcel->mDataSize)
+ || (len > parcel->mDataSize)
+ || (offset + len > parcel->mDataSize)) {
+ return BAD_VALUE;
+ }
+
+ // Count objects in range
+ for (int i = 0; i < (int) size; i++) {
+ size_t off = objects[i];
+ if ((off >= offset) && (off < offset + len)) {
+ if (firstIndex == -1) {
+ firstIndex = i;
+ }
+ lastIndex = i;
+ }
+ }
+ int numObjects = lastIndex - firstIndex + 1;
+
+ // grow data
+ err = growData(len);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // append data
+ memcpy(mData + mDataPos, data + offset, len);
+ mDataPos += len;
+ mDataSize += len;
+
+ if (numObjects > 0) {
+ // grow objects
+ if (mObjectsCapacity < mObjectsSize + numObjects) {
+ int newSize = ((mObjectsSize + numObjects)*3)/2;
+ size_t *objects =
+ (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == (size_t*)0) {
+ return NO_MEMORY;
+ }
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ // append and acquire objects
+ int idx = mObjectsSize;
+ for (int i = firstIndex; i <= lastIndex; i++) {
+ size_t off = objects[i] - offset + startPos;
+ mObjects[idx++] = off;
+ mObjectsSize++;
+
+ flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData + off);
+ acquire_object(proc, *flat, this);
+
+ if (flat->type == BINDER_TYPE_FD) {
+ // If this is a file descriptor, we need to dup it so the
+ // new Parcel now owns its own fd, and can declare that we
+ // officially know we have fds.
+ flat->handle = dup(flat->handle);
+ flat->cookie = (void*)1;
+ mHasFds = mFdsKnown = true;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool Parcel::hasFileDescriptors() const
+{
+ if (!mFdsKnown) {
+ scanForFds();
+ }
+ return mHasFds;
+}
+
+status_t Parcel::writeInterfaceToken(const String16& interface)
+{
+ // currently the interface identification token is just its name as a string
+ return writeString16(interface);
+}
+
+bool Parcel::checkInterface(IBinder* binder) const
+{
+ return enforceInterface(binder->getInterfaceDescriptor());
+}
+
+bool Parcel::enforceInterface(const String16& interface) const
+{
+ const String16 str(readString16());
+ if (str == interface) {
+ return true;
+ } else {
+ LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
+ String8(interface).string(), String8(str).string());
+ return false;
+ }
+}
+
+const size_t* Parcel::objects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::objectsCount() const
+{
+ return mObjectsSize;
+}
+
+status_t Parcel::errorCheck() const
+{
+ return mError;
+}
+
+void Parcel::setError(status_t err)
+{
+ mError = err;
+}
+
+status_t Parcel::finishWrite(size_t len)
+{
+ //printf("Finish write of %d\n", len);
+ mDataPos += len;
+ LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
+ if (mDataPos > mDataSize) {
+ mDataSize = mDataPos;
+ LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
+ }
+ //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
+ return NO_ERROR;
+}
+
+status_t Parcel::writeUnpadded(const void* data, size_t len)
+{
+ size_t end = mDataPos + len;
+ if (end < mDataPos) {
+ // integer overflow
+ return BAD_VALUE;
+ }
+
+ if (end <= mDataCapacity) {
+restart_write:
+ memcpy(mData+mDataPos, data, len);
+ return finishWrite(len);
+ }
+
+ status_t err = growData(len);
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::write(const void* data, size_t len)
+{
+ void* const d = writeInplace(len);
+ if (d) {
+ memcpy(d, data, len);
+ return NO_ERROR;
+ }
+ return mError;
+}
+
+void* Parcel::writeInplace(size_t len)
+{
+ const size_t padded = PAD_SIZE(len);
+
+ // sanity check for integer overflow
+ if (mDataPos+padded < mDataPos) {
+ return NULL;
+ }
+
+ if ((mDataPos+padded) <= mDataCapacity) {
+restart_write:
+ //printf("Writing %ld bytes, padded to %ld\n", len, padded);
+ uint8_t* const data = mData+mDataPos;
+
+ // Need to pad at end?
+ if (padded != len) {
+#if BYTE_ORDER == BIG_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
+ };
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
+ };
+#endif
+ //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
+ // *reinterpret_cast<void**>(data+padded-4));
+ *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
+ }
+
+ finishWrite(padded);
+ return data;
+ }
+
+ status_t err = growData(padded);
+ if (err == NO_ERROR) goto restart_write;
+ return NULL;
+}
+
+status_t Parcel::writeInt32(int32_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeInt64(int64_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeFloat(float val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeDouble(double val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeIntPtr(intptr_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeCString(const char* str)
+{
+ return write(str, strlen(str)+1);
+}
+
+status_t Parcel::writeString8(const String8& str)
+{
+ status_t err = writeInt32(str.bytes());
+ if (err == NO_ERROR) {
+ err = write(str.string(), str.bytes()+1);
+ }
+ return err;
+}
+
+status_t Parcel::writeString16(const String16& str)
+{
+ return writeString16(str.string(), str.size());
+}
+
+status_t Parcel::writeString16(const char16_t* str, size_t len)
+{
+ if (str == NULL) return writeInt32(-1);
+
+ status_t err = writeInt32(len);
+ if (err == NO_ERROR) {
+ len *= sizeof(char16_t);
+ uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
+ if (data) {
+ memcpy(data, str, len);
+ *reinterpret_cast<char16_t*>(data+len) = 0;
+ return NO_ERROR;
+ }
+ err = mError;
+ }
+ return err;
+}
+
+status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeNativeHandle(const native_handle* handle)
+{
+ if (!handle || handle->version != sizeof(native_handle))
+ return BAD_TYPE;
+
+ status_t err;
+ err = writeInt32(handle->numFds);
+ if (err != NO_ERROR) return err;
+
+ err = writeInt32(handle->numInts);
+ if (err != NO_ERROR) return err;
+
+ for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++)
+ err = writeDupFileDescriptor(handle->data[i]);
+
+ if (err != NO_ERROR) {
+ LOGD("write native handle, write dup fd failed");
+ return err;
+ }
+ err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);
+ return err;
+}
+
+status_t Parcel::writeFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = fd;
+ obj.cookie = (void*)0;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeDupFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = dup(fd);
+ obj.cookie = (void*)1;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
+{
+ const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
+ const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+ if (enoughData && enoughObjects) {
+restart_write:
+ *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
+
+ // Need to write meta-data?
+ if (nullMetaData || val.binder != NULL) {
+ mObjects[mObjectsSize] = mDataPos;
+ acquire_object(ProcessState::self(), val, this);
+ mObjectsSize++;
+ }
+
+ // remember if it's a file descriptor
+ if (val.type == BINDER_TYPE_FD) {
+ mHasFds = mFdsKnown = true;
+ }
+
+ return finishWrite(sizeof(flat_binder_object));
+ }
+
+ if (!enoughData) {
+ const status_t err = growData(sizeof(val));
+ if (err != NO_ERROR) return err;
+ }
+ if (!enoughObjects) {
+ size_t newSize = ((mObjectsSize+2)*3)/2;
+ size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == NULL) return NO_MEMORY;
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ goto restart_write;
+}
+
+
+void Parcel::remove(size_t start, size_t amt)
+{
+ LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
+}
+
+status_t Parcel::read(void* outData, size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ memcpy(outData, mData+mDataPos, len);
+ mDataPos += PAD_SIZE(len);
+ LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
+ return NO_ERROR;
+ }
+ return NOT_ENOUGH_DATA;
+}
+
+const void* Parcel::readInplace(size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += PAD_SIZE(len);
+ LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
+ return data;
+ }
+ return NULL;
+}
+
+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(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
+{
+ return readAligned<int32_t>();
+}
+
+
+status_t Parcel::readInt64(int64_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+int64_t Parcel::readInt64() const
+{
+ return readAligned<int64_t>();
+}
+
+status_t Parcel::readFloat(float *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+float Parcel::readFloat() const
+{
+ return readAligned<float>();
+}
+
+status_t Parcel::readDouble(double *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+double Parcel::readDouble() const
+{
+ return readAligned<double>();
+}
+
+status_t Parcel::readIntPtr(intptr_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+intptr_t Parcel::readIntPtr() const
+{
+ return readAligned<intptr_t>();
+}
+
+
+const char* Parcel::readCString() const
+{
+ const size_t avail = mDataSize-mDataPos;
+ if (avail > 0) {
+ const char* str = reinterpret_cast<const char*>(mData+mDataPos);
+ // is the string's trailing NUL within the parcel's valid bounds?
+ const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
+ if (eos) {
+ const size_t len = eos - str;
+ mDataPos += PAD_SIZE(len+1);
+ LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
+ return str;
+ }
+ }
+ return NULL;
+}
+
+String8 Parcel::readString8() const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow adding 1 for trailing NUL
+ if (size > 0 && size < INT32_MAX) {
+ const char* str = (const char*)readInplace(size+1);
+ if (str) return String8(str, size);
+ }
+ return String8();
+}
+
+String16 Parcel::readString16() const
+{
+ size_t len;
+ const char16_t* str = readString16Inplace(&len);
+ if (str) return String16(str, len);
+ LOGE("Reading a NULL string not supported here.");
+ return String16();
+}
+
+const char16_t* Parcel::readString16Inplace(size_t* outLen) const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow from size+1
+ if (size >= 0 && size < INT32_MAX) {
+ *outLen = size;
+ const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
+ if (str != NULL) {
+ return str;
+ }
+ }
+ *outLen = 0;
+ return NULL;
+}
+
+sp<IBinder> Parcel::readStrongBinder() const
+{
+ sp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+wp<IBinder> Parcel::readWeakBinder() const
+{
+ wp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+
+native_handle* Parcel::readNativeHandle() const
+{
+ int numFds, numInts;
+ status_t err;
+ err = readInt32(&numFds);
+ if (err != NO_ERROR) return 0;
+ err = readInt32(&numInts);
+ if (err != NO_ERROR) return 0;
+
+ native_handle* h = native_handle_create(numFds, numInts);
+ for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
+ h->data[i] = dup(readFileDescriptor());
+ if (h->data[i] < 0) err = BAD_VALUE;
+ }
+ err = read(h->data + numFds, sizeof(int)*numInts);
+ if (err != NO_ERROR) {
+ native_handle_close(h);
+ native_handle_delete(h);
+ h = 0;
+ }
+ return h;
+}
+
+
+int Parcel::readFileDescriptor() const
+{
+ const flat_binder_object* flat = readObject(true);
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_FD:
+ //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
+ return flat->handle;
+ }
+ }
+ return BAD_TYPE;
+}
+
+const flat_binder_object* Parcel::readObject(bool nullMetaData) const
+{
+ const size_t DPOS = mDataPos;
+ if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
+ const flat_binder_object* obj
+ = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
+ mDataPos = DPOS + sizeof(flat_binder_object);
+ if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
+ // When transferring a NULL object, we don't write it into
+ // the object list, so we don't want to check for it when
+ // reading.
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Ensure that this object is valid...
+ size_t* const OBJS = mObjects;
+ const size_t N = mObjectsSize;
+ size_t opos = mNextObjectHint;
+
+ if (N > 0) {
+ LOGV("Parcel %p looking for obj at %d, hint=%d\n",
+ this, DPOS, opos);
+
+ // Start at the current hint position, looking for an object at
+ // the current data position.
+ if (opos < N) {
+ while (opos < (N-1) && OBJS[opos] < DPOS) {
+ opos++;
+ }
+ } else {
+ opos = N-1;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with forward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Look backwards for it...
+ while (opos > 0 && OBJS[opos] > DPOS) {
+ opos--;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with backward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+ }
+ LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
+ this, DPOS);
+ }
+ return NULL;
+}
+
+void Parcel::closeFileDescriptors()
+{
+ size_t i = mObjectsSize;
+ if (i > 0) {
+ //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
+ }
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ //LOGI("Closing fd: %ld\n", flat->handle);
+ close(flat->handle);
+ }
+ }
+}
+
+const uint8_t* Parcel::ipcData() const
+{
+ return mData;
+}
+
+size_t Parcel::ipcDataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+const size_t* Parcel::ipcObjects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::ipcObjectsCount() const
+{
+ return mObjectsSize;
+}
+
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
+{
+ freeDataNoInit();
+ mError = NO_ERROR;
+ mData = const_cast<uint8_t*>(data);
+ mDataSize = mDataCapacity = dataSize;
+ //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
+ mDataPos = 0;
+ LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = const_cast<size_t*>(objects);
+ mObjectsSize = mObjectsCapacity = objectsCount;
+ mNextObjectHint = 0;
+ mOwner = relFunc;
+ mOwnerCookie = relCookie;
+ scanForFds();
+}
+
+void Parcel::print(TextOutput& to, uint32_t flags) const
+{
+ to << "Parcel(";
+
+ if (errorCheck() != NO_ERROR) {
+ const status_t err = errorCheck();
+ to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
+ } else if (dataSize() > 0) {
+ const uint8_t* DATA = data();
+ to << indent << HexDump(DATA, dataSize()) << dedent;
+ const size_t* OBJS = objects();
+ const size_t N = objectsCount();
+ for (size_t i=0; i<N; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
+ to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+ << TypeCode(flat->type & 0x7f7f7f00)
+ << " = " << flat->binder;
+ }
+ } else {
+ to << "NULL";
+ }
+
+ to << ")";
+}
+
+void Parcel::releaseObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ release_object(proc, *flat, this);
+ }
+}
+
+void Parcel::acquireObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ acquire_object(proc, *flat, this);
+ }
+}
+
+void Parcel::freeData()
+{
+ freeDataNoInit();
+ initState();
+}
+
+void Parcel::freeDataNoInit()
+{
+ if (mOwner) {
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ } else {
+ releaseObjects();
+ if (mData) free(mData);
+ if (mObjects) free(mObjects);
+ }
+}
+
+status_t Parcel::growData(size_t len)
+{
+ size_t newSize = ((mDataSize+len)*3)/2;
+ return (newSize <= mDataSize)
+ ? (status_t) NO_MEMORY
+ : continueWrite(newSize);
+}
+
+status_t Parcel::restartWrite(size_t desired)
+{
+ if (mOwner) {
+ freeData();
+ return continueWrite(desired);
+ }
+
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (!data && desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ releaseObjects();
+
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ }
+
+ mDataSize = mDataPos = 0;
+ LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
+
+ free(mObjects);
+ mObjects = NULL;
+ mObjectsSize = mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+
+ return NO_ERROR;
+}
+
+status_t Parcel::continueWrite(size_t desired)
+{
+ // If shrinking, first adjust for any objects that appear
+ // after the new data size.
+ size_t objectsSize = mObjectsSize;
+ if (desired < mDataSize) {
+ if (desired == 0) {
+ objectsSize = 0;
+ } else {
+ while (objectsSize > 0) {
+ if (mObjects[objectsSize-1] < desired)
+ break;
+ objectsSize--;
+ }
+ }
+ }
+
+ if (mOwner) {
+ // If the size is going to zero, just release the owner's data.
+ if (desired == 0) {
+ freeData();
+ return NO_ERROR;
+ }
+
+ // If there is a different owner, we need to take
+ // posession.
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ size_t* objects = NULL;
+
+ if (objectsSize) {
+ objects = (size_t*)malloc(objectsSize*sizeof(size_t));
+ if (!objects) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ // Little hack to only acquire references on objects
+ // we will be keeping.
+ size_t oldObjectsSize = mObjectsSize;
+ mObjectsSize = objectsSize;
+ acquireObjects();
+ mObjectsSize = oldObjectsSize;
+ }
+
+ if (mData) {
+ memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
+ }
+ if (objects && mObjects) {
+ memcpy(objects, mObjects, objectsSize*sizeof(size_t));
+ }
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ mOwner = NULL;
+
+ mData = data;
+ mObjects = objects;
+ mDataSize = (mDataSize < desired) ? mDataSize : desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ mDataCapacity = desired;
+ mObjectsSize = mObjectsCapacity = objectsSize;
+ mNextObjectHint = 0;
+
+ } else if (mData) {
+ if (objectsSize < mObjectsSize) {
+ // Need to release refs on any objects we are dropping.
+ const sp<ProcessState> proc(ProcessState::self());
+ for (size_t i=objectsSize; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ // will need to rescan because we may have lopped off the only FDs
+ mFdsKnown = false;
+ }
+ release_object(proc, *flat, this);
+ }
+ size_t* objects =
+ (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
+ if (objects) {
+ mObjects = objects;
+ }
+ mObjectsSize = objectsSize;
+ mNextObjectHint = 0;
+ }
+
+ // We own the data, so we can just do a realloc().
+ if (desired > mDataCapacity) {
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ } else if (desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ } else {
+ mDataSize = desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ if (mDataPos > desired) {
+ mDataPos = desired;
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ }
+ }
+
+ } else {
+ // This is the first data. Easy!
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ if(!(mDataCapacity == 0 && mObjects == NULL
+ && mObjectsCapacity == 0)) {
+ LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
+ }
+
+ mData = data;
+ mDataSize = mDataPos = 0;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ mDataCapacity = desired;
+ }
+
+ return NO_ERROR;
+}
+
+void Parcel::initState()
+{
+ mError = NO_ERROR;
+ mData = 0;
+ mDataSize = 0;
+ mDataCapacity = 0;
+ mDataPos = 0;
+ LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = NULL;
+ mObjectsSize = 0;
+ mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+ mOwner = NULL;
+}
+
+void Parcel::scanForFds() const
+{
+ bool hasFds = false;
+ for (size_t i=0; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ hasFds = true;
+ break;
+ }
+ }
+ mHasFds = hasFds;
+ mFdsKnown = true;
+}
+
+}; // namespace android
diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp
new file mode 100644
index 0000000..fd8fe69
--- /dev/null
+++ b/libs/binder/Permission.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Permission.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+Permission::Permission(char const* name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const String16& name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const Permission& rhs)
+ : mPermissionName(rhs.mPermissionName),
+ mGranted(rhs.mGranted),
+ mPid(rhs.mPid)
+{
+}
+
+Permission::~Permission()
+{
+}
+
+bool Permission::operator < (const Permission& rhs) const
+{
+ return mPermissionName < rhs.mPermissionName;
+}
+
+bool Permission::checkCalling() const
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::check(pid_t pid, uid_t uid) const
+{
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::doCheckPermission(pid_t pid, uid_t uid) const
+{
+ if ((uid == 0) || (pid == mPid)) {
+ // root and ourselves is always okay
+ return true;
+ } else {
+ // see if we already granted this permission for this uid
+ Mutex::Autolock _l(mLock);
+ if (mGranted.indexOf(uid) >= 0)
+ return true;
+ }
+
+ bool granted = checkPermission(mPermissionName, pid, uid);
+ if (granted) {
+ Mutex::Autolock _l(mLock);
+ // no need to check again, the old item will be replaced if it is
+ // already there.
+ mGranted.add(uid);
+ }
+ return granted;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
new file mode 100644
index 0000000..d7daf73
--- /dev/null
+++ b/libs/binder/ProcessState.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ProcessState"
+
+#include <cutils/process_name.h>
+
+#include <binder/ProcessState.h>
+
+#include <utils/Atomic.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <binder/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#define BINDER_VM_SIZE (1*1024*1024)
+
+static bool gSingleProcess = false;
+
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// Global variables
+int mArgC;
+const char* const* mArgV;
+int mArgLen;
+
+class PoolThread : public Thread
+{
+public:
+ PoolThread(bool isMain)
+ : mIsMain(isMain)
+ {
+ }
+
+protected:
+ virtual bool threadLoop()
+ {
+ IPCThreadState::self()->joinThreadPool(mIsMain);
+ return false;
+ }
+
+ const bool mIsMain;
+};
+
+sp<ProcessState> ProcessState::self()
+{
+ if (gProcess != NULL) return gProcess;
+
+ AutoMutex _l(gProcessMutex);
+ if (gProcess == NULL) gProcess = new ProcessState;
+ return gProcess;
+}
+
+void ProcessState::setSingleProcess(bool singleProcess)
+{
+ gSingleProcess = singleProcess;
+}
+
+
+void ProcessState::setContextObject(const sp<IBinder>& object)
+{
+ setContextObject(object, String16("default"));
+}
+
+sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
+{
+ if (supportsProcesses()) {
+ return getStrongProxyForHandle(0);
+ } else {
+ return getContextObject(String16("default"), caller);
+ }
+}
+
+void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
+{
+ AutoMutex _l(mLock);
+ mContexts.add(name, object);
+}
+
+sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
+{
+ mLock.lock();
+ sp<IBinder> object(
+ mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
+ mLock.unlock();
+
+ //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
+
+ if (object != NULL) return object;
+
+ // Don't attempt to retrieve contexts if we manage them
+ if (mManagesContexts) {
+ LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
+ String8(name).string());
+ return NULL;
+ }
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ {
+ Parcel data, reply;
+ // no interface token on this magic transaction
+ data.writeString16(name);
+ data.writeStrongBinder(caller);
+ status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
+ if (result == NO_ERROR) {
+ object = reply.readStrongBinder();
+ }
+ }
+
+ ipc->flushCommands();
+
+ if (object != NULL) setContextObject(object, name);
+ return object;
+}
+
+bool ProcessState::supportsProcesses() const
+{
+ return mDriverFD >= 0;
+}
+
+void ProcessState::startThreadPool()
+{
+ AutoMutex _l(mLock);
+ if (!mThreadPoolStarted) {
+ mThreadPoolStarted = true;
+ spawnPooledThread(true);
+ }
+}
+
+bool ProcessState::isContextManager(void) const
+{
+ return mManagesContexts;
+}
+
+bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
+{
+ if (!mManagesContexts) {
+ AutoMutex _l(mLock);
+ mBinderContextCheckFunc = checkFunc;
+ mBinderContextUserData = userData;
+ if (mDriverFD >= 0) {
+ int dummy = 0;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+#else
+ status_t result = INVALID_OPERATION;
+#endif
+ if (result == 0) {
+ mManagesContexts = true;
+ } else if (result == -1) {
+ mBinderContextCheckFunc = NULL;
+ mBinderContextUserData = NULL;
+ LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
+ }
+ } else {
+ // If there is no driver, our only world is the local
+ // process so we can always become the context manager there.
+ mManagesContexts = true;
+ }
+ }
+ return mManagesContexts;
+}
+
+ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
+{
+ const size_t N=mHandleToObject.size();
+ if (N <= (size_t)handle) {
+ handle_entry e;
+ e.binder = NULL;
+ e.refs = NULL;
+ status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
+ if (err < NO_ERROR) return NULL;
+ }
+ return &mHandleToObject.editItemAt(handle);
+}
+
+sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
+{
+ sp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. See comment
+ // in getWeakProxyForHandle() for more info about this.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ result = b;
+ } else {
+ // This little bit of nastyness is to allow us to add a primary
+ // reference to the remote proxy when this team doesn't have one
+ // but another team is sending the handle to us.
+ result.force_set(b);
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
+{
+ wp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. The
+ // attemptIncWeak() is safe because we know the BpBinder destructor will always
+ // call expungeHandle(), which acquires the same lock we are holding now.
+ // We need to do this because there is a race condition between someone
+ // releasing a reference on this BpBinder, and a new reference on its handle
+ // arriving from the driver.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ result = b;
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ } else {
+ result = b;
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
+{
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ // This handle may have already been replaced with a new BpBinder
+ // (if someone failed the AttemptIncWeak() above); we don't want
+ // to overwrite it.
+ if (e && e->binder == binder) e->binder = NULL;
+}
+
+void ProcessState::setArgs(int argc, const char* const argv[])
+{
+ mArgC = argc;
+ mArgV = (const char **)argv;
+
+ mArgLen = 0;
+ for (int i=0; i<argc; i++) {
+ mArgLen += strlen(argv[i]) + 1;
+ }
+ mArgLen--;
+}
+
+int ProcessState::getArgC() const
+{
+ return mArgC;
+}
+
+const char* const* ProcessState::getArgV() const
+{
+ return mArgV;
+}
+
+void ProcessState::setArgV0(const char* txt)
+{
+ if (mArgV != NULL) {
+ strncpy((char*)mArgV[0], txt, mArgLen);
+ set_process_name(txt);
+ }
+}
+
+void ProcessState::spawnPooledThread(bool isMain)
+{
+ if (mThreadPoolStarted) {
+ int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ char buf[32];
+ sprintf(buf, "Binder Thread #%d", s);
+ LOGV("Spawning new pooled thread, name=%s\n", buf);
+ sp<Thread> t = new PoolThread(isMain);
+ t->run(buf);
+ }
+}
+
+static int open_driver()
+{
+ if (gSingleProcess) {
+ return -1;
+ }
+
+ int fd = open("/dev/binder", O_RDWR);
+ if (fd >= 0) {
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ int vers;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(fd, BINDER_VERSION, &vers);
+#else
+ status_t result = -1;
+ errno = EPERM;
+#endif
+ if (result == -1) {
+ LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
+ close(fd);
+ fd = -1;
+ }
+ if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+ LOGE("Binder driver protocol does not match user space protocol!");
+ close(fd);
+ fd = -1;
+ }
+#if defined(HAVE_ANDROID_OS)
+ size_t maxThreads = 15;
+ result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+ if (result == -1) {
+ LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+ }
+#endif
+
+ } else {
+ LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+ }
+ return fd;
+}
+
+ProcessState::ProcessState()
+ : mDriverFD(open_driver())
+ , mVMStart(MAP_FAILED)
+ , mManagesContexts(false)
+ , mBinderContextCheckFunc(NULL)
+ , mBinderContextUserData(NULL)
+ , mThreadPoolStarted(false)
+ , mThreadPoolSeq(1)
+{
+ if (mDriverFD >= 0) {
+ // XXX Ideally, there should be a specific define for whether we
+ // have mmap (or whether we could possibly have the kernel module
+ // availabla).
+#if !defined(HAVE_WIN32_IPC)
+ // mmap the binder, providing a chunk of virtual address space to receive transactions.
+ mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+ if (mVMStart == MAP_FAILED) {
+ // *sigh*
+ LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+ close(mDriverFD);
+ mDriverFD = -1;
+ }
+#else
+ mDriverFD = -1;
+#endif
+ }
+ if (mDriverFD < 0) {
+ // Need to run without the driver, starting our own thread pool.
+ }
+}
+
+ProcessState::~ProcessState()
+{
+}
+
+}; // namespace android
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
new file mode 100644
index 0000000..12b0308
--- /dev/null
+++ b/libs/binder/Static.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <private/binder/Static.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// ------------ ProcessState.cpp
+
+Mutex gProcessMutex;
+sp<ProcessState> gProcess;
+
+class LibUtilsIPCtStatics
+{
+public:
+ LibUtilsIPCtStatics()
+ {
+ }
+
+ ~LibUtilsIPCtStatics()
+ {
+ IPCThreadState::shutdown();
+ }
+};
+
+static LibUtilsIPCtStatics gIPCStatics;
+
+// ------------ ServiceManager.cpp
+
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
new file mode 100644
index 0000000..bc466be
--- /dev/null
+++ b/libs/rs/Android.mk
@@ -0,0 +1,115 @@
+
+LOCAL_PATH:=$(call my-dir)
+
+
+# Build rsg-generator ====================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := rsg-generator
+
+# These symbols are normally defined by BUILD_XXX, but we need to define them
+# here so that local-intermediates-dir works.
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+intermediates := $(local-intermediates-dir)
+
+LOCAL_SRC_FILES:= \
+ spec.l \
+ rsg_generator.c
+
+include $(BUILD_HOST_EXECUTABLE)
+
+# TODO: This should go into build/core/config.mk
+RSG_GENERATOR:=$(LOCAL_BUILT_MODULE)
+
+
+
+# Build render script lib ====================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libRS
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+intermediates:= $(local-intermediates-dir)
+
+# Generate custom headers
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApiStructs.h \
+ rsgApiFuncDecl.h \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# Generate custom source files
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApi.cpp \
+ rsgApiReplay.cpp \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# libRS needs libacc, which isn't 64-bit clean, and so can't be built
+# for the simulator on gHardy, and therefore libRS needs to be excluded
+# from the simulator as well.
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_SRC_FILES:= \
+ rsAdapter.cpp \
+ rsAllocation.cpp \
+ rsComponent.cpp \
+ rsContext.cpp \
+ rsDevice.cpp \
+ rsElement.cpp \
+ rsFileA3D.cpp \
+ rsLight.cpp \
+ rsLocklessFifo.cpp \
+ rsObjectBase.cpp \
+ rsMatrix.cpp \
+ rsMesh.cpp \
+ rsNoise.cpp \
+ rsProgram.cpp \
+ rsProgramFragment.cpp \
+ rsProgramFragmentStore.cpp \
+ rsProgramVertex.cpp \
+ rsSampler.cpp \
+ rsScript.cpp \
+ rsScriptC.cpp \
+ rsScriptC_Lib.cpp \
+ rsSimpleMesh.cpp \
+ rsThreadIO.cpp \
+ rsType.cpp \
+ rsTriangleMesh.cpp
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libui libacc
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libRS
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Include the subdirectories ====================
+include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk,\
+ java \
+ ))
+
+endif #simulator
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
new file mode 100644
index 0000000..d7d572e
--- /dev/null
+++ b/libs/rs/RenderScript.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef RENDER_SCRIPT_H
+#define RENDER_SCRIPT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////////////////////
+//
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsFile;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsSimpleMesh;
+typedef void * RsType;
+typedef void * RsLight;
+
+typedef void * RsProgramVertex;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+
+RsDevice rsDeviceCreate();
+void rsDeviceDestroy(RsDevice);
+
+RsContext rsContextCreate(RsDevice, void *, uint32_t version);
+void rsContextDestroy(RsContext);
+
+#define RS_MAX_TEXTURE 2
+
+enum RsDataType {
+ RS_TYPE_FLOAT,
+ RS_TYPE_UNSIGNED,
+ RS_TYPE_SIGNED
+};
+
+enum RsDataKind {
+ RS_KIND_USER,
+ RS_KIND_RED,
+ RS_KIND_GREEN,
+ RS_KIND_BLUE,
+ RS_KIND_ALPHA,
+ RS_KIND_LUMINANCE,
+ RS_KIND_INTENSITY,
+ RS_KIND_X,
+ RS_KIND_Y,
+ RS_KIND_Z,
+ RS_KIND_W,
+ RS_KIND_S,
+ RS_KIND_T,
+ RS_KIND_Q,
+ RS_KIND_R,
+ RS_KIND_NX,
+ RS_KIND_NY,
+ RS_KIND_NZ,
+ RS_KIND_INDEX
+};
+
+enum RsElementPredefined {
+ RS_ELEMENT_USER_U8,
+ RS_ELEMENT_USER_I8,
+ RS_ELEMENT_USER_U16,
+ RS_ELEMENT_USER_I16,
+ RS_ELEMENT_USER_U32,
+ RS_ELEMENT_USER_I32,
+ RS_ELEMENT_USER_FLOAT,
+
+ RS_ELEMENT_A_8, // 7
+ RS_ELEMENT_RGB_565, // 8
+ RS_ELEMENT_RGBA_5551, // 9
+ RS_ELEMENT_RGBA_4444, // 10
+ RS_ELEMENT_RGB_888, // 11
+ RS_ELEMENT_RGBA_8888, // 12
+
+ RS_ELEMENT_INDEX_16, //13
+ RS_ELEMENT_INDEX_32,
+ RS_ELEMENT_XY_F32,
+ RS_ELEMENT_XYZ_F32,
+ RS_ELEMENT_ST_XY_F32,
+ RS_ELEMENT_ST_XYZ_F32,
+ RS_ELEMENT_NORM_XYZ_F32,
+ RS_ELEMENT_NORM_ST_XYZ_F32,
+};
+
+enum RsSamplerParam {
+ RS_SAMPLER_MIN_FILTER,
+ RS_SAMPLER_MAG_FILTER,
+ RS_SAMPLER_WRAP_S,
+ RS_SAMPLER_WRAP_T,
+ RS_SAMPLER_WRAP_R
+};
+
+enum RsSamplerValue {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP
+};
+
+enum RsDimension {
+ RS_DIMENSION_X,
+ RS_DIMENSION_Y,
+ RS_DIMENSION_Z,
+ RS_DIMENSION_LOD,
+ RS_DIMENSION_FACE,
+
+ RS_DIMENSION_ARRAY_0 = 100,
+ RS_DIMENSION_ARRAY_1,
+ RS_DIMENSION_ARRAY_2,
+ RS_DIMENSION_ARRAY_3,
+ RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
+};
+
+enum RsDepthFunc {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL
+};
+
+enum RsBlendSrcFunc {
+ RS_BLEND_SRC_ZERO, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
+};
+
+enum RsBlendDstFunc {
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
+};
+
+enum RsTexEnvMode {
+ RS_TEX_ENV_MODE_REPLACE,
+ RS_TEX_ENV_MODE_MODULATE,
+ RS_TEX_ENV_MODE_DECAL
+};
+
+enum RsPrimitive {
+ RS_PRIMITIVE_POINT,
+ RS_PRIMITIVE_LINE,
+ RS_PRIMITIVE_LINE_STRIP,
+ RS_PRIMITIVE_TRIANGLE,
+ RS_PRIMITIVE_TRIANGLE_STRIP,
+ RS_PRIMITIVE_TRIANGLE_FAN
+};
+
+
+#include "rsgApiFuncDecl.h"
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // RENDER_SCRIPT_H
+
+
+
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
new file mode 100644
index 0000000..5eb8912
--- /dev/null
+++ b/libs/rs/RenderScriptEnv.h
@@ -0,0 +1,33 @@
+#include <stdint.h>
+
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsSimpleMesh;
+typedef void * RsType;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+typedef void * RsLight;
+
+
+typedef struct {
+ float m[16];
+} rsc_Matrix;
+
+
+typedef struct {
+ float v[4];
+} rsc_Vector4;
+
+#define RS_PROGRAM_VERTEX_MODELVIEW_OFFSET 0
+#define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
+#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
+
diff --git a/libs/rs/java/Android.mk b/libs/rs/java/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/rs/java/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/rs/java/Fall/Android.mk b/libs/rs/java/Fall/Android.mk
new file mode 100644
index 0000000..6366f63
--- /dev/null
+++ b/libs/rs/java/Fall/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := FallRS
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fall/AndroidManifest.xml b/libs/rs/java/Fall/AndroidManifest.xml
new file mode 100644
index 0000000..f646d0d
--- /dev/null
+++ b/libs/rs/java/Fall/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.fall.rs">
+
+ <application android:label="FallRS">
+
+ <activity
+ android:screenOrientation="portrait"
+ android:name="Fall"
+ android:theme="@android:style/Theme.NoTitleBar">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/leaves.png b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
new file mode 100644
index 0000000..9eddd66
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
new file mode 100644
index 0000000..1698f28
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
new file mode 100644
index 0000000..b18c124
--- /dev/null
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -0,0 +1,481 @@
+// 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.
+
+#pragma version(1)
+#pragma stateVertex(PVBackground)
+#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 LEAF_STRUCT_FIELDS_COUNT 11
+#define LEAF_STRUCT_X 0
+#define LEAF_STRUCT_Y 1
+#define LEAF_STRUCT_SCALE 2
+#define LEAF_STRUCT_ANGLE 3
+#define LEAF_STRUCT_SPIN 4
+#define LEAF_STRUCT_U1 5
+#define LEAF_STRUCT_U2 6
+#define LEAF_STRUCT_ALTITUDE 7
+#define LEAF_STRUCT_RIPPLED 8
+#define LEAF_STRUCT_DELTAX 9
+#define LEAF_STRUCT_DELTAY 10
+
+#define LEAVES_TEXTURES_COUNT 4
+
+#define LEAF_SIZE 0.55f
+
+#define REFRACTION 1.333f
+#define DAMP 3
+
+#define DROP_RADIUS 2
+// The higher, the smaller the ripple
+#define RIPPLE_HEIGHT 10.0f
+
+int offset(int x, int y, int width) {
+ 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);
+
+ 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;
+
+ x = width - x;
+
+ int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
+ int index = loadI32(RSID_STATE, RSID_RIPPLE_INDEX);
+ int origin = offset(0, 0, width);
+
+ int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+ int sqr = r * r;
+
+ int h = 0;
+ for ( ; h < r; h++) {
+ 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++) {
+ int squ = w * w;
+ if (squ + sqv < sqr) {
+ int v = -sqrtf((sqr - (squ + sqv)) << 16);
+ current[yn + x + w] = v;
+ current[yp + x + w] = v;
+ current[yn + x - w] = v;
+ current[yp + x - w] = v;
+ }
+ }
+ }
+}
+
+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 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);
+
+ int a = 1;
+ int b = width + 2;
+ int h = height;
+ while (h) {
+ int w = width;
+ while (w) {
+ int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - next[0];
+ droplet -= (droplet >> DAMP);
+ next[0] = droplet;
+ current++;
+ next++;
+ w--;
+ }
+ current += 2;
+ next += 2;
+ h--;
+ }
+}
+
+int refraction(int d, int wave) {
+ int* map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+ int i = d;
+ if (i < 0) i = -i;
+ if (i > 512) i = 512;
+ int w = (wave + 0x10000) >> 8;
+ w &= ~(w >> 31);
+ int r = (map[i] * w) >> 3;
+ if (d < 0) {
+ return -r;
+ }
+ return r;
+}
+
+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 origin = offset(0, 0, width);
+
+ int b = width + 2;
+
+ int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+ float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+
+ int h = height - 1;
+ while (h >= 0) {
+ int w = width - 1;
+ int wave = current[0];
+ 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 u = (width - w) + offsetx;
+ u &= ~(u >> 31);
+ if (u >= width) u = width - 1;
+
+ int offsety = refraction(dy, wave) >> 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;
+
+ // Update Z coordinate of the vertex
+ vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
+
+ w--;
+ current++;
+ wave = nextWave;
+ }
+ h--;
+ current += 2;
+ }
+
+ // Compute the normals for lighting
+ int y = 0;
+ for ( ; y < height; y++) {
+ int x = 0;
+ int yOffset = y * width;
+ for ( ; x < width; x++) {
+ // V1
+ float v1x = vertices[(yOffset + x) * 8 + 5];
+ float v1y = vertices[(yOffset + x) * 8 + 6];
+ float v1z = vertices[(yOffset + x) * 8 + 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];
+
+ // 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];
+
+ // N1
+ float n1x = v2x - v1x;
+ float n1y = v2y - v1y;
+ float n1z = v2z - v1z;
+
+ // N2
+ float n2x = v3x - v1x;
+ float n2y = v3y - v1y;
+ float n2z = v3z - v1z;
+
+ // N1 x N2
+ float n3x = n1y * n2z - n1z * n2y;
+ float n3y = n1z * n2x - n1x * n2z;
+ float n3z = n1x * n2y - n1y * n2x;
+
+ // Normalize
+ float len = 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];
+
+ // N1
+ n1x = v2x - v1x;
+ n1y = v2y - v1y;
+ n1z = v2z - v1z;
+
+ // N2
+ n2x = v3x - v1x;
+ 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;
+
+ // Normalize
+ len = 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;
+
+ // 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);
+ }
+ }
+}
+
+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;
+
+ int quadX1 = clamp(x1, 0, meshWidth);
+ int quadX2 = clamp(x2, 0, meshWidth);
+ int quadY1 = clamp(y1, 0, meshHeight);
+ int quadY2 = clamp(y2, 0, meshHeight);
+
+ float z = 0.0f;
+ int vertexCount = 0;
+
+ int y = quadY1;
+ for ( ; y < quadY2; y++) {
+ int x = quadX1;
+ int yOffset = y * meshWidth;
+ for ( ; x < quadX2; x++) {
+ z += vertices[(yOffset + x) * 8 + 7];
+ vertexCount++;
+ }
+ }
+
+ return 75.0f * z / vertexCount;
+}
+
+void drawLeaf(int index, int frameCount, float* vertices, int meshWidth, int meshHeight,
+ float glWidth, float glHeight) {
+
+ float *leafStruct = loadArrayF(RSID_LEAVES, index);
+
+ float x = leafStruct[LEAF_STRUCT_X];
+ float x1 = x - LEAF_SIZE;
+ float x2 = x + LEAF_SIZE;
+
+ float y = leafStruct[LEAF_STRUCT_Y];
+ float y1 = y - LEAF_SIZE;
+ float y2 = y + LEAF_SIZE;
+
+ float u1 = leafStruct[LEAF_STRUCT_U1];
+ float u2 = leafStruct[LEAF_STRUCT_U2];
+
+ float z1 = 0.0f;
+ float z2 = 0.0f;
+ float z3 = 0.0f;
+ float z4 = 0.0f;
+
+ float a = leafStruct[LEAF_STRUCT_ALTITUDE];
+ float s = leafStruct[LEAF_STRUCT_SCALE];
+ float r = leafStruct[LEAF_STRUCT_ANGLE];
+
+ float tz = 0.0f;
+ 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);
+ }
+
+ x1 -= x;
+ x2 -= x;
+ y1 -= y;
+ y2 -= y;
+
+ float matrix[16];
+ matrixLoadIdentity(matrix);
+ matrixTranslate(matrix, x, y, tz);
+ matrixScale(matrix, s, s, 1.0f);
+ matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
+ vpLoadModelMatrix(matrix);
+
+ drawQuadTexCoords(x1, y1, z1, u1, 1.0f,
+ x2, y1, z2, u2, 1.0f,
+ x2, y2, z3, u2, 0.0f,
+ x1, y2, z4, u1, 0.0f);
+
+ float spin = leafStruct[LEAF_STRUCT_SPIN];
+ 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_RADIUS);
+ spin /= 4.0f;
+ leafStruct[LEAF_STRUCT_SPIN] = spin;
+ leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
+ }
+ leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
+ leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
+ r += spin;
+ leafStruct[LEAF_STRUCT_ANGLE] = r;
+ } else {
+ a -= 0.005f;
+ leafStruct[LEAF_STRUCT_ALTITUDE] = a;
+ r += spin * 2.0f;
+ leafStruct[LEAF_STRUCT_ANGLE] = r;
+ }
+
+ if (-LEAF_SIZE * s + x > glWidth / 2.0f || LEAF_SIZE * s + x < -glWidth / 2.0f ||
+ LEAF_SIZE * s + y < -glHeight / 2.0f) {
+
+ int sprite = randf(LEAVES_TEXTURES_COUNT);
+ leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
+ leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
+ leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
+ 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;
+ }
+}
+
+void drawLeaves(int frameCount) {
+ bindProgramFragment(NAMED_PFLeaf);
+ bindProgramFragmentStore(NAMED_PFSLeaf);
+ bindTexture(NAMED_PFLeaf, 0, NAMED_TLeaves);
+
+ int leavesCount = loadI32(RSID_STATE, RSID_LEAVES_COUNT);
+ 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);
+
+ float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
+
+ int i = 0;
+ for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
+ drawLeaf(i, frameCount, 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);
+
+ bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
+ drawTriangleMesh(NAMED_mesh);
+
+ 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);
+ bindProgramFragment(NAMED_PFLighting);
+ drawTriangleMesh(NAMED_mesh);
+
+ drawLeaves(frameCount);
+
+ if (!isRunning) {
+ drawNormals();
+ }
+
+ frameCount++;
+ storeI32(RSID_STATE, RSID_FRAME_COUNT, frameCount);
+
+ return 1;
+}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java b/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
new file mode 100644
index 0000000..b1d9b1d
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
@@ -0,0 +1,47 @@
+/*
+ * 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 com.android.fall.rs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Fall extends Activity {
+ private FallView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mView = new FallView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+}
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
new file mode 100644
index 0000000..63e6ed9
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -0,0 +1,426 @@
+/*
+ * 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 com.android.fall.rs;
+
+import android.content.res.Resources;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Allocation;
+import android.renderscript.Sampler;
+import android.renderscript.Element;
+import android.renderscript.Light;
+import static android.renderscript.Sampler.Value.LINEAR;
+import static android.renderscript.Sampler.Value.CLAMP;
+import static android.renderscript.ProgramStore.DepthFunc.*;
+import static android.renderscript.ProgramStore.BlendDstFunc;
+import static android.renderscript.ProgramStore.BlendSrcFunc;
+import static android.renderscript.ProgramFragment.EnvMode.*;
+import static android.renderscript.Element.*;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
+
+import java.util.TimeZone;
+
+class FallRS {
+ 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 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_RIPPLE_MAP = 1;
+
+ private static final int RSID_REFRACTION_MAP = 2;
+
+ private static final int RSID_LEAVES = 3;
+ private static final int LEAVES_COUNT = 14;
+ private static final int LEAF_STRUCT_FIELDS_COUNT = 11;
+ private static final int LEAF_STRUCT_X = 0;
+ private static final int LEAF_STRUCT_Y = 1;
+ private static final int LEAF_STRUCT_SCALE = 2;
+ private static final int LEAF_STRUCT_ANGLE = 3;
+ private static final int LEAF_STRUCT_SPIN = 4;
+ private static final int LEAF_STRUCT_U1 = 5;
+ private static final int LEAF_STRUCT_U2 = 6;
+ private static final int LEAF_STRUCT_ALTITUDE = 7;
+ private static final int LEAF_STRUCT_RIPPLED = 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 Resources mResources;
+ private RenderScript mRS;
+
+ private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+ private final int mWidth;
+ private final int mHeight;
+
+ private ScriptC mScript;
+ private Sampler mSampler;
+ private ProgramFragment mPfBackground;
+ private ProgramFragment mPfLighting;
+ private ProgramFragment mPfLeaf;
+ private ProgramStore mPfsBackground;
+ private ProgramStore mPfsLeaf;
+ private ProgramVertex mPvBackground;
+ private ProgramVertex mPvLines;
+ private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
+ private Light mLight;
+
+ private Allocation[] mTextures;
+
+ private Allocation mState;
+ private RenderScript.TriangleMesh mMesh;
+ private int mMeshWidth;
+ private int mMeshHeight;
+
+ private Allocation mRippleMap;
+ private Allocation mRefractionMap;
+ private Allocation mLeaves;
+
+ private Allocation mGlState;
+ private float mGlHeight;
+
+ public FallRS(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mOptionsARGB.inScaled = false;
+ mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ }
+
+ public void init(RenderScript rs, Resources res) {
+ mRS = rs;
+ mResources = res;
+ 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();
+ createProgramFragment();
+ createMesh();
+ createScriptStructures();
+ loadTextures();
+
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ 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);
+
+ mRS.contextBindRootScript(mScript);
+ }
+
+ private void createMesh() {
+ final RenderScript rs = mRS;
+ rs.triangleMeshBegin(Element.NORM_ST_XYZ_F32, Element.INDEX_16);
+
+ int wResolution;
+ int hResolution;
+
+ final int width = mWidth;
+ final int height = mHeight;
+
+ if (width < height) {
+ wResolution = MESH_RESOLUTION;
+ hResolution = (int) (MESH_RESOLUTION * height / (float) width);
+ } else {
+ wResolution = (int) (MESH_RESOLUTION * width / (float) height);
+ hResolution = MESH_RESOLUTION;
+ }
+
+ mGlHeight = 2.0f * height / (float) width;
+ final float glHeight = mGlHeight;
+
+ float quadWidth = 2.0f / (float) wResolution;
+ float quadHeight = glHeight / (float) hResolution;
+
+ wResolution += 2;
+ hResolution += 2;
+
+ for (int y = 0; y <= hResolution; y++) {
+ 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);
+ }
+ }
+
+ for (int y = 0; y < hResolution; y++) {
+ for (int x = 0; x < wResolution; x++) {
+ final int index = y * (wResolution + 1) + x;
+ final int iWR1 = index + wResolution + 1;
+ rs.triangleMeshAddTriangle(index, index + 1, iWR1);
+ rs.triangleMeshAddTriangle(index + 1, iWR1, iWR1 + 1);
+ }
+ }
+
+ mMesh = rs.triangleMeshCreate();
+ mMesh.setName("mesh");
+
+ mMeshWidth = wResolution + 1;
+ mMeshHeight = hResolution + 1;
+ }
+
+ private void createScriptStructures() {
+ final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
+
+ createState(rippleMapSize);
+ createGlState();
+ createRippleMap(rippleMapSize);
+ createRefractionMap();
+ createLeaves();
+ }
+
+ private void createLeaves() {
+ final float[] leaves = new float[LEAVES_COUNT * LEAF_STRUCT_FIELDS_COUNT];
+ mLeaves = Allocation.createSized(mRS, USER_FLOAT, leaves.length);
+ for (int i = 0; i < leaves.length; i += LEAF_STRUCT_FIELDS_COUNT) {
+ createLeaf(leaves, i);
+ }
+ mLeaves.data(leaves);
+ }
+
+ private void createRefractionMap() {
+ final int[] refractionMap = new int[513];
+ float ir = 1.0f / 1.333f;
+ for (int i = 0; i < refractionMap.length; i++) {
+ float d = (float) Math.tan(Math.asin(Math.sin(Math.atan(i * (1.0f / 256.0f))) * ir));
+ refractionMap[i] = (int) Math.floor(d * (1 << 16) + 0.5f);
+ }
+ mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
+ mRefractionMap.data(refractionMap);
+ }
+
+ private void createRippleMap(int rippleMapSize) {
+ final int[] rippleMap = new int[rippleMapSize * 2];
+ mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ private void createLeaf(float[] leaves, int index) {
+ int sprite = random(LEAVES_TEXTURES_COUNT);
+ //noinspection PointlessArithmeticExpression
+ leaves[index + LEAF_STRUCT_X] = random(-1.0f, 1.0f);
+ leaves[index + LEAF_STRUCT_Y] = random(-mGlHeight / 2.0f, mGlHeight / 2.0f);
+ leaves[index + LEAF_STRUCT_SCALE] = random(0.4f, 0.5f);
+ leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, 360.0f);
+ leaves[index + LEAF_STRUCT_SPIN] = degrees(random(-0.02f, 0.02f)) / 4.0f;
+ leaves[index + LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+ 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;
+ }
+
+ private void loadTextures() {
+ mTextures = new Allocation[TEXTURES_COUNT];
+
+ final Allocation[] textures = mTextures;
+ textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
+ textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
+
+ final int count = textures.length;
+ for (int i = 0; i < count; i++) {
+ final Allocation texture = textures[i];
+ texture.uploadToTexture(0);
+ }
+ }
+
+ private Allocation loadTexture(int id, String name) {
+ final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
+ id, RGB_565, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private Allocation loadTextureARGB(int id, String name) {
+ Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
+ final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private void createProgramFragment() {
+ Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
+ sampleBuilder.setMin(LINEAR);
+ sampleBuilder.setMag(LINEAR);
+ sampleBuilder.setWrapS(CLAMP);
+ sampleBuilder.setWrapT(CLAMP);
+ mSampler = 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);
+
+ builder = new ProgramFragment.Builder(mRS, null, null);
+ builder.setTexEnable(false, 0);
+ mPfLighting = builder.create();
+ mPfLighting.setName("PFLighting");
+ mPfLighting.bindSampler(mSampler, 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);
+ }
+
+ 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.setDepthMask(true);
+ mPfsBackground = builder.create();
+ mPfsBackground.setName("PFSBackground");
+
+ builder = new ProgramStore.Builder(mRS, null, null);
+ builder.setDepthFunc(ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ builder.setDitherEnable(true);
+ builder.setDepthMask(true);
+ mPfsLeaf = builder.create();
+ mPfsLeaf.setName("PFSLeaf");
+ }
+
+ private void createProgramVertex() {
+ mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
+
+ mLight = new Light.Builder(mRS).create();
+ mLight.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 = new ProgramVertex.Builder(mRS, null, null);
+ mPvLines = builder.create();
+ mPvLines.bindAllocation(mPvOrthoAlloc);
+ mPvLines.setName("PVLines");
+ }
+
+ 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 });
+ }
+}
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
new file mode 100644
index 0000000..d7573be
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
@@ -0,0 +1,73 @@
+/*
+ * 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 com.android.fall.rs;
+
+import android.content.Context;
+import android.view.SurfaceHolder;
+import android.view.MotionEvent;
+import android.view.KeyEvent;
+import android.renderscript.RenderScript;
+import android.renderscript.RSSurfaceView;
+
+class FallView extends RSSurfaceView {
+ private FallRS mRender;
+
+ public FallView(Context context) {
+ super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ RenderScript RS = createRenderScript();
+ 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:
+ case MotionEvent.ACTION_MOVE:
+ mRender.addDrop(event.getX(), event.getY());
+ try {
+ Thread.sleep(16);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ break;
+ }
+ return true;
+ }
+}
diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Film/Android.mk
new file mode 100644
index 0000000..b7f98fc
--- /dev/null
+++ b/libs/rs/java/Film/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Film
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Film/AndroidManifest.xml b/libs/rs/java/Film/AndroidManifest.xml
new file mode 100644
index 0000000..a5ce8a1
--- /dev/null
+++ b/libs/rs/java/Film/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.film">
+ <application android:label="Film">
+ <activity android:name="Film"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Film/res/drawable/p01.png b/libs/rs/java/Film/res/drawable/p01.png
new file mode 100644
index 0000000..a9b9bdb
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p01.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p02.png b/libs/rs/java/Film/res/drawable/p02.png
new file mode 100644
index 0000000..8162c82
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p02.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p03.png b/libs/rs/java/Film/res/drawable/p03.png
new file mode 100644
index 0000000..e3e26c0
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p03.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p04.png b/libs/rs/java/Film/res/drawable/p04.png
new file mode 100644
index 0000000..daee603
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p04.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p05.png b/libs/rs/java/Film/res/drawable/p05.png
new file mode 100644
index 0000000..fac5248
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p05.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p06.png b/libs/rs/java/Film/res/drawable/p06.png
new file mode 100644
index 0000000..3b51261
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p06.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p07.png b/libs/rs/java/Film/res/drawable/p07.png
new file mode 100644
index 0000000..d8bd938
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p07.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p08.png b/libs/rs/java/Film/res/drawable/p08.png
new file mode 100644
index 0000000..ef175e8
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p08.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p09.png b/libs/rs/java/Film/res/drawable/p09.png
new file mode 100644
index 0000000..7bf3874
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p09.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p10.png b/libs/rs/java/Film/res/drawable/p10.png
new file mode 100644
index 0000000..908827d
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p10.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p11.png b/libs/rs/java/Film/res/drawable/p11.png
new file mode 100644
index 0000000..1289f71
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p11.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p12.png b/libs/rs/java/Film/res/drawable/p12.png
new file mode 100644
index 0000000..e1af16a
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p12.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p13.png b/libs/rs/java/Film/res/drawable/p13.png
new file mode 100644
index 0000000..d08bcbe
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p13.png
Binary files differ
diff --git a/libs/rs/java/Film/res/raw/filmimage.c b/libs/rs/java/Film/res/raw/filmimage.c
new file mode 100644
index 0000000..3bd9496
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmimage.c
@@ -0,0 +1,110 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(orthoWindow)
+#pragma stateRaster(flat)
+#pragma stateFragment(PgmFragBackground)
+#pragma stateFragmentStore(MyBlend)
+
+
+int main(void* con, int ft, int launchID) {
+ int count, touch, x, y, rate, maxLife, lifeShift;
+ int life;
+ int ct, ct2;
+ int newPart;
+ int drawCount;
+ int dx, dy, idx;
+ int posx,posy;
+ int c;
+ int srcIdx;
+ int dstIdx;
+
+ count = loadI32(con, 0, 1);
+ touch = loadI32(con, 0, 2);
+ x = loadI32(con, 0, 3);
+ y = loadI32(con, 0, 4);
+
+ rate = 4;
+ maxLife = (count / rate) - 1;
+ lifeShift = 0;
+ {
+ life = maxLife;
+ while (life > 255) {
+ life = life >> 1;
+ lifeShift ++;
+ }
+ }
+
+ drawRect(con, 0, 256, 0, 512);
+ contextBindProgramFragment(con, NAMED_PgmFragParts);
+
+ if (touch) {
+ newPart = loadI32(con, 2, 0);
+ for (ct2=0; ct2<rate; ct2++) {
+ dx = scriptRand(con, 0x10000) - 0x8000;
+ dy = scriptRand(con, 0x10000) - 0x8000;
+
+ idx = newPart * 5 + 1;
+ storeI32(con, 2, idx, dx);
+ storeI32(con, 2, idx + 1, dy);
+ storeI32(con, 2, idx + 2, maxLife);
+ storeI32(con, 2, idx + 3, x << 16);
+ storeI32(con, 2, idx + 4, y << 16);
+
+ newPart++;
+ if (newPart >= count) {
+ newPart = 0;
+ }
+ }
+ storeI32(con, 2, 0, newPart);
+ }
+
+ drawCount = 0;
+ for (ct=0; ct < count; ct++) {
+ srcIdx = ct * 5 + 1;
+
+ dx = loadI32(con, 2, srcIdx);
+ dy = loadI32(con, 2, srcIdx + 1);
+ life = loadI32(con, 2, srcIdx + 2);
+ posx = loadI32(con, 2, srcIdx + 3);
+ posy = loadI32(con, 2, srcIdx + 4);
+
+ if (life) {
+ if (posy < (480 << 16)) {
+ dstIdx = drawCount * 9;
+ c = 0xffafcf | ((life >> lifeShift) << 24);
+
+ storeU32(con, 1, dstIdx, c);
+ storeI32(con, 1, dstIdx + 1, posx);
+ storeI32(con, 1, dstIdx + 2, posy);
+
+ storeU32(con, 1, dstIdx + 3, c);
+ storeI32(con, 1, dstIdx + 4, posx + 0x10000);
+ storeI32(con, 1, dstIdx + 5, posy + dy * 4);
+
+ storeU32(con, 1, dstIdx + 6, c);
+ storeI32(con, 1, dstIdx + 7, posx - 0x10000);
+ storeI32(con, 1, dstIdx + 8, posy + dy * 4);
+ drawCount ++;
+ } else {
+ if (dy > 0) {
+ dy = (-dy) >> 1;
+ }
+ }
+
+ posx = posx + dx;
+ posy = posy + dy;
+ dy = dy + 0x400;
+ life --;
+
+ //storeI32(con, 2, srcIdx, dx);
+ storeI32(con, 2, srcIdx + 1, dy);
+ storeI32(con, 2, srcIdx + 2, life);
+ storeI32(con, 2, srcIdx + 3, posx);
+ storeI32(con, 2, srcIdx + 4, posy);
+ }
+ }
+
+ drawTriangleArray(con, NAMED_PartBuffer, drawCount);
+ return 1;
+}
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
new file mode 100644
index 0000000..255d908
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -0,0 +1,106 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(PVBackground)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PSBackground)
+
+#define POS_TRANSLATE 0
+#define POS_ROTATE 1
+#define POS_FOCUS 2
+
+#define STATE_TRIANGLE_OFFSET_COUNT 0
+#define STATE_LAST_FOCUS 1
+
+
+// The script enviroment has 3 env allocations.
+// bank0: (r) The enviroment structure
+// bank1: (r) The position information
+// bank2: (rw) The temporary texture state
+
+int main(int index)
+{
+ float mat1[16];
+
+ float trans = Pos_translate;
+ float rot = Pos_rotate;
+ matrixLoadScale(mat1, 2.f, 2.f, 2.f);
+ matrixTranslate(mat1, 0.f, 0.f, trans);
+ matrixRotate(mat1, 90.f, 0.f, 0.f, 1.f);
+ matrixRotate(mat1, rot, 1.f, 0.f, 0.f);
+ storeMatrix(3, 0, mat1);
+
+ // Draw the lighting effect in the strip and fill the Z buffer.
+ drawTriangleMesh(NAMED_mesh);
+
+
+ // Start of images.
+ bindProgramFragmentStore(NAMED_PSImages);
+ bindProgramFragment(NAMED_PFImages);
+ bindProgramVertex(NAMED_PVImages);
+
+ float focusPos = Pos_focus;
+ int focusID = 0;
+ int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
+ int imgCount = 13;
+
+ if (trans > (-.3f)) {
+ focusID = -1.0f - focusPos;
+ if (focusID >= imgCount) {
+ focusID = -1;
+ }
+ } else {
+ focusID = -1;
+ }
+
+ /*
+ if (focusID != lastFocusID) {
+ if (lastFocusID >= 0) {
+ uploadToTexture(con, env->tex[lastFocusID], 1);
+ }
+ if (focusID >= 0) {
+ uploadToTexture(con, env->tex[focusID], 0);
+ }
+ }
+ */
+ storeI32(2, STATE_LAST_FOCUS, focusID);
+
+ int triangleOffsetsCount = Pos_triangleOffsetCount;
+
+ int imgId = 0;
+ for (imgId=1; imgId <= imgCount; imgId++) {
+ float pos = focusPos + imgId + 0.4f;
+ int offset = (int)floorf(pos * 2.f);
+ pos = pos - 0.75f;
+
+ offset = offset + triangleOffsetsCount / 2;
+
+ int drawit = 1;
+ if (offset < 0) {
+ drawit = 0;
+ }
+ if (offset >= triangleOffsetsCount) {
+ drawit = 0;
+ }
+
+ //if (!((offset < 0) || (offset >= triangleOffsetsCount))) {
+ if (drawit) {
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > triangleOffsetsCount) {
+ end = triangleOffsetsCount;
+ }
+
+ bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1));
+ matrixLoadTranslate(mat1, -pos - loadF(5, triangleOffsetsCount / 2), 0, 0);
+ vpLoadTextureMatrix(mat1);
+ drawTriangleMeshRange(NAMED_mesh, loadI32(4, start), loadI32(4, end) - loadI32(4, start));
+ }
+ }
+ return 0;
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/Film.java b/libs/rs/java/Film/src/com/android/film/Film.java
new file mode 100644
index 0000000..6e99816
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/Film.java
@@ -0,0 +1,90 @@
+/*
+ * 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.film;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Film extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private FilmView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FilmView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
new file mode 100644
index 0000000..e6cd52d
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -0,0 +1,264 @@
+/*
+ * 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.film;
+
+import java.io.Writer;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import android.renderscript.*;
+
+public class FilmRS {
+ class StripPosition {
+ public float translate;
+ public float rotate;
+ public float focus;
+ public int triangleOffsetCount;
+ }
+ StripPosition mPos = new StripPosition();
+
+
+ private final int STATE_LAST_FOCUS = 1;
+
+ public FilmRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void setFilmStripPosition(int x, int y)
+ {
+ if (x < 50) {
+ x = 50;
+ }
+ if (x > 270) {
+ x = 270;
+ }
+
+ float anim = ((float)x-50) / 270.f;
+ mPos.translate = 2f * anim + 0.5f; // translation
+ mPos.rotate = (anim * 40); // rotation
+ mPos.focus = ((float)y) / 16.f - 10.f; // focusPos
+ mPos.triangleOffsetCount = mFSM.mTriangleOffsetsCount;
+ mAllocPos.data(mPos);
+ }
+
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private Script mScriptStrip;
+ private Script mScriptImage;
+ private Element mElementVertex;
+ private Element mElementIndex;
+ private Sampler mSampler;
+ private ProgramStore mPSBackground;
+ private ProgramStore mPSImages;
+ private ProgramFragment mPFBackground;
+ private ProgramFragment mPFImages;
+ private ProgramVertex mPVBackground;
+ private ProgramVertex mPVImages;
+ private ProgramVertex.MatrixAllocation mPVA;
+ private Type mStripPositionType;
+
+ private Allocation mImages[];
+ private Allocation mAllocIDs;
+ private Allocation mAllocPos;
+ private Allocation mAllocState;
+ private Allocation mAllocPV;
+ private Allocation mAllocOffsetsTex;
+ private Allocation mAllocOffsets;
+
+ private RenderScript.TriangleMesh mMesh;
+ private Light mLight;
+
+ private FilmStripMesh mFSM;
+
+ private int[] mBufferIDs;
+ private float[] mBufferPos = new float[3];
+ private int[] mBufferState;
+
+ private void initPFS() {
+ ProgramStore.Builder b = new ProgramStore.Builder(mRS, null, null);
+
+ b.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ b.setDitherEnable(true);
+ b.setDepthMask(true);
+ mPSBackground = b.create();
+ mPSBackground.setName("PSBackground");
+
+ b.setDepthFunc(ProgramStore.DepthFunc.EQUAL);
+ b.setDitherEnable(false);
+ b.setDepthMask(false);
+ b.setBlendFunc(ProgramStore.BlendSrcFunc.ONE,
+ ProgramStore.BlendDstFunc.ONE);
+ mPSImages = b.create();
+ mPSImages.setName("PSImages");
+ }
+
+ private void initPF() {
+ Sampler.Builder bs = new Sampler.Builder(mRS);
+ bs.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
+ bs.setMag(Sampler.Value.LINEAR);
+ bs.setWrapS(Sampler.Value.CLAMP);
+ bs.setWrapT(Sampler.Value.WRAP);
+ mSampler = bs.create();
+
+ ProgramFragment.Builder b = new ProgramFragment.Builder(mRS, null, null);
+
+ mPFBackground = b.create();
+ mPFBackground.setName("PFBackground");
+
+ b.setTexEnable(true, 0);
+ b.setTexEnvMode(ProgramFragment.EnvMode.REPLACE, 0);
+ mPFImages = b.create();
+ mPFImages.bindSampler(mSampler, 0);
+ mPFImages.setName("PFImages");
+ }
+
+ private void initPV() {
+ mLight = (new Light.Builder(mRS)).create();
+ mLight.setPosition(0, -0.5f, -1.0f);
+
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ pvb.addLight(mLight);
+ mPVBackground = pvb.create();
+ mPVBackground.setName("PVBackground");
+
+ pvb = new ProgramVertex.Builder(mRS, null, null);
+ pvb.setTextureMatrixEnable(true);
+ mPVImages = pvb.create();
+ mPVImages.setName("PVImages");
+ }
+
+ private void loadImages() {
+ mBufferIDs = new int[13];
+ mImages = new Allocation[13];
+ mAllocIDs = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mBufferIDs.length);
+
+ Element ie = Element.RGB_565;
+ mImages[0] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p01, ie, true);
+ mImages[1] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p02, ie, true);
+ mImages[2] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p03, ie, true);
+ mImages[3] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p04, ie, true);
+ mImages[4] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p05, ie, true);
+ mImages[5] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p06, ie, true);
+ mImages[6] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p07, ie, true);
+ mImages[7] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p08, ie, true);
+ mImages[8] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p09, ie, true);
+ mImages[9] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p10, ie, true);
+ mImages[10] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p11, ie, true);
+ mImages[11] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p12, ie, true);
+ mImages[12] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p13, ie, true);
+
+ int black[] = new int[1024];
+ for(int ct=0; ct < mImages.length; ct++) {
+ Allocation.Adapter2D a = mImages[ct].createAdapter2D();
+
+ int size = 512;
+ int mip = 0;
+ while(size >= 2) {
+ a.subData(0, 0, 2, size, black);
+ a.subData(size-2, 0, 2, size, black);
+ a.subData(0, 0, size, 2, black);
+ a.subData(0, size-2, size, 2, black);
+ size >>= 1;
+ mip++;
+ a.setConstraint(Dimension.LOD, mip);
+ }
+ a.destroy();
+
+ mImages[ct].uploadToTexture(1);
+ mBufferIDs[ct] = mImages[ct].getID();
+ }
+ mAllocIDs.data(mBufferIDs);
+ }
+
+ private void initState()
+ {
+ mBufferState = new int[10];
+ mAllocState = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mBufferState.length);
+ mBufferState[STATE_LAST_FOCUS] = -1;
+ mAllocState.data(mBufferState);
+ }
+
+ private void initRS() {
+ mElementVertex = Element.NORM_ST_XYZ_F32;
+ mElementIndex = Element.INDEX_16;
+
+ mRS.triangleMeshBegin(mElementVertex, mElementIndex);
+ mFSM = new FilmStripMesh();
+ mFSM.init(mRS);
+ mMesh = mRS.triangleMeshCreate();
+ mMesh.setName("mesh");
+
+ initPFS();
+ initPF();
+ initPV();
+
+ Log.e("rs", "Done loading named");
+
+ mStripPositionType = Type.createFromClass(mRS, StripPosition.class, 1);
+
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setScript(mRes, R.raw.filmstrip);
+ sb.setRoot(true);
+ sb.setType(mStripPositionType, "Pos", 1);
+ mScriptStrip = sb.create();
+ mScriptStrip.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ mAllocPos = Allocation.createTyped(mRS, mStripPositionType);
+
+ loadImages();
+ initState();
+
+ mPVA = new ProgramVertex.MatrixAllocation(mRS);
+ mPVBackground.bindAllocation(mPVA);
+ mPVImages.bindAllocation(mPVA);
+ mPVA.setupProjectionNormalized(320, 480);
+
+
+ mScriptStrip.bindAllocation(mAllocIDs, 0);
+ mScriptStrip.bindAllocation(mAllocPos, 1);
+ mScriptStrip.bindAllocation(mAllocState, 2);
+ mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
+
+
+ mAllocOffsets = Allocation.createSized(mRS,
+ Element.USER_I32, mFSM.mTriangleOffsets.length);
+ mAllocOffsets.data(mFSM.mTriangleOffsets);
+ mScriptStrip.bindAllocation(mAllocOffsets, 4);
+
+ mAllocOffsetsTex = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mFSM.mTriangleOffsetsTex.length);
+ mAllocOffsetsTex.data(mFSM.mTriangleOffsetsTex);
+ mScriptStrip.bindAllocation(mAllocOffsetsTex, 5);
+
+ setFilmStripPosition(0, 0);
+ mRS.contextBindRootScript(mScriptStrip);
+ }
+}
+
+
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
new file mode 100644
index 0000000..02bffd8
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
@@ -0,0 +1,255 @@
+/*
+ * 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 com.android.film;
+
+import java.io.Writer;
+import java.lang.Math;
+import android.util.Log;
+
+import android.renderscript.RenderScript;
+
+
+class FilmStripMesh {
+
+ class Vertex {
+ float nx;
+ float ny;
+ float nz;
+ float s;
+ float t;
+ float x;
+ float y;
+ float z;
+
+ Vertex() {
+ nx = 0;
+ ny = 0;
+ nz = 0;
+ s = 0;
+ t = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ void xyz(float _x, float _y, float _z) {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void nxyz(float _x, float _y, float _z) {
+ nx = _x;
+ ny = _y;
+ nz = _z;
+ }
+
+ void st(float _s, float _t) {
+ s = _s;
+ t = _t;
+ }
+
+ void computeNorm(Vertex v1, Vertex v2) {
+ float dx = v1.x - v2.x;
+ float dy = v1.y - v2.y;
+ float dz = v1.z - v2.z;
+ float len = (float)java.lang.Math.sqrt(dx*dx + dy*dy + dz*dz);
+ dx /= len;
+ dy /= len;
+ dz /= len;
+
+ nx = dx * dz;
+ ny = dy * dz;
+ nz = (float)java.lang.Math.sqrt(dx*dx + dy*dy);
+
+ len = (float)java.lang.Math.sqrt(nx*nx + ny*ny + nz*nz);
+ nx /= len;
+ ny /= len;
+ nz /= len;
+ }
+
+ void addToRS(RenderScript rs) {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(x, y, z, s, t, nx, ny, nz);
+ }
+ }
+
+ int[] mTriangleOffsets;
+ float[] mTriangleOffsetsTex;
+ int mTriangleOffsetsCount;
+
+ void init(RenderScript rs)
+ {
+ float vtx[] = new float[] {
+ 60.431003f, 124.482050f,
+ 60.862074f, 120.872604f,
+ 61.705303f, 117.336662f,
+ 62.949505f, 113.921127f,
+ 64.578177f, 110.671304f,
+ 66.569716f, 107.630302f,
+ 68.897703f, 104.838457f,
+ 71.531259f, 102.332803f,
+ 74.435452f, 100.146577f,
+ 77.571757f, 98.308777f,
+ 80.898574f, 96.843781f,
+ 84.371773f, 95.771023f,
+ 87.945283f, 95.104731f,
+ 98.958994f, 95.267098f,
+ 109.489523f, 98.497596f,
+ 118.699582f, 104.539366f,
+ 125.856872f, 112.912022f,
+ 130.392311f, 122.949849f,
+ 131.945283f, 133.854731f,
+ 130.392311f, 144.759613f,
+ 125.856872f, 154.797439f,
+ 118.699582f, 163.170096f,
+ 109.489523f, 169.211866f,
+ 98.958994f, 172.442364f,
+ 87.945283f, 172.604731f,
+ 72.507313f, 172.672927f,
+ 57.678920f, 168.377071f,
+ 44.668135f, 160.067134f,
+ 34.534908f, 148.420104f,
+ 28.104767f, 134.384831f,
+ 25.901557f, 119.104731f,
+ 28.104767f, 103.824631f,
+ 34.534908f, 89.789358f,
+ 44.668135f, 78.142327f,
+ 57.678920f, 69.832390f,
+ 72.507313f, 65.536534f,
+ 87.945283f, 65.604731f,
+ 106.918117f, 65.688542f,
+ 125.141795f, 60.409056f,
+ 141.131686f, 50.196376f,
+ 153.585137f, 35.882502f,
+ 161.487600f, 18.633545f,
+ 164.195283f, -0.145269f,
+ 161.487600f, -18.924084f,
+ 153.585137f, -36.173040f,
+ 141.131686f, -50.486914f,
+ 125.141795f, -60.699594f,
+ 106.918117f, -65.979081f,
+ 87.945283f, -65.895269f,
+ 80f, -65.895269f,
+ 60f, -65.895269f,
+ 40f, -65.895269f,
+ 20f, -65.895269f,
+ 0f, -65.895269f,
+ -20f, -65.895269f,
+ -40f, -65.895269f,
+ -60f, -65.895269f,
+ -80f, -65.895269f,
+ -87.945283f, -65.895269f,
+ -106.918117f, -65.979081f,
+ -125.141795f, -60.699594f,
+ -141.131686f, -50.486914f,
+ -153.585137f, -36.173040f,
+ -161.487600f, -18.924084f,
+ -164.195283f, -0.145269f,
+ -161.487600f, 18.633545f,
+ -153.585137f, 35.882502f,
+ -141.131686f, 50.196376f,
+ -125.141795f, 60.409056f,
+ -106.918117f, 65.688542f,
+ -87.945283f, 65.604731f,
+ -72.507313f, 65.536534f,
+ -57.678920f, 69.832390f,
+ -44.668135f, 78.142327f,
+ -34.534908f, 89.789358f,
+ -28.104767f, 103.824631f,
+ -25.901557f, 119.104731f,
+ -28.104767f, 134.384831f,
+ -34.534908f, 148.420104f,
+ -44.668135f, 160.067134f,
+ -57.678920f, 168.377071f,
+ -72.507313f, 172.672927f,
+ -87.945283f, 172.604731f,
+ -98.958994f, 172.442364f,
+ -109.489523f, 169.211866f,
+ -118.699582f, 163.170096f,
+ -125.856872f, 154.797439f,
+ -130.392311f, 144.759613f,
+ -131.945283f, 133.854731f,
+ -130.392311f, 122.949849f,
+ -125.856872f, 112.912022f,
+ -118.699582f, 104.539366f,
+ -109.489523f, 98.497596f,
+ -98.958994f, 95.267098f,
+ -87.945283f, 95.104731f,
+ -84.371773f, 95.771023f,
+ -80.898574f, 96.843781f,
+ -77.571757f, 98.308777f,
+ -74.435452f, 100.146577f,
+ -71.531259f, 102.332803f,
+ -68.897703f, 104.838457f,
+ -66.569716f, 107.630302f,
+ -64.578177f, 110.671304f,
+ -62.949505f, 113.921127f,
+ -61.705303f, 117.336662f,
+ -60.862074f, 120.872604f,
+ -60.431003f, 124.482050f
+ };
+
+
+ mTriangleOffsets = new int[64];
+ mTriangleOffsetsTex = new float[64];
+
+ mTriangleOffsets[0] = 0;
+ mTriangleOffsetsCount = 1;
+
+ Vertex t = new Vertex();
+ t.nxyz(1, 0, 0);
+ int count = vtx.length / 2;
+
+ float runningS = 0;
+ for (int ct=0; ct < (count-1); ct++) {
+ t.x = -vtx[ct*2] / 100.f;
+ t.z = vtx[ct*2+1] / 100.f;
+ t.s = runningS;
+ t.nx = (vtx[ct*2+3] - vtx[ct*2 +1]);
+ t.ny = (vtx[ct*2+2] - vtx[ct*2 ]);
+ float len = (float)java.lang.Math.sqrt(t.nx * t.nx + t.ny * t.ny);
+ runningS += len / 100;
+ t.nx /= len;
+ t.ny /= len;
+ t.y = -0.5f;
+ t.t = 0;
+ //Log.e("xx", "vtx " + t.x + " " + t.y + " " + t.z);
+ t.addToRS(rs);
+ t.y = .5f;
+ t.t = 1;
+ t.addToRS(rs);
+
+ //LOGE(" %f", runningS);
+ if((runningS*2) > mTriangleOffsetsCount) {
+ //LOGE("**** img %i %i", gTriangleOffsetsCount, ct*2);
+ mTriangleOffsets[mTriangleOffsetsCount] = ct*2;
+ mTriangleOffsetsTex[mTriangleOffsetsCount] = t.s;
+ mTriangleOffsetsCount ++;
+ }
+ }
+
+ count = (count * 2 - 2);
+ for (int ct=0; ct < (count-2); ct+= 2) {
+ rs.triangleMeshAddTriangle(ct, ct+1, ct+2);
+ rs.triangleMeshAddTriangle(ct+1, ct+3, ct+2);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java
new file mode 100644
index 0000000..73b7414
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmView.java
@@ -0,0 +1,82 @@
+/*
+ * 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.film;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FilmView extends RSSurfaceView {
+
+ public FilmView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private FilmRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new FilmRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+ mRender.setFilmStripPosition((int)ev.getX(), (int)ev.getY() / 5);
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk
new file mode 100644
index 0000000..b6a9f10
--- /dev/null
+++ b/libs/rs/java/Fountain/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Fountain
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..dd0e428
--- /dev/null
+++ b/libs/rs/java/Fountain/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.fountain">
+ <application android:label="Fountain">
+ <activity android:name="Fountain"
+ android:theme="@android:style/Theme.Translucent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
new file mode 100755
index 0000000..e91bfb4
--- /dev/null
+++ b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
Binary files differ
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
new file mode 100644
index 0000000..e7804a5
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -0,0 +1,52 @@
+// Fountain test script
+#pragma version(1)
+#pragma stateVertex(default)
+#pragma stateFragment(default)
+#pragma stateFragmentStore(default)
+
+int main(int launchID) {
+ int ct;
+ int count = Control_count - 1;
+ int rate = Control_rate;
+ float *dataF = loadArrayF(1, 0);
+ float height = getHeight();
+
+ if (rate) {
+ debugI32("rate", 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(1, count * 5, newPart);
+ }
+
+ for (ct=0; ct < count; ct++) {
+ 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;
+ }
+
+ uploadToBufferObject(NAMED_PartBuffer);
+ drawSimpleMeshRange(NAMED_PartMesh, 0, count);
+ return 1;
+}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
new file mode 100644
index 0000000..58c78fa
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
@@ -0,0 +1,90 @@
+/*
+ * 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.fountain;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Fountain extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private FountainView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FountainView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
new file mode 100644
index 0000000..da9eda8
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -0,0 +1,117 @@
+/*
+ * 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.fountain;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+
+public class FountainRS {
+ public static final int PART_COUNT = 20000;
+
+ static class SomeData {
+ public int x;
+ public int y;
+ public int rate;
+ public int count;
+ public float r;
+ public float g;
+ public float b;
+ }
+
+ public FountainRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ 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);
+ }
+
+
+ /////////////////////////////////////////
+
+ private Resources mRes;
+
+ private RenderScript mRS;
+ private Allocation mIntAlloc;
+ private Allocation mPartAlloc;
+ private Script mScript;
+ private SimpleMesh mSM;
+ 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);
+ mSD.count = PART_COUNT;
+ mIntAlloc.data(mSD);
+
+ Element.Builder eb = new Element.Builder(mRS);
+ 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);
+ smb.setPrimitive(Primitive.POINT);
+ mSM = smb.create();
+ mSM.setName("PartMesh");
+
+ mPartAlloc = mSM.createVertexAllocation(vtxSlot);
+ mPartAlloc.setName("PartBuffer");
+ mSM.bindVertexAllocation(mPartAlloc, 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, "Control", 0);
+ mScript = sb.create();
+ mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ mScript.bindAllocation(mIntAlloc, 0);
+ mScript.bindAllocation(mPartAlloc, 1);
+ mRS.contextBindRootScript(mScript);
+ }
+
+}
+
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
new file mode 100644
index 0000000..2768e2c
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -0,0 +1,79 @@
+/*
+ * 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.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FountainView extends RSSurfaceView {
+
+ public FountainView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private FountainRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new FountainRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0);
+ return false;
+ }
+ 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/Galaxy/Android.mk b/libs/rs/java/Galaxy/Android.mk
new file mode 100644
index 0000000..0884e18
--- /dev/null
+++ b/libs/rs/java/Galaxy/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := GalaxyRS
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Galaxy/AndroidManifest.xml b/libs/rs/java/Galaxy/AndroidManifest.xml
new file mode 100644
index 0000000..6da1e0f
--- /dev/null
+++ b/libs/rs/java/Galaxy/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.galaxy.rs">
+
+ <application android:label="GalaxyRS">
+
+ <activity
+ android:screenOrientation="portrait"
+ android:name="Galaxy"
+ android:theme="@android:style/Theme.NoTitleBar">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png b/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png
new file mode 100644
index 0000000..e1c7010
--- /dev/null
+++ b/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png
Binary files differ
diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png b/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png
new file mode 100644
index 0000000..4ffb1ee
--- /dev/null
+++ b/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png
Binary files differ
diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg b/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg
new file mode 100644
index 0000000..b61f6a3
--- /dev/null
+++ b/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg
Binary files differ
diff --git a/libs/rs/java/Galaxy/res/raw/galaxy.c b/libs/rs/java/Galaxy/res/raw/galaxy.c
new file mode 100644
index 0000000..8575712
--- /dev/null
+++ b/libs/rs/java/Galaxy/res/raw/galaxy.c
@@ -0,0 +1,132 @@
+// 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.
+
+#pragma version(1)
+#pragma stateVertex(PVBackground)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define RSID_PARTICLES 1
+
+#define PARTICLE_STRUCT_FIELDS_COUNT 4
+#define PARTICLE_STRUCT_ANGLE 0
+#define PARTICLE_STRUCT_DISTANCE 1
+#define PARTICLE_STRUCT_SPEED 2
+#define PARTICLE_STRUCT_RADIUS 3
+
+#define RSID_PARTICLES_BUFFER 2
+#define PARTICLE_BUFFER_COMPONENTS_COUNT 5
+
+#define PARTICLES_TEXTURES_COUNT 2
+
+#define ELLIPSE_RATIO 0.86f
+#define ELLIPSE_TWIST 0.02333333333f
+
+void drawSpace(int width, int height) {
+ bindTexture(NAMED_PFBackground, 0, NAMED_TSpace);
+ drawQuadTexCoords(
+ 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ width, 0.0f, 0.0f,
+ 2.0f, 1.0f,
+ width, height, 0.0f,
+ 2.0f, 0.0f,
+ 0.0f, height, 0.0f,
+ 0.0f, 0.0f);
+}
+
+void drawLights(int width, int height) {
+ float x = (width - 512.0f) / 2.0f;
+ float y = (height - 512.0f) / 2.0f;
+
+ bindProgramFragment(NAMED_PFBackground);
+ bindTexture(NAMED_PFBackground, 0, NAMED_TLight1);
+ drawQuad(x + 512.0f, y , 0.0f,
+ x , y , 0.0f,
+ x , y + 512.0f, 0.0f,
+ x + 512.0f, y + 512.0f, 0.0f);
+}
+
+void drawParticle(float *particle, int index, float *particleBuffer, int bufferIndex,
+ float w, float h) {
+
+ float distance = particle[index + PARTICLE_STRUCT_DISTANCE];
+ float angle = particle[index + PARTICLE_STRUCT_ANGLE];
+ float speed = particle[index + PARTICLE_STRUCT_SPEED];
+ float r = particle[index + PARTICLE_STRUCT_RADIUS];
+
+ float a = angle + speed;
+ float x = distance * sinf(a);
+ float y = distance * cosf(a) * ELLIPSE_RATIO;
+ float z = distance * ELLIPSE_TWIST;
+ float s = cosf(z);
+ float t = sinf(z);
+
+ float sX = t * x + s * y + w;
+ float sY = s * x - t * y + h;
+
+ // lower left vertex of the particle's triangle
+ particleBuffer[bufferIndex + 1] = sX - r; // X
+ particleBuffer[bufferIndex + 2] = sY + r; // Y
+
+ // lower right vertex of the particle's triangle
+ bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT;
+ particleBuffer[bufferIndex + 1] = sX + r; // X
+ particleBuffer[bufferIndex + 2] = sY + r; // Y
+
+ // upper middle vertex of the particle's triangle
+ bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT;
+ particleBuffer[bufferIndex + 1] = sX; // X
+ particleBuffer[bufferIndex + 2] = sY - r; // Y
+
+ particle[index + PARTICLE_STRUCT_ANGLE] = a;
+}
+
+void drawParticles(int width, int height) {
+ bindProgramFragment(NAMED_PFLighting);
+ bindProgramFragmentStore(NAMED_PFSLights);
+ bindTexture(NAMED_PFLighting, 0, NAMED_TFlares);
+
+ int radius = State_galaxyRadius;
+ int particlesCount = State_particlesCount;
+ int count = particlesCount * PARTICLE_STRUCT_FIELDS_COUNT;
+
+ float *particle = loadArrayF(RSID_PARTICLES, 0);
+ float *particleBuffer = loadArrayF(RSID_PARTICLES_BUFFER, 0);
+
+ float w = width * 0.5f;
+ float h = height * 0.5f;
+
+ int i = 0;
+ int bufferIndex = 0;
+ for ( ; i < count; i += PARTICLE_STRUCT_FIELDS_COUNT) {
+ drawParticle(particle, i, particleBuffer, bufferIndex, w, h);
+ // each particle is a triangle (3 vertices) of 6 properties (ABGR, X, Y, Z, S, T)
+ bufferIndex += 3 * PARTICLE_BUFFER_COMPONENTS_COUNT;
+ }
+
+ uploadToBufferObject(NAMED_ParticlesBuffer);
+ drawSimpleMeshRange(NAMED_ParticlesMesh, 0, particlesCount * 3);
+}
+
+int main(int index) {
+ int width = State_width;
+ int height = State_height;
+
+ drawSpace(width, height);
+ drawParticles(width, height);
+ drawLights(width, height);
+
+ return 1;
+}
diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java
new file mode 100644
index 0000000..27d333c
--- /dev/null
+++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.galaxy.rs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Galaxy extends Activity {
+ private GalaxyView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mView = new GalaxyView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+}
\ No newline at end of file
diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java
new file mode 100644
index 0000000..1b9e349
--- /dev/null
+++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java
@@ -0,0 +1,362 @@
+/*
+ * 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 com.android.galaxy.rs;
+
+import android.content.res.Resources;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Allocation;
+import android.renderscript.Sampler;
+import android.renderscript.Element;
+import android.renderscript.SimpleMesh;
+import android.renderscript.Primitive;
+import android.renderscript.Type;
+import static android.renderscript.Sampler.Value.LINEAR;
+import static android.renderscript.Sampler.Value.NEAREST;
+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;
+import static android.renderscript.ProgramFragment.EnvMode.*;
+import static android.renderscript.Element.*;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
+
+import java.util.TimeZone;
+
+class GalaxyRS {
+ private static final int GALAXY_RADIUS = 300;
+ private static final int PARTICLES_COUNT = 12000;
+
+ private static final int RSID_STATE = 0;
+
+ private static final int TEXTURES_COUNT = 3;
+ private static final int PARTICLES_TEXTURES_COUNT = 2;
+ private static final int RSID_TEXTURE_SPACE = 0;
+ private static final int RSID_TEXTURE_LIGHT1 = 1;
+ private static final int RSID_TEXTURE_FLARES = 2;
+
+ private static final int RSID_PARTICLES = 1;
+ private static final int PARTICLE_STRUCT_FIELDS_COUNT = 4;
+ private static final int PARTICLE_STRUCT_ANGLE = 0;
+ private static final int PARTICLE_STRUCT_DISTANCE = 1;
+ private static final int PARTICLE_STRUCT_SPEED = 2;
+ private static final int PARTICLE_STRUCT_RADIUS = 3;
+
+ private static final int RSID_PARTICLES_BUFFER = 2;
+
+ private Resources mResources;
+ private RenderScript mRS;
+
+ private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+ private final int mWidth;
+ private final int mHeight;
+
+ private ScriptC mScript;
+ private Sampler mSampler;
+ private Sampler mLightSampler;
+ private ProgramFragment mPfBackground;
+ private ProgramFragment mPfLighting;
+ private ProgramStore mPfsBackground;
+ private ProgramStore mPfsLights;
+ private ProgramVertex mPvBackground;
+ private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
+
+ private Allocation[] mTextures;
+
+ private Type mStateType;
+ private Allocation mState;
+ private Allocation mParticles;
+ private Allocation mParticlesBuffer;
+ private SimpleMesh mParticlesMesh;
+
+ private final float[] mFloatData5 = new float[5];
+
+ public GalaxyRS(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mOptionsARGB.inScaled = false;
+ mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ }
+
+ public void init(RenderScript rs, Resources res) {
+ mRS = rs;
+ mResources = res;
+ initRS();
+ }
+
+ public void destroy() {
+ mScript.destroy();
+ mSampler.destroy();
+ mLightSampler.destroy();
+ mPfBackground.destroy();
+ mPfsBackground.destroy();
+ mPvBackground.destroy();
+ mPvOrthoAlloc.mAlloc.destroy();
+ for (Allocation a : mTextures) {
+ a.destroy();
+ }
+ mState.destroy();
+ mPfLighting.destroy();
+ mParticles.destroy();
+ mPfsLights.destroy();
+ mParticlesMesh.destroy();
+ mParticlesBuffer.destroy();
+ mStateType.destroy();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void initRS() {
+ createProgramVertex();
+ createProgramFragmentStore();
+ createProgramFragment();
+ createScriptStructures();
+ loadTextures();
+
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setType(mStateType, "State", 0);
+ sb.setScript(mResources, R.raw.galaxy);
+ 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(mParticles, RSID_PARTICLES);
+ mScript.bindAllocation(mParticlesBuffer, RSID_PARTICLES_BUFFER);
+
+ mRS.contextBindRootScript(mScript);
+ }
+
+ private void createScriptStructures() {
+ createState();
+ createParticlesMesh();
+ createParticles();
+ }
+
+ private void createParticlesMesh() {
+ final Element.Builder elementBuilder = new Element.Builder(mRS);
+ elementBuilder.addUNorm8RGBA();
+ elementBuilder.addFloatXY();
+ elementBuilder.addFloatST();
+ final Element vertexElement = elementBuilder.create();
+
+ final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS);
+ final int vertexSlot = meshBuilder.addVertexType(vertexElement, PARTICLES_COUNT * 3);
+ meshBuilder.setPrimitive(Primitive.TRIANGLE);
+ mParticlesMesh = meshBuilder.create();
+ mParticlesMesh.setName("ParticlesMesh");
+
+ mParticlesBuffer = mParticlesMesh.createVertexAllocation(vertexSlot);
+ mParticlesBuffer.setName("ParticlesBuffer");
+ mParticlesMesh.bindVertexAllocation(mParticlesBuffer, 0);
+ }
+
+ static class GalaxyState {
+ public int frameCount;
+ public int width;
+ public int height;
+ public int particlesCount;
+ public int galaxyRadius;
+ }
+
+ private void createState() {
+ GalaxyState state = new GalaxyState();
+ state.width = mWidth;
+ state.height = mHeight;
+ state.particlesCount = PARTICLES_COUNT;
+ state.galaxyRadius = GALAXY_RADIUS;
+
+ mStateType = Type.createFromClass(mRS, GalaxyState.class, 1, "GalaxyState");
+ mState = Allocation.createTyped(mRS, mStateType);
+ mState.data(state);
+ }
+
+ private void createParticles() {
+ final float[] particles = new float[PARTICLES_COUNT * PARTICLE_STRUCT_FIELDS_COUNT];
+
+ int bufferIndex = 0;
+
+ for (int i = 0; i < particles.length; i += PARTICLE_STRUCT_FIELDS_COUNT) {
+ createParticle(particles, i, bufferIndex);
+ bufferIndex += 3;
+ }
+
+ mParticles = Allocation.createSized(mRS, USER_FLOAT, particles.length);
+ mParticles.data(particles);
+ }
+
+ @SuppressWarnings({"PointlessArithmeticExpression"})
+ private void createParticle(float[] particles, int index, int bufferIndex) {
+ float d = abs(randomGauss()) * GALAXY_RADIUS / 2.0f;
+
+ particles[index + PARTICLE_STRUCT_ANGLE] = random(0.0f, (float) (Math.PI * 2.0));
+ particles[index + PARTICLE_STRUCT_DISTANCE] = d;
+ particles[index + PARTICLE_STRUCT_SPEED] = random(0.0015f, 0.0025f) *
+ (0.5f + (0.5f * (float) GALAXY_RADIUS / d));
+ particles[index + PARTICLE_STRUCT_RADIUS] = random(1.0f, 2.1f);
+
+ int red, green, blue;
+ if (d < GALAXY_RADIUS / 3.0f) {
+ red = (int) (220 + (d / (float) GALAXY_RADIUS) * 35);
+ green = 220;
+ blue = 220;
+ } else {
+ red = 180;
+ green = 180;
+ blue = (int) constrain(140 + (d / (float) GALAXY_RADIUS) * 115, 140, 255);
+ }
+
+ final int color = 0xFF000000 | red | green << 8 | blue << 16;
+ final int sprite = random(PARTICLES_TEXTURES_COUNT);
+ final float u1 = sprite / (float) PARTICLES_TEXTURES_COUNT;
+ final float u2 = (sprite + 1) / (float) PARTICLES_TEXTURES_COUNT;
+
+ final float[] floatData = mFloatData5;
+ final Allocation buffer = mParticlesBuffer;
+
+ floatData[0] = Float.intBitsToFloat(color);
+ floatData[3] = u1;
+ floatData[4] = 1.0f;
+ buffer.subData1D(bufferIndex, 1, floatData);
+
+ bufferIndex++;
+ floatData[3] = u2;
+ floatData[4] = 1.0f;
+ buffer.subData1D(bufferIndex, 1, floatData);
+
+ bufferIndex++;
+ floatData[3] = u1 + (u2 - u1) / 2.0f;
+ floatData[4] = 0.0f;
+ buffer.subData1D(bufferIndex, 1, floatData);
+ }
+
+ private static float randomGauss() {
+ float x1;
+ float x2;
+ float w;
+
+ do {
+ x1 = 2.0f * random(0.0f, 1.0f) - 1.0f;
+ x2 = 2.0f * random(0.0f, 1.0f) - 1.0f;
+ w = x1 * x1 + x2 * x2;
+ } while (w >= 1.0f);
+
+ w = (float) Math.sqrt(-2.0 * log(w) / w);
+ return x1 * w;
+ }
+
+ private void loadTextures() {
+ mTextures = new Allocation[TEXTURES_COUNT];
+
+ final Allocation[] textures = mTextures;
+ textures[RSID_TEXTURE_SPACE] = loadTexture(R.drawable.space, "TSpace");
+ textures[RSID_TEXTURE_LIGHT1] = loadTextureARGB(R.drawable.light1, "TLight1");
+ textures[RSID_TEXTURE_FLARES] = loadTextureARGB(R.drawable.flares, "TFlares");
+
+ final int count = textures.length;
+ for (int i = 0; i < count; i++) {
+ final Allocation texture = textures[i];
+ texture.uploadToTexture(0);
+ }
+ }
+
+ private Allocation loadTexture(int id, String name) {
+ final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
+ id, RGB_565, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private Allocation loadTextureARGB(int id, String name) {
+ Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
+ final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private void createProgramFragment() {
+ Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
+ sampleBuilder.setMin(LINEAR);
+ sampleBuilder.setMag(LINEAR);
+ sampleBuilder.setWrapS(WRAP);
+ sampleBuilder.setWrapT(WRAP);
+ mSampler = 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);
+
+ sampleBuilder = new Sampler.Builder(mRS);
+ sampleBuilder.setMin(NEAREST);
+ sampleBuilder.setMag(NEAREST);
+ sampleBuilder.setWrapS(WRAP);
+ sampleBuilder.setWrapT(WRAP);
+ mLightSampler = sampleBuilder.create();
+
+ builder = new ProgramFragment.Builder(mRS, null, null);
+ builder.setTexEnable(true, 0);
+ builder.setTexEnvMode(MODULATE, 0);
+ mPfLighting = builder.create();
+ mPfLighting.setName("PFLighting");
+ mPfLighting.bindSampler(mLightSampler, 0);
+ }
+
+ private void createProgramFragmentStore() {
+ ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
+ builder.setDepthFunc(ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO);
+ builder.setDitherEnable(false);
+ mPfsBackground = builder.create();
+ mPfsBackground.setName("PFSBackground");
+
+ builder = new ProgramStore.Builder(mRS, null, null);
+ builder.setDepthFunc(ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+ builder.setDitherEnable(false);
+ mPfsLights = builder.create();
+ mPfsLights.setName("PFSLights");
+ }
+
+ private void createProgramVertex() {
+ mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ //mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
+ mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
+
+ ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
+ mPvBackground = builder.create();
+ mPvBackground.bindAllocation(mPvOrthoAlloc);
+ mPvBackground.setName("PVBackground");
+ }
+}
diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java
new file mode 100644
index 0000000..341293b
--- /dev/null
+++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.android.galaxy.rs;
+
+import android.content.Context;
+import android.view.SurfaceHolder;
+import android.renderscript.RenderScript;
+import android.renderscript.RSSurfaceView;
+
+class GalaxyView extends RSSurfaceView {
+ private GalaxyRS mRender;
+
+ public GalaxyView(Context context) {
+ super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ RenderScript RS = createRenderScript();
+ mRender = new GalaxyRS(w, h);
+ mRender.init(RS, getResources());
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ if (mRender != null) mRender.destroy();
+ }
+}
diff --git a/libs/rs/java/Rollo/Android.mk b/libs/rs/java/Rollo/Android.mk
new file mode 100644
index 0000000..5a4957c
--- /dev/null
+++ b/libs/rs/java/Rollo/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Rollo
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Rollo/AndroidManifest.xml b/libs/rs/java/Rollo/AndroidManifest.xml
new file mode 100644
index 0000000..127a140
--- /dev/null
+++ b/libs/rs/java/Rollo/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.rollo">
+ <application android:label="Rollo">
+ <activity android:name="Rollo"
+ android:theme="@android:style/Theme.Translucent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Rollo/res/raw/browser.png b/libs/rs/java/Rollo/res/raw/browser.png
new file mode 100644
index 0000000..513f0be
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/browser.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/calendar.png b/libs/rs/java/Rollo/res/raw/calendar.png
new file mode 100644
index 0000000..030ae73
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/calendar.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g1155.png b/libs/rs/java/Rollo/res/raw/g1155.png
new file mode 100644
index 0000000..68e1843
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g1155.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g2140.png b/libs/rs/java/Rollo/res/raw/g2140.png
new file mode 100644
index 0000000..8c4e853
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g2140.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/maps.png b/libs/rs/java/Rollo/res/raw/maps.png
new file mode 100644
index 0000000..fd5fc39
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/maps.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/market.png b/libs/rs/java/Rollo/res/raw/market.png
new file mode 100644
index 0000000..83b6910
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/market.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1920.png b/libs/rs/java/Rollo/res/raw/path1920.png
new file mode 100644
index 0000000..3510665
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1920.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1927.png b/libs/rs/java/Rollo/res/raw/path1927.png
new file mode 100644
index 0000000..fccc846
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1927.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3099.png b/libs/rs/java/Rollo/res/raw/path3099.png
new file mode 100644
index 0000000..527ebf6
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3099.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3950.png b/libs/rs/java/Rollo/res/raw/path3950.png
new file mode 100644
index 0000000..59a646a
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3950.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path431.png b/libs/rs/java/Rollo/res/raw/path431.png
new file mode 100644
index 0000000..5d2ed75
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path431.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path4481.png b/libs/rs/java/Rollo/res/raw/path4481.png
new file mode 100644
index 0000000..78be0fc
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path4481.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path5168.png b/libs/rs/java/Rollo/res/raw/path5168.png
new file mode 100644
index 0000000..a7c3a19
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path5168.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path676.png b/libs/rs/java/Rollo/res/raw/path676.png
new file mode 100644
index 0000000..2099690
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path676.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path754.png b/libs/rs/java/Rollo/res/raw/path754.png
new file mode 100644
index 0000000..88aed5b
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path754.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path815.png b/libs/rs/java/Rollo/res/raw/path815.png
new file mode 100644
index 0000000..407570f
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path815.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/photos.png b/libs/rs/java/Rollo/res/raw/photos.png
new file mode 100644
index 0000000..1ed8f1e
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/photos.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/polygon2408.png b/libs/rs/java/Rollo/res/raw/polygon2408.png
new file mode 100644
index 0000000..4413954
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/polygon2408.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
new file mode 100644
index 0000000..6376715
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -0,0 +1,184 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+
+float filter(float val, float target, float str)
+{
+ float delta = (target - val);
+ return val + delta * str;
+}
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int row;
+ int col;
+ int imageID;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+
+ float f = loadF(2, 0);
+
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ if (f > 0.02f) {
+ //f = f - 0.02f;
+ //storeF(2, 0, f);
+ }
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
+ }
+
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 4.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
+ targetRot = targetRot * 0.80f - .12f;
+ float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, drawRot);
+
+ float diam = 8.f;
+ float scale = 1.0f / zoom;
+
+ // Bug makes 1.0f alpha fail.
+ color(1.0f, 1.0f, 1.0f, 0.99f);
+
+ float rot = drawRot * scale;
+ float rotStep = 16.0f / 180.0f * 3.14f * scale;
+ rowCount = 4;
+ int index = 0;
+ int iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ float tmpSin = sinf(rot);
+ float tmpCos = cosf(rot);
+ //debugF("rot", rot);
+
+ float tx1 = tmpSin * diam - (tmpCos * scale * 0.9f);
+ float tx2 = tx1 + (tmpCos * scale * 1.8f);
+ float tz1 = tmpCos * diam + (tmpSin * scale * 0.9f);
+ float tz2 = tz1 - (tmpSin * scale * 1.8f);
+
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ float ty1 = ((y * 3.1f) - 5.f) * scale;
+ float ty2 = ty1 + scale * 1.8f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ if ((zoom < 1.1f) && (zoom > 0.9f)) {
+ bindProgramVertex(NAMED_PVOrtho);
+ bindProgramFragment(NAMED_PFText);
+ bindProgramFragmentStore(NAMED_PFSText);
+
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+
+ float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
+
+ float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
+ if (alpha > 0.99f) {
+ alpha = 0.99f;
+ }
+ alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
+
+ tx = tx + 0.25f;
+
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+
+ if (alpha > 0) {
+ color(1.0f, 1.0f, 1.0f, alpha);
+
+ float ty = 605.f - y * 150.f;
+
+ ty = ty + 0.25f;
+
+ bindTexture(NAMED_PFText, 0, loadI32(3, index));
+ drawRect(tx, ty, tx + 128.f, ty + 32.f, 0.5f);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+
+ bindProgramVertex(NAMED_PV);
+ bindProgramFragment(NAMED_PF);
+ bindProgramFragmentStore(NAMED_PFS);
+ }
+
+ // Draw the selected icon
+ color(1.0f, 1.0f, 1.0f, 0.9f);
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ if (index == selectedID) {
+
+ float tmpSin = sinf(rot) * scale;
+ float tmpCos = cosf(rot) * scale;
+ float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+ float tx2 = tx1 + (tmpCos * 4.f);
+ float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+ float tz2 = tz1 - (tmpSin * 4.f);
+
+ float ty1 = ((y * 3.1f) - 4.5f) * scale;
+ float ty2 = ty1 + scale * 4.f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ return 1;
+}
+
+
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
new file mode 100644
index 0000000..256fa3c
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -0,0 +1,155 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+float filter(float val, float target, float str)
+{
+ float delta = (target - val);
+ return val + delta * str;
+}
+
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int imageID;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+ int iconCount = loadI32(0, STATE_COUNT);
+
+ float f = loadF(2, 0);
+
+ float iconSize = 1.f;
+ float iconSpacing = 0.2f;
+ float z = 4.f;
+
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
+ }
+
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 5.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
+ float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, pos);
+ pos = pos - 1.f;
+
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+
+
+ // Draw flat icons first
+ int index = ((int)pos) * 4;
+ int row;
+ int col;
+ float xoffset = -0.3f;
+ float gridSize = iconSize * 4.f + iconSpacing * 3.f;
+ float yoffset = (pos - ((int)pos));
+ for (row = 0; row < 4; row ++) {
+ float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + iconSize;
+
+ for (col = 0; (col < 4) && (index < iconCount); col ++) {
+ if (index >= 0) {
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ float fcol = col;
+ float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ drawQuad(tx1, ty1, z,
+ tx2, ty1, z,
+ tx2, ty2, z,
+ tx1, ty2, z);
+ }
+ index++;
+ }
+ }
+
+ // bottom roller
+ {
+ float roll = (1.f - yoffset) * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
+ float ty1 = ty2 - tmpCos * iconSize;
+
+ float tz1 = z + tmpSin * iconSize;
+ float tz2 = z;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+ // Top roller
+ {
+ index = (((int)pos) * 4) - 4;
+ float roll = yoffset * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + tmpCos * iconSize;
+
+ float tz1 = z;
+ float tz2 = z + tmpSin * iconSize;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+
+
+
+ return 1;
+}
+
+
+
diff --git a/libs/rs/java/Rollo/res/raw/settings.png b/libs/rs/java/Rollo/res/raw/settings.png
new file mode 100644
index 0000000..dd2cd95
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/settings.png
Binary files differ
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
new file mode 100644
index 0000000..400d801
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
@@ -0,0 +1,90 @@
+/*
+ * 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.rollo;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Rollo extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private RolloView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new RolloView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
new file mode 100644
index 0000000..ba74b58
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -0,0 +1,315 @@
+/*
+ * 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.rollo;
+
+import java.io.Writer;
+
+import android.renderscript.RenderScript;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.renderscript.Allocation;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.Sampler;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.Typeface;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class RolloRS {
+ //public static final int STATE_SELECTED_ID = 0;
+ public static final int STATE_DONE = 1;
+ //public static final int STATE_PRESSURE = 2;
+ public static final int STATE_ZOOM = 3;
+ //public static final int STATE_WARP = 4;
+ public static final int STATE_ORIENTATION = 5;
+ public static final int STATE_SELECTION = 6;
+ public static final int STATE_FIRST_VISIBLE = 7;
+ public static final int STATE_COUNT = 8;
+ public static final int STATE_TOUCH = 9;
+
+
+ public RolloRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+ initNamed();
+ initRS();
+ }
+
+ public void setPosition(float column) {
+ mAllocStateBuf[STATE_FIRST_VISIBLE] = (int)(column * (-20));
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setTouch(boolean touch) {
+ mAllocStateBuf[STATE_TOUCH] = touch ? 1 : 0;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setZoom(float z) {
+ //Log.e("rs", "zoom " + Float.toString(z));
+
+ mAllocStateBuf[STATE_ZOOM] = (int)(z * 1000.f);
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setSelected(int index) {
+ //Log.e("rs", "setSelected " + Integer.toString(index));
+
+ mAllocStateBuf[STATE_SELECTION] = index;
+ mAllocStateBuf[STATE_DONE] = 1;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ private int mWidth;
+ private int mHeight;
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private Script mScript;
+ private Sampler mSampler;
+ private Sampler mSamplerText;
+ private ProgramStore mPSBackground;
+ private ProgramStore mPSText;
+ private ProgramFragment mPFImages;
+ private ProgramFragment mPFText;
+ private ProgramVertex mPV;
+ private ProgramVertex.MatrixAllocation mPVAlloc;
+ private ProgramVertex mPVOrtho;
+ private ProgramVertex.MatrixAllocation mPVOrthoAlloc;
+ private Allocation[] mIcons;
+ private Allocation[] mLabels;
+
+ private int[] mAllocStateBuf;
+ private Allocation mAllocState;
+
+ private int[] mAllocIconIDBuf;
+ private Allocation mAllocIconID;
+
+ private int[] mAllocLabelIDBuf;
+ private Allocation mAllocLabelID;
+
+ private int[] mAllocScratchBuf;
+ private Allocation mAllocScratch;
+
+ private void initNamed() {
+ Sampler.Builder sb = new Sampler.Builder(mRS);
+ sb.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
+ sb.setMag(Sampler.Value.LINEAR);
+ sb.setWrapS(Sampler.Value.CLAMP);
+ sb.setWrapT(Sampler.Value.CLAMP);
+ mSampler = sb.create();
+
+ sb.setMin(Sampler.Value.NEAREST);
+ sb.setMag(Sampler.Value.NEAREST);
+ mSamplerText = sb.create();
+
+
+ ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null);
+ bf.setTexEnable(true, 0);
+ bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
+ mPFImages = bf.create();
+ mPFImages.setName("PF");
+ mPFImages.bindSampler(mSampler, 0);
+
+ bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
+ mPFText = bf.create();
+ mPFText.setName("PFText");
+ mPFText.bindSampler(mSamplerText, 0);
+
+ ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null);
+ bs.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ bs.setDitherEnable(false);
+ bs.setDepthMask(true);
+ bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ mPSBackground = bs.create();
+ mPSBackground.setName("PFS");
+
+ bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ bs.setDepthMask(false);
+ bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ mPSText = bs.create();
+ mPSText.setName("PFSText");
+
+ mPVAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
+
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ mPV = pvb.create();
+ mPV.setName("PV");
+ mPV.bindAllocation(mPVAlloc);
+
+ mPVOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ mPVOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
+
+ pvb.setTextureMatrixEnable(true);
+ mPVOrtho = pvb.create();
+ mPVOrtho.setName("PVOrtho");
+ mPVOrtho.bindAllocation(mPVOrthoAlloc);
+
+ mRS.contextBindProgramVertex(mPV);
+
+ mAllocScratchBuf = new int[32];
+ mAllocScratch = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocScratchBuf.length);
+ mAllocScratch.data(mAllocScratchBuf);
+
+ Log.e("rs", "Done loading named");
+
+
+
+ {
+ mIcons = new Allocation[29];
+ mAllocIconIDBuf = new int[mIcons.length];
+ mAllocIconID = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocIconIDBuf.length);
+
+ mLabels = new Allocation[29];
+ mAllocLabelIDBuf = new int[mLabels.length];
+ mAllocLabelID = Allocation.createSized(mRS,
+ Element.USER_I32, mLabels.length);
+
+ Element ie8888 = Element.RGBA_8888;
+
+ mIcons[0] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.browser, ie8888, true);
+ mIcons[1] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.market, ie8888, true);
+ mIcons[2] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.photos, ie8888, true);
+ mIcons[3] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.settings, ie8888, true);
+ mIcons[4] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.calendar, ie8888, true);
+ mIcons[5] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g1155, ie8888, true);
+ mIcons[6] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g2140, ie8888, true);
+ mIcons[7] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.maps, ie8888, true);
+ mIcons[8] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path431, ie8888, true);
+ mIcons[9] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path676, ie8888, true);
+ mIcons[10] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path754, ie8888, true);
+ mIcons[11] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path815, ie8888, true);
+ mIcons[12] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1920, ie8888, true);
+ mIcons[13] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1927, ie8888, true);
+ mIcons[14] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3099, ie8888, true);
+ mIcons[15] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3950, ie8888, true);
+ mIcons[16] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path4481, ie8888, true);
+ mIcons[17] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path5168, ie8888, true);
+ mIcons[18] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.polygon2408, ie8888, true);
+
+ mLabels[0] = makeTextBitmap("browser");
+ mLabels[1] = makeTextBitmap("market");
+ mLabels[2] = makeTextBitmap("photos");
+ mLabels[3] = makeTextBitmap("settings");
+ mLabels[4] = makeTextBitmap("calendar");
+ mLabels[5] = makeTextBitmap("g1155");
+ mLabels[6] = makeTextBitmap("g2140");
+ mLabels[7] = makeTextBitmap("maps");
+ mLabels[8] = makeTextBitmap("path431");
+ mLabels[9] = makeTextBitmap("path676");
+ mLabels[10] = makeTextBitmap("path754");
+ mLabels[11] = makeTextBitmap("path815");
+ mLabels[12] = makeTextBitmap("path1920");
+ mLabels[13] = makeTextBitmap("path1927");
+ mLabels[14] = makeTextBitmap("path3099");
+ mLabels[15] = makeTextBitmap("path3950");
+ mLabels[16] = makeTextBitmap("path4481");
+ mLabels[17] = makeTextBitmap("path5168");
+ mLabels[18] = makeTextBitmap("polygon2408");
+
+ mIcons[19] = mIcons[0];
+ mIcons[20] = mIcons[1];
+ mIcons[21] = mIcons[2];
+ mIcons[22] = mIcons[3];
+ mIcons[23] = mIcons[4];
+ mIcons[24] = mIcons[5];
+ mIcons[25] = mIcons[6];
+ mIcons[26] = mIcons[7];
+ mIcons[27] = mIcons[8];
+ mIcons[28] = mIcons[9];
+
+ mLabels[19] = mLabels[0];
+ mLabels[20] = mLabels[1];
+ mLabels[21] = mLabels[2];
+ mLabels[22] = mLabels[3];
+ mLabels[23] = mLabels[4];
+ mLabels[24] = mLabels[5];
+ mLabels[25] = mLabels[6];
+ mLabels[26] = mLabels[7];
+ mLabels[27] = mLabels[8];
+ mLabels[28] = mLabels[9];
+
+ for(int ct=0; ct < mIcons.length; ct++) {
+ mIcons[ct].uploadToTexture(0);
+ mLabels[ct].uploadToTexture(0);
+ mAllocIconIDBuf[ct] = mIcons[ct].getID();
+ mAllocLabelIDBuf[ct] = mLabels[ct].getID();
+ }
+ mAllocIconID.data(mAllocIconIDBuf);
+ mAllocLabelID.data(mAllocLabelIDBuf);
+ }
+
+ }
+
+ Allocation makeTextBitmap(String t) {
+ Bitmap b = Bitmap.createBitmap(128, 32, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ Paint p = new Paint();
+ p.setTypeface(Typeface.DEFAULT_BOLD);
+ p.setTextSize(20);
+ p.setColor(0xffffffff);
+ c.drawText(t, 2, 26, p);
+ return Allocation.createFromBitmap(mRS, b, Element.RGBA_8888, true);
+ }
+
+
+ private void initRS() {
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setScript(mRes, R.raw.rollo);
+ //sb.setScript(mRes, R.raw.rollo2);
+ sb.setRoot(true);
+ mScript = sb.create();
+ mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
+ mAllocState = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocStateBuf.length);
+ mScript.bindAllocation(mAllocState, 0);
+ mScript.bindAllocation(mAllocIconID, 1);
+ mScript.bindAllocation(mAllocScratch, 2);
+ mScript.bindAllocation(mAllocLabelID, 3);
+ setPosition(0);
+ setZoom(1);
+
+ //RenderScript.File f = mRS.fileOpen("/sdcard/test.a3d");
+
+ mRS.contextBindRootScript(mScript);
+ }
+}
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
new file mode 100644
index 0000000..3e1c54d
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -0,0 +1,214 @@
+/*
+ * 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.rollo;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import java.lang.Float;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.graphics.PixelFormat;
+
+
+public class RolloView extends RSSurfaceView {
+ public RolloView(Context context) {
+ super(context);
+ setFocusable(true);
+ getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ private RenderScript mRS;
+ private RolloRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript();
+ mRender = new RolloRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+ boolean mControlMode = false;
+ boolean mZoomMode = false;
+ boolean mFlingMode = false;
+ float mFlingX = 0;
+ float mFlingY = 0;
+ float mColumn = -1;
+ float mOldColumn;
+ float mZoom = 1;
+
+ int mIconCount = 29;
+ int mRows = 4;
+ int mColumns = (mIconCount + mRows - 1) / mRows;
+
+ float mMaxZoom = ((float)mColumns) / 3.f;
+
+
+ void setColumn(boolean clamp)
+ {
+ //Log.e("rs", " col = " + Float.toString(mColumn));
+ float c = mColumn;
+ if(c > (mColumns -2)) {
+ c = (mColumns -2);
+ }
+ if(c < 0) {
+ c = 0;
+ }
+ mRender.setPosition(c);
+ if(clamp) {
+ mColumn = c;
+ }
+ }
+
+ void computeSelection(float x, float y)
+ {
+ float col = mColumn + (x - 0.5f) * 4 + 1.25f;
+ int iCol = (int)(col + 0.25f);
+
+ float row = (y / 0.8f) * mRows;
+ int iRow = (int)(row - 0.5f);
+
+ mRender.setSelected(iCol * mRows + iRow);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+
+ float nx = ev.getX() / getWidth();
+ float ny = ev.getY() / getHeight();
+
+ //Log.e("rs", "width=" + Float.toString(getWidth()));
+ //Log.e("rs", "height=" + Float.toString(getHeight()));
+
+ mRender.setTouch(ret);
+
+ if((ny > 0.85f) || mControlMode) {
+ mFlingMode = false;
+
+ // Projector control
+ if((nx > 0.2f) && (nx < 0.8f) || mControlMode) {
+ if(act != ev.ACTION_UP) {
+ float zoom = mMaxZoom;
+ if(mControlMode) {
+ if(!mZoomMode) {
+ zoom = 1.f;
+ }
+ float dx = nx - mFlingX;
+
+ if((ny < 0.9) && mZoomMode) {
+ zoom = mMaxZoom - ((0.9f - ny) * 10.f);
+ if(zoom < 1) {
+ zoom = 1;
+ mZoomMode = false;
+ }
+ mOldColumn = mColumn;
+ }
+ mColumn += dx * 4;// * zoom;
+ if(zoom > 1.01f) {
+ mColumn += (mZoom - zoom) * (nx - 0.5f) * 4 * zoom;
+ }
+ } else {
+ mOldColumn = mColumn;
+ mColumn = ((float)mColumns) / 2;
+ mControlMode = true;
+ mZoomMode = true;
+ }
+ mZoom = zoom;
+ mFlingX = nx;
+ mRender.setZoom(zoom);
+ if(mZoom < 1.01f) {
+ computeSelection(nx, ny);
+ }
+ } else {
+ mControlMode = false;
+ mColumn = mOldColumn;
+ mRender.setZoom(1.f);
+ mRender.setSelected(-1);
+ }
+ } else {
+ // Do something with corners here....
+ }
+ setColumn(true);
+
+ } else {
+ // icon control
+ if(act != ev.ACTION_UP) {
+ if(mFlingMode) {
+ mColumn += (mFlingX - nx) * 4;
+ setColumn(true);
+ }
+ mFlingMode = true;
+ mFlingX = nx;
+ mFlingY = ny;
+ } else {
+ mFlingMode = false;
+ mColumn = (float)(java.lang.Math.floor(mColumn * 0.25f + 0.3f) * 4.f) + 1.f;
+ setColumn(true);
+ }
+ }
+
+
+ return ret;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev)
+ {
+ float x = ev.getX();
+ float y = ev.getY();
+ //Float tx = new Float(x);
+ //Float ty = new Float(y);
+ //Log.e("rs", "tbe " + tx.toString() + ", " + ty.toString());
+
+
+ return true;
+ }
+
+}
+
+
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
new file mode 100644
index 0000000..0df237f
--- /dev/null
+++ b/libs/rs/rs.spec
@@ -0,0 +1,520 @@
+
+
+ContextBindRootScript {
+ param RsScript sampler
+ }
+
+ContextBindProgramFragmentStore {
+ param RsProgramFragmentStore pgm
+ }
+
+ContextBindProgramFragment {
+ param RsProgramFragment pgm
+ }
+
+ContextBindProgramVertex {
+ param RsProgramVertex pgm
+ }
+
+ContextSetDefineF {
+ param const char* name
+ param float value
+ }
+
+ContextSetDefineI32 {
+ param const char* name
+ param int32_t value
+ }
+
+AssignName {
+ param void *obj
+ param const char *name
+ param size_t len
+ }
+
+ElementBegin {
+}
+
+ElementAddPredefined {
+ param RsElementPredefined predef
+ }
+
+ElementAdd {
+ param RsDataKind dataKind
+ param RsDataType dataType
+ param bool isNormalized
+ param size_t bits
+ param const char * name
+ }
+
+ElementCreate {
+ ret RsElement
+ }
+
+ElementGetPredefined {
+ param RsElementPredefined predef
+ ret RsElement
+ }
+
+ElementDestroy {
+ param RsElement ve
+ }
+
+TypeBegin {
+ param RsElement type
+ }
+
+TypeAdd {
+ param RsDimension dim
+ param size_t value
+ }
+
+TypeCreate {
+ ret RsType
+ }
+
+TypeDestroy {
+ param RsType p
+ }
+
+AllocationCreateTyped {
+ param RsType type
+ ret RsAllocation
+ }
+
+AllocationCreatePredefSized {
+ param RsElementPredefined predef
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateSized {
+ param RsElement e
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateFromFile {
+ param const char *file
+ param bool genMips
+ ret RsAllocation
+ }
+
+AllocationCreateFromBitmap {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
+AllocationCreateFromBitmapBoxed {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
+
+AllocationUploadToTexture {
+ param RsAllocation alloc
+ param uint32_t baseMipLevel
+ }
+
+AllocationUploadToBufferObject {
+ param RsAllocation alloc
+ }
+
+AllocationDestroy {
+ param RsAllocation alloc
+ }
+
+
+AllocationData {
+ param RsAllocation va
+ param const void * data
+ }
+
+Allocation1DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Allocation2DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+AllocationRead {
+ param RsAllocation va
+ param void * data
+ }
+
+Adapter1DCreate {
+ ret RsAdapter1D
+ }
+
+Adapter1DBindAllocation {
+ param RsAdapter1D adapt
+ param RsAllocation alloc
+ }
+
+Adapter1DDestroy {
+ param RsAdapter1D adapter
+ }
+
+Adapter1DSetConstraint {
+ param RsAdapter1D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter1DData {
+ param RsAdapter1D adapter
+ param const void * data
+ }
+
+Adapter1DSubData {
+ param RsAdapter1D adapter
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Adapter2DCreate {
+ ret RsAdapter2D
+ }
+
+Adapter2DBindAllocation {
+ param RsAdapter2D adapt
+ param RsAllocation alloc
+ }
+
+Adapter2DDestroy {
+ param RsAdapter2D adapter
+ }
+
+Adapter2DSetConstraint {
+ param RsAdapter2D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter2DData {
+ param RsAdapter2D adapter
+ param const void *data
+ }
+
+Adapter2DSubData {
+ param RsAdapter2D adapter
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+SamplerBegin {
+ }
+
+SamplerSet {
+ param RsSamplerParam p
+ param RsSamplerValue value
+ }
+
+SamplerCreate {
+ ret RsSampler
+ }
+
+SamplerDestroy {
+ param RsSampler s
+ }
+
+TriangleMeshBegin {
+ param RsElement vertex
+ param RsElement index
+ }
+
+TriangleMeshAddVertex {
+ param const void *vtx
+ }
+
+TriangleMeshAddTriangle {
+ param uint32_t idx1
+ param uint32_t idx2
+ param uint32_t idx3
+ }
+
+TriangleMeshCreate {
+ ret RsTriangleMesh
+ }
+
+TriangleMeshDestroy {
+ param RsTriangleMesh mesh
+ }
+
+TriangleMeshRender {
+ param RsTriangleMesh vtm
+ }
+
+TriangleMeshRenderRange {
+ param RsTriangleMesh vtm
+ param uint32_t start
+ param uint32_t count
+ }
+
+ScriptDestroy {
+ param RsScript script
+ }
+
+ScriptBindAllocation {
+ param RsScript vtm
+ param RsAllocation va
+ param uint32_t slot
+ }
+
+
+ScriptCBegin {
+ }
+
+ScriptSetClearColor {
+ param RsScript s
+ param float r
+ param float g
+ param float b
+ param float a
+ }
+
+ScriptSetTimeZone {
+ param RsScript s
+ param const char * timeZone
+ param uint32_t length
+ }
+
+ScriptSetClearDepth {
+ param RsScript s
+ param float depth
+ }
+
+ScriptSetClearStencil {
+ param RsScript s
+ param uint32_t stencil
+ }
+
+ScriptSetType {
+ param RsType type
+ param uint32_t slot
+ param bool isWritable
+ param const char * name
+ }
+
+ScriptSetRoot {
+ param bool isRoot
+ }
+
+
+
+ScriptCSetScript {
+ param void * codePtr
+ }
+
+ScriptCSetText {
+ param const char * text
+ param uint32_t length
+ }
+
+ScriptCCreate {
+ ret RsScript
+ }
+
+ScriptCSetDefineF {
+ param const char* name
+ param float value
+ }
+
+ScriptCSetDefineI32 {
+ param const char* name
+ param int32_t value
+ }
+
+ProgramFragmentStoreBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentStoreColorMask {
+ param bool r
+ param bool g
+ param bool b
+ param bool a
+ }
+
+ProgramFragmentStoreBlendFunc {
+ param RsBlendSrcFunc srcFunc
+ param RsBlendDstFunc destFunc
+ }
+
+ProgramFragmentStoreDepthMask {
+ param bool enable
+}
+
+ProgramFragmentStoreDither {
+ param bool enable
+}
+
+ProgramFragmentStoreDepthFunc {
+ param RsDepthFunc func
+}
+
+ProgramFragmentStoreCreate {
+ ret RsProgramFragmentStore
+ }
+
+ProgramFragmentStoreDestroy {
+ param RsProgramFragmentStore pfs
+ }
+
+
+ProgramFragmentBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentBindTexture {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsAllocation a
+ }
+
+ProgramFragmentBindSampler {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsSampler s
+ }
+
+ProgramFragmentSetType {
+ param uint32_t slot
+ param RsType t
+ }
+
+ProgramFragmentSetEnvMode {
+ param uint32_t slot
+ param RsTexEnvMode env
+ }
+
+ProgramFragmentSetTexEnable {
+ param uint32_t slot
+ param bool enable
+ }
+
+ProgramFragmentCreate {
+ ret RsProgramFragment
+ }
+
+ProgramFragmentDestroy {
+ param RsProgramFragment pf
+ }
+
+
+ProgramVertexBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramVertexCreate {
+ ret RsProgramVertex
+ }
+
+ProgramVertexBindAllocation {
+ param RsProgramVertex vpgm
+ param RsAllocation constants
+ }
+
+ProgramVertexSetTextureMatrixEnable {
+ param bool enable
+ }
+
+ProgramVertexAddLight {
+ param RsLight light
+ }
+
+LightBegin {
+ }
+
+LightSetLocal {
+ param bool isLocal
+ }
+
+LightSetMonochromatic {
+ param bool isMono
+ }
+
+LightCreate {
+ ret RsLight light
+ }
+
+LightDestroy {
+ param RsLight light
+ }
+
+LightSetPosition {
+ param RsLight light
+ param float x
+ param float y
+ param float z
+ }
+
+LightSetColor {
+ param RsLight light
+ param float r
+ param float g
+ param float b
+ }
+
+FileOpen {
+ ret RsFile
+ param const char *name
+ param size_t len
+ }
+
+
+SimpleMeshCreate {
+ ret RsSimpleMesh
+ param RsAllocation prim
+ param RsAllocation index
+ param RsAllocation *vtx
+ param uint32_t vtxCount
+ param uint32_t primType
+ }
+
+SimpleMeshDestroy {
+ param RsSimpleMesh mesh
+ }
+
+SimpleMeshBindIndex {
+ param RsSimpleMesh mesh
+ param RsAllocation idx
+ }
+
+SimpleMeshBindPrimitive {
+ param RsSimpleMesh mesh
+ param RsAllocation prim
+ }
+
+SimpleMeshBindVertex {
+ param RsSimpleMesh mesh
+ param RsAllocation vtx
+ param uint32_t slot
+ }
+
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
new file mode 100644
index 0000000..25f3340
--- /dev/null
+++ b/libs/rs/rsAdapter.cpp
@@ -0,0 +1,249 @@
+
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Adapter1D::Adapter1D()
+{
+ reset();
+}
+
+Adapter1D::Adapter1D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter1D::reset()
+{
+ mY = 0;
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter1D::getElement(uint32_t x)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, mY);
+ return ptr;
+}
+
+void Adapter1D::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ if (mAllocation.get() && mAllocation.get()->getType()) {
+ void *ptr = getElement(xoff);
+ count *= mAllocation.get()->getType()->getElementSizeBytes();
+ memcpy(ptr, data, count);
+ }
+}
+
+void Adapter1D::data(const void *data)
+{
+ memcpy(getElement(0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+namespace android {
+namespace renderscript {
+
+RsAdapter1D rsi_Adapter1DCreate(Context *rsc)
+{
+ Adapter1D *a = new Adapter1D();
+ a->incRef();
+ 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);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter1DSetConstraint(Context *rsc, RsAdapter1D va, RsDimension dim, uint32_t value)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 1D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ a->setY(value);
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter1DSubData(Context *rsc, RsAdapter1D va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->subData(xoff, count, data);
+}
+
+void rsi_Adapter1DData(Context *rsc, RsAdapter1D va, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->data(data);
+}
+
+}
+}
+
+//////////////////////////
+
+Adapter2D::Adapter2D()
+{
+ reset();
+}
+
+Adapter2D::Adapter2D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter2D::reset()
+{
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter2D::getElement(uint32_t x, uint32_t y) const
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, y);
+ return ptr;
+}
+
+void Adapter2D::subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+
+ uint32_t eSize = mAllocation.get()->getType()->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ memcpy(getElement(xoff, line), src, lineSize);
+ src += lineSize;
+ }
+}
+
+void Adapter2D::data(const void *data)
+{
+ memcpy(getElement(0,0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+RsAdapter2D rsi_Adapter2DCreate(Context *rsc)
+{
+ Adapter2D *a = new Adapter2D();
+ a->incRef();
+ 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);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter2DSetConstraint(Context *rsc, RsAdapter2D va, RsDimension dim, uint32_t value)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 2D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ rsAssert(!"Cannot contrain Y in an 2D adapter");
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter2DData(Context *rsc, RsAdapter2D va, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->data(data);
+}
+
+void rsi_Adapter2DSubData(Context *rsc, RsAdapter2D va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->subData(xoff, yoff, w, h, data);
+}
+
+}
+}
diff --git a/libs/rs/rsAdapter.h b/libs/rs/rsAdapter.h
new file mode 100644
index 0000000..865535e
--- /dev/null
+++ b/libs/rs/rsAdapter.h
@@ -0,0 +1,96 @@
+/*
+ * 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 ANDROID_RS_ADAPTER_H
+#define ANDROID_RS_ADAPTER_H
+
+#include "rsAllocation.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Adapter1D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter1D();
+ Adapter1D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x);
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ inline void setY(uint32_t y) {mY = y;}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void data(const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mY;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+class Adapter2D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter2D();
+ Adapter2D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x, uint32_t y) const;
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+ uint32_t getDimY() const {return mAllocation->getType()->getLODDimY(mLOD);}
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
new file mode 100644
index 0000000..ad9c739
--- /dev/null
+++ b/libs/rs/rsAllocation.cpp
@@ -0,0 +1,539 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Allocation::Allocation(const Type *type)
+{
+ mPtr = NULL;
+
+ mCpuWrite = false;
+ mCpuRead = false;
+ mGpuWrite = false;
+ mGpuRead = false;
+
+ mReadWriteRatio = 0;
+ mUpdateSize = 0;
+
+ mIsTexture = false;
+ mTextureID = 0;
+
+ mIsVertexBuffer = false;
+ mBufferID = 0;
+
+ mType.set(type);
+ rsAssert(type);
+ mPtr = malloc(mType->getSizeBytes());
+ if (!mPtr) {
+ LOGE("Allocation::Allocation, alloc failure");
+ }
+}
+
+Allocation::~Allocation()
+{
+}
+
+void Allocation::setCpuWritable(bool)
+{
+}
+
+void Allocation::setGpuWritable(bool)
+{
+}
+
+void Allocation::setCpuReadable(bool)
+{
+}
+
+void Allocation::setGpuReadable(bool)
+{
+}
+
+bool Allocation::fixAllocation()
+{
+ return false;
+}
+
+void Allocation::uploadToTexture(uint32_t lodOffset)
+{
+ //rsAssert(!mTextureId);
+ rsAssert(lodOffset < mType->getLODCount());
+
+ GLenum type = mType->getElement()->getGLType();
+ GLenum format = mType->getElement()->getGLFormat();
+
+ if (!type || !format) {
+ return;
+ }
+
+ if (!mTextureID) {
+ glGenTextures(1, &mTextureID);
+ }
+ glBindTexture(GL_TEXTURE_2D, mTextureID);
+
+ Adapter2D adapt(this);
+ for(uint32_t lod = 0; (lod + lodOffset) < mType->getLODCount(); lod++) {
+ adapt.setLOD(lod+lodOffset);
+
+ uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
+ glTexImage2D(GL_TEXTURE_2D, lod, format,
+ adapt.getDimX(), adapt.getDimY(),
+ 0, format, type, ptr);
+ }
+}
+
+void Allocation::uploadToBufferObject()
+{
+ rsAssert(!mType->getDimY());
+ rsAssert(!mType->getDimZ());
+
+ if (!mBufferID) {
+ glGenBuffers(1, &mBufferID);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
+ glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+
+void Allocation::data(const void *data)
+{
+ memcpy(mPtr, data, mType->getSizeBytes());
+}
+
+void Allocation::read(void *data)
+{
+ memcpy(data, mPtr, mType->getSizeBytes());
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ ptr += eSize * xoff;
+ memcpy(ptr, data, count * eSize);
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = mType->getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ uint8_t *dst = static_cast<uint8_t *>(mPtr);
+ dst += eSize * (xoff + yoff * destW);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ memcpy(dst, src, lineSize);
+ src += lineSize;
+ dst += destW * eSize;
+ }
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data)
+{
+}
+
+
+
+/////////////////
+//
+
+
+namespace android {
+namespace renderscript {
+
+RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
+{
+ const Type * type = static_cast<const Type *>(vtype);
+
+ Allocation * alloc = new Allocation(type);
+ alloc->incRef();
+ return alloc;
+}
+
+RsAllocation rsi_AllocationCreatePredefSized(Context *rsc, RsElementPredefined t, size_t count)
+{
+ RsElement e = rsi_ElementGetPredefined(rsc, t);
+ return rsi_AllocationCreateSized(rsc, e, count);
+}
+
+RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
+{
+ Type * type = new Type();
+ type->setDimX(count);
+ type->setElement(static_cast<Element *>(e));
+ type->compute();
+ return rsi_AllocationCreateTyped(rsc, type);
+}
+
+void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToTexture(baseMipLevel);
+}
+
+void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToBufferObject();
+}
+
+void rsi_AllocationDestroy(Context *rsc, RsAllocation)
+{
+}
+
+static void mip565(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < h; y++) {
+ uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
+ const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
+ const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < w; x++) {
+ *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+}
+
+static void mip8888(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < h; y++) {
+ uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
+ const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
+ const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < w; x++) {
+ *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+}
+
+static void mip(const Adapter2D &out, const Adapter2D &in)
+{
+ switch(out.getBaseType()->getElement()->getSizeBits()) {
+ case 32:
+ mip8888(out, in);
+ break;
+ case 16:
+ mip565(out, in);
+ break;
+
+ }
+
+}
+
+typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
+
+static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 2);
+}
+static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count);
+}
+static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 4);
+}
+
+
+static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 3;
+ }
+}
+
+static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 4;
+ }
+}
+
+static ElementConverter_t pickConverter(RsElementPredefined dstFmt, RsElementPredefined srcFmt)
+{
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_565)) {
+ return elementConverter_cpy_16;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_888)) {
+ return elementConverter_888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_8888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGBA_8888) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_cpy_32;
+ }
+
+ LOGE("pickConverter, unsuported combo, src %i, dst %i", srcFmt, dstFmt);
+ return 0;
+}
+
+
+RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ rsAssert(!(w & (w-1)));
+ rsAssert(!(h & (h-1)));
+
+ //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt));
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ return NULL;
+ }
+ texAlloc->incRef();
+
+ ElementConverter_t cvt = pickConverter(dstFmt, srcFmt);
+ cvt(texAlloc->getPtr(), data, w * h);
+
+ if (genMips) {
+ Adapter2D adapt(texAlloc);
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ mip(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+static uint32_t fmtToBits(RsElementPredefined fmt)
+{
+ return 16;
+}
+
+RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ uint32_t w2 = rsHigherPow2(w);
+ uint32_t h2 = rsHigherPow2(h);
+
+ if ((w2 == w) && (h2 == h)) {
+ return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data);
+ }
+
+ uint32_t bpp = fmtToBits(srcFmt) >> 3;
+ size_t size = w2 * h2 * bpp;
+ uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
+ memset(tmp, 0, size);
+
+ const uint8_t * src = static_cast<const uint8_t *>(data);
+ for (uint32_t y = 0; y < h; y++) {
+ uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
+ memcpy(&ydst[(w2 - w) >> 1], src, w * bpp);
+ src += w * bpp;
+ }
+
+ RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp);
+ free(tmp);
+ return ret;
+
+
+
+
+}
+
+
+RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
+{
+ bool use32bpp = false;
+
+ typedef struct _Win3xBitmapHeader
+ {
+ uint16_t type;
+ uint32_t totalSize;
+ uint32_t reserved;
+ uint32_t offset;
+ int32_t hdrSize; /* Size of this header in bytes */
+ int32_t width; /* Image width in pixels */
+ int32_t height; /* Image height in pixels */
+ int16_t planes; /* Number of color planes */
+ int16_t bpp; /* Number of bits per pixel */
+ /* Fields added for Windows 3.x follow this line */
+ int32_t compression; /* Compression methods used */
+ int32_t sizeOfBitmap; /* Size of bitmap in bytes */
+ int32_t horzResolution; /* Horizontal resolution in pixels per meter */
+ int32_t vertResolution; /* Vertical resolution in pixels per meter */
+ int32_t colorsUsed; /* Number of colors in the image */
+ int32_t colorsImportant; /* Minimum number of important colors */
+ } __attribute__((__packed__)) WIN3XBITMAPHEADER;
+
+ _Win3xBitmapHeader hdr;
+
+ FILE *f = fopen(file, "rb");
+ if (f == NULL) {
+ LOGE("rsAllocationCreateFromBitmap failed to open file %s", file);
+ return NULL;
+ }
+ memset(&hdr, 0, sizeof(hdr));
+ fread(&hdr, sizeof(hdr), 1, f);
+
+ if (hdr.bpp != 24) {
+ LOGE("Unsuported BMP type");
+ fclose(f);
+ return NULL;
+ }
+
+ int32_t texWidth = rsHigherPow2(hdr.width);
+ int32_t texHeight = rsHigherPow2(hdr.height);
+
+ if (use32bpp) {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGBA_8888));
+ } else {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ }
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, texWidth);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, texHeight);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ texAlloc->incRef();
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ fclose(f);
+ return NULL;
+ }
+
+ // offset to letterbox if height is not pow2
+ Adapter2D adapt(texAlloc);
+ uint8_t * fileInBuf = new uint8_t[texWidth * 3];
+ uint32_t yOffset = (hdr.width - hdr.height) / 2;
+
+ if (use32bpp) {
+ uint8_t *tmp = static_cast<uint8_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ tmp[0] = fileInBuf[x*3 + 2];
+ tmp[1] = fileInBuf[x*3 + 1];
+ tmp[2] = fileInBuf[x*3];
+ tmp[3] = 0xff;
+ tmp += 4;
+ }
+ }
+ } else {
+ uint16_t *tmp = static_cast<uint16_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ *tmp = rs888to565(fileInBuf[x*3 + 2], fileInBuf[x*3 + 1], fileInBuf[x*3]);
+ tmp++;
+ }
+ }
+ }
+
+ fclose(f);
+ delete [] fileInBuf;
+
+ if (genMips) {
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ mip(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->data(data);
+ rsc->allocationCheck(a);
+}
+
+void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, count, data);
+ rsc->allocationCheck(a);
+}
+
+void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, yoff, w, h, data);
+ rsc->allocationCheck(a);
+}
+
+void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->read(data);
+}
+
+
+}
+}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
new file mode 100644
index 0000000..00af9ed
--- /dev/null
+++ b/libs/rs/rsAllocation.h
@@ -0,0 +1,101 @@
+/*
+ * 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 ANDROID_STRUCTURED_ALLOCATION_H
+#define ANDROID_STRUCTURED_ALLOCATION_H
+
+#include "rsType.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Allocation : public ObjectBase
+{
+ // The graphics equilivent of malloc. The allocation contains a structure of elements.
+
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Allocation(const Type *);
+ virtual ~Allocation();
+
+ void setCpuWritable(bool);
+ void setGpuWritable(bool);
+ void setCpuReadable(bool);
+ void setGpuReadable(bool);
+
+ bool fixAllocation();
+
+ void * getPtr() const {return mPtr;}
+ const Type * getType() const {return mType.get();}
+
+ void uploadToTexture(uint32_t lodOffset = 0);
+ uint32_t getTextureID() const {return mTextureID;}
+
+ void uploadToBufferObject();
+ uint32_t getBufferObjectID() const {return mBufferID;}
+
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data);
+
+ void read(void *data);
+
+ void enableGLVertexBuffers() const;
+ void setupGLIndexBuffers() const;
+
+
+protected:
+ ObjectBaseRef<const Type> mType;
+ void * mPtr;
+
+ // Usage restrictions
+ bool mCpuWrite;
+ bool mCpuRead;
+ bool mGpuWrite;
+ bool mGpuRead;
+
+ // more usage hint data from the application
+ // which can be used by a driver to pick the best memory type.
+ // Likely ignored for now
+ float mReadWriteRatio;
+ float mUpdateSize;
+
+
+ // Is this a legal structure to be used as a texture source.
+ // Initially this will require 1D or 2D and color data
+ bool mIsTexture;
+ uint32_t mTextureID;
+
+ // Is this a legal structure to be used as a vertex source.
+ // Initially this will require 1D and x(yzw). Additional per element data
+ // is allowed.
+ bool mIsVertexBuffer;
+ uint32_t mBufferID;
+};
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
new file mode 100644
index 0000000..b88710c
--- /dev/null
+++ b/libs/rs/rsComponent.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include "rsComponent.h"
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Component::Component()
+{
+ mType = FLOAT;
+ mKind = NONE;
+ mIsNormalized = false;
+ mBits = 0;
+}
+
+Component::Component(
+ DataKind dk, DataType dt,
+ bool isNormalized, uint32_t bits, const char * name)
+{
+ mType = dt;
+ mKind = dk;
+ mIsNormalized = isNormalized;
+ mBits = bits;
+ if (name) {
+ mName = name;
+ }
+}
+
+const char * Component::getCType() const
+{
+ switch(mType) {
+ case FLOAT:
+ return "float";
+ case SIGNED:
+ case UNSIGNED:
+ switch(mBits) {
+ case 32:
+ return "int";
+ case 16:
+ return "short";
+ case 8:
+ return "char";
+ }
+ break;
+ }
+ return NULL;
+}
+
+Component::~Component()
+{
+}
+
+uint32_t Component::getGLType() const
+{
+ switch(mType) {
+ case RS_TYPE_FLOAT:
+ rsAssert(mBits == 32);
+ return GL_FLOAT;
+ case RS_TYPE_SIGNED:
+ switch(mBits) {
+ case 32:
+ return 0;//GL_INT;
+ case 16:
+ return GL_SHORT;
+ case 8:
+ return GL_BYTE;
+ }
+ break;
+ case RS_TYPE_UNSIGNED:
+ switch(mBits) {
+ case 32:
+ return 0;//GL_UNSIGNED_INT;
+ case 16:
+ return GL_UNSIGNED_SHORT;
+ case 8:
+ return GL_UNSIGNED_BYTE;
+ }
+ break;
+ }
+ //rsAssert(!"Bad type");
+ //LOGE("mType %i, mKind %i, mBits %i, mIsNormalized %i", mType, mKind, mBits, mIsNormalized);
+ return 0;
+}
+
+
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
new file mode 100644
index 0000000..6342f1b
--- /dev/null
+++ b/libs/rs/rsComponent.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ANDROID_RS_STRUCTURED_COMPONENT_H
+#define ANDROID_RS_STRUCTURED_COMPONENT_H
+
+#include "rsUtils.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Component : public ObjectBase
+{
+public:
+ enum DataType {
+ FLOAT,
+ UNSIGNED,
+ SIGNED
+ };
+
+ enum DataKind {
+ NONE,
+ RED, GREEN, BLUE, ALPHA, LUMINANCE, INTENSITY,
+ X, Y, Z, W,
+ S, T, Q, R,
+ NX, NY, NZ,
+ INDEX,
+ USER
+ };
+
+
+ Component(DataKind dk, DataType dt, bool isNorm, uint32_t bits, const char *);
+ virtual ~Component();
+
+ DataType getType() const {return mType;}
+ bool getIsNormalized() const {return mIsNormalized;}
+ DataKind getKind() const {return mKind;}
+ uint32_t getBits() const {return mBits;}
+
+ uint32_t getGLType() const;
+ const char * getCType() const;
+
+ const char * getComponentName() const {return mName.string();}
+
+protected:
+
+ DataType mType;
+ bool mIsNormalized;
+ DataKind mKind;
+ uint32_t mBits;
+ String8 mName;
+
+private:
+ Component();
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_STRUCTURED_COMPONENT_H
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
new file mode 100644
index 0000000..52389ea
--- /dev/null
+++ b/libs/rs/rsContext.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ */
+
+#include "rsDevice.h"
+#include "rsContext.h"
+#include "rsThreadIO.h"
+#include <ui/FramebufferNativeWindow.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Context * Context::gCon = NULL;
+pthread_key_t Context::gThreadTLSKey = 0;
+
+void Context::initEGL()
+{
+ mNumConfigs = -1;
+
+ 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
+ };
+
+ mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion);
+ eglChooseConfig(mDisplay, s_configAttribs, &mConfig, 1, &mNumConfigs);
+
+ if (mWndSurface) {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig, mWndSurface,
+ NULL);
+ } else {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig,
+ android_createDisplaySurface(),
+ NULL);
+ }
+
+ mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL);
+ eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+ eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mHeight);
+}
+
+bool Context::runScript(Script *s, uint32_t launchID)
+{
+ ObjectBaseRef<ProgramFragment> frag(mFragment);
+ ObjectBaseRef<ProgramVertex> vtx(mVertex);
+ ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore);
+
+ bool ret = s->run(this, launchID);
+
+ mFragment.set(frag);
+ mVertex.set(vtx);
+ mFragmentStore.set(store);
+ return ret;
+}
+
+
+bool Context::runRootScript()
+{
+ rsAssert(mRootScript->mEnviroment.mIsRoot);
+
+ //glColor4f(1,1,1,1);
+ //glEnable(GL_LIGHT0);
+ glViewport(0, 0, mWidth, mHeight);
+
+ glDepthMask(GL_TRUE);
+ 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 RS_LOG_TIMES
+ struct timespec startTime;
+ clock_gettime(CLOCK_MONOTONIC, &startTime);
+#endif
+ bool ret = runScript(mRootScript.get(), 0);
+
+#if RS_LOG_TIMES
+ struct timespec endTime;
+ clock_gettime(CLOCK_MONOTONIC, &endTime);
+
+ uint64_t t1 = endTime.tv_nsec + ((uint64_t)endTime.tv_sec * 1000 * 1000 * 1000);
+ uint64_t t2 = startTime.tv_nsec + ((uint64_t)startTime.tv_sec * 1000 * 1000 * 1000);
+ int t3 = (int)((t1 - t2) / 1000 / 1000);
+ LOGE("times %i", t3);
+#endif
+
+ return ret;
+}
+
+void Context::setupCheck()
+{
+ if (mFragmentStore.get()) {
+ mFragmentStore->setupGL(&mStateFragmentStore);
+ }
+ if (mFragment.get()) {
+ mFragment->setupGL(&mStateFragment);
+ }
+ if (mVertex.get()) {
+ mVertex->setupGL(&mStateVertex);
+ }
+
+}
+
+
+void * Context::threadProc(void *vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+
+ rsc->initEGL();
+
+ ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
+ if (!tlsStruct) {
+ LOGE("Error allocating tls storage");
+ return NULL;
+ }
+ tlsStruct->mContext = rsc;
+ tlsStruct->mScript = NULL;
+ int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct);
+ if (status) {
+ LOGE("pthread_setspecific %i", status);
+ }
+
+ rsc->mStateVertex.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setVertex(NULL);
+ rsc->mStateFragment.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setFragment(NULL);
+ rsc->mStateFragmentStore.init(rsc, rsc->mWidth, rsc->mHeight);
+ rsc->setFragmentStore(NULL);
+
+ rsc->mRunning = true;
+ bool mDraw = true;
+ while (!rsc->mExit) {
+ mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw);
+ mDraw &= (rsc->mRootScript.get() != NULL);
+
+ if (mDraw) {
+ mDraw = rsc->runRootScript();
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ }
+ }
+
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ eglTerminate(rsc->mDisplay);
+ return NULL;
+}
+
+Context::Context(Device *dev, Surface *sur)
+{
+ dev->addContext(this);
+ mDev = dev;
+ mRunning = false;
+ mExit = false;
+
+ // see comment in header
+ gCon = this;
+
+ int status;
+ pthread_attr_t threadAttr;
+
+ status = pthread_key_create(&gThreadTLSKey, NULL);
+ if (status) {
+ LOGE("Failed to init thread tls key.");
+ return;
+ }
+
+ status = pthread_attr_init(&threadAttr);
+ if (status) {
+ LOGE("Failed to init thread attribute.");
+ return;
+ }
+
+ sched_param sparam;
+ sparam.sched_priority = ANDROID_PRIORITY_DISPLAY;
+ pthread_attr_setschedparam(&threadAttr, &sparam);
+
+ mWndSurface = sur;
+
+ LOGV("RS Launching thread");
+ status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
+ if (status) {
+ LOGE("Failed to start rs context thread.");
+ }
+
+ while(!mRunning) {
+ sleep(1);
+ }
+
+ pthread_attr_destroy(&threadAttr);
+}
+
+Context::~Context()
+{
+ mExit = true;
+ void *res;
+
+ int status = pthread_join(mThreadId, &res);
+
+ 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();
+}
+
+void Context::setRootScript(Script *s)
+{
+ mRootScript.set(s);
+}
+
+void Context::setFragmentStore(ProgramFragmentStore *pfs)
+{
+ if (pfs == NULL) {
+ mFragmentStore.set(mStateFragmentStore.mDefault);
+ } else {
+ mFragmentStore.set(pfs);
+ }
+}
+
+void Context::setFragment(ProgramFragment *pf)
+{
+ if (pf == NULL) {
+ mFragment.set(mStateFragment.mDefault);
+ } else {
+ mFragment.set(pf);
+ }
+}
+
+void Context::allocationCheck(const Allocation *a)
+{
+ mVertex->checkUpdatedAllocation(a);
+ mFragment->checkUpdatedAllocation(a);
+ mFragmentStore->checkUpdatedAllocation(a);
+}
+
+void Context::setVertex(ProgramVertex *pv)
+{
+ if (pv == NULL) {
+ mVertex.set(mStateVertex.mDefault);
+ } else {
+ mVertex.set(pv);
+ }
+}
+
+void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
+{
+ rsAssert(!obj->getName());
+ obj->setName(name, len);
+ mNames.add(obj);
+}
+
+void Context::removeName(ObjectBase *obj)
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (obj == mNames[ct]) {
+ mNames.removeAt(ct);
+ return;
+ }
+ }
+}
+
+ObjectBase * Context::lookupName(const char *name) const
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (!strcmp(name, mNames[ct]->getName())) {
+ return mNames[ct];
+ }
+ }
+ return NULL;
+}
+
+void Context::appendNameDefines(String8 *str) const
+{
+ char buf[256];
+ for (size_t ct=0; ct < mNames.size(); ct++) {
+ str->append("#define NAMED_");
+ str->append(mNames[ct]->getName());
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mNames[ct]);
+ str->append(buf);
+ }
+}
+
+void Context::appendVarDefines(String8 *str) const
+{
+ char buf[256];
+ for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+ str->append("#define ");
+ str->append(mInt32Defines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+ str->append(buf);
+
+ }
+ for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+ str->append("#define ");
+ str->append(mFloatDefines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+ str->append(buf);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_ContextBindRootScript(Context *rsc, RsScript vs)
+{
+ Script *s = static_cast<Script *>(vs);
+ rsc->setRootScript(s);
+}
+
+void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs)
+{
+ Sampler *s = static_cast<Sampler *>(vs);
+
+ if (slot > RS_MAX_SAMPLER_SLOT) {
+ LOGE("Invalid sampler slot");
+ return;
+ }
+
+ s->bindToContext(&rsc->mStateSampler, slot);
+}
+
+void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs)
+{
+ ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs);
+ rsc->setFragmentStore(pfs);
+}
+
+void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ rsc->setFragment(pf);
+}
+
+void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpv);
+ rsc->setVertex(pv);
+}
+
+void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len)
+{
+ ObjectBase *ob = static_cast<ObjectBase *>(obj);
+ rsc->assignName(ob, name, len);
+}
+
+void rsi_ContextSetDefineF(Context *rsc, const char* name, float value)
+{
+ rsc->addInt32Define(name, value);
+}
+
+void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+ rsc->addFloatDefine(name, value);
+}
+
+}
+}
+
+
+RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version)
+{
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = new Context(dev, (Surface *)sur);
+ return rsc;
+}
+
+void rsContextDestroy(RsContext vrsc)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ delete rsc;
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
new file mode 100644
index 0000000..3d17298
--- /dev/null
+++ b/libs/rs/rsContext.h
@@ -0,0 +1,167 @@
+/*
+ * 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 ANDROID_RS_CONTEXT_H
+#define ANDROID_RS_CONTEXT_H
+
+#include "rsUtils.h"
+
+#include <ui/Surface.h>
+
+#include "rsThreadIO.h"
+#include "rsType.h"
+#include "rsMatrix.h"
+#include "rsAllocation.h"
+#include "rsTriangleMesh.h"
+#include "rsSimpleMesh.h"
+#include "rsMesh.h"
+#include "rsDevice.h"
+#include "rsScriptC.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rsSampler.h"
+#include "rsLight.h"
+#include "rsProgramFragment.h"
+#include "rsProgramFragmentStore.h"
+#include "rsProgramVertex.h"
+
+#include "rsgApiStructs.h"
+#include "rsLocklessFifo.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context
+{
+public:
+ Context(Device *, Surface *);
+ ~Context();
+
+ static pthread_key_t gThreadTLSKey;
+ struct ScriptTLSStruct {
+ Context * mContext;
+ Script * mScript;
+ };
+
+
+ //StructuredAllocationContext mStateAllocation;
+ ElementState mStateElement;
+ TypeState mStateType;
+ SamplerState mStateSampler;
+ ProgramFragmentState mStateFragment;
+ ProgramFragmentStoreState mStateFragmentStore;
+ ProgramVertexState mStateVertex;
+ LightState mStateLight;
+
+ TriangleMeshContext mStateTriangleMesh;
+
+ ScriptCState mScriptC;
+
+ static Context * getContext() {return gCon;}
+
+ void swapBuffers();
+ void setRootScript(Script *);
+ void setVertex(ProgramVertex *);
+ void setFragment(ProgramFragment *);
+ void setFragmentStore(ProgramFragmentStore *);
+
+ void updateSurface(void *sur);
+
+ const ProgramFragment * getFragment() {return mFragment.get();}
+ const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+ const ProgramVertex * getVertex() {return mVertex.get();}
+
+ void setupCheck();
+ void allocationCheck(const Allocation *);
+
+ void assignName(ObjectBase *obj, const char *name, uint32_t len);
+ void removeName(ObjectBase *obj);
+ ObjectBase * lookupName(const char *name) const;
+ void appendNameDefines(String8 *str) const;
+ void appendVarDefines(String8 *str) const;
+
+ ProgramFragment * getDefaultProgramFragment() const {
+ return mStateFragment.mDefault.get();
+ }
+ ProgramVertex * getDefaultProgramVertex() const {
+ return mStateVertex.mDefault.get();
+ }
+ ProgramFragmentStore * getDefaultProgramFragmentStore() const {
+ return mStateFragmentStore.mDefault.get();
+ }
+
+ void addInt32Define(const char* name, int32_t value) {
+ mInt32Defines.add(String8(name), value);
+ }
+
+ void addFloatDefine(const char* name, float value) {
+ mFloatDefines.add(String8(name), value);
+ }
+
+ uint32_t getWidth() const {return mWidth;}
+ uint32_t getHeight() const {return mHeight;}
+
+
+ ThreadIO mIO;
+
+protected:
+ Device *mDev;
+
+ EGLint mNumConfigs;
+ EGLint mMajorVersion;
+ EGLint mMinorVersion;
+ EGLConfig mConfig;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLDisplay mDisplay;
+
+ bool mRunning;
+ bool mExit;
+
+ pthread_t mThreadId;
+
+ ObjectBaseRef<Script> mRootScript;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+private:
+ Context();
+
+ void initEGL();
+
+ bool runScript(Script *s, uint32_t launchID);
+ bool runRootScript();
+
+ static void * threadProc(void *);
+
+ // todo: put in TLS
+ static Context *gCon;
+ Surface *mWndSurface;
+
+ Vector<ObjectBase *> mNames;
+ KeyedVector<String8,int> mInt32Defines;
+ KeyedVector<String8,float> mFloatDefines;
+};
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
new file mode 100644
index 0000000..1b3c41b
--- /dev/null
+++ b/libs/rs/rsDevice.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include "rsDevice.h"
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Device::Device()
+{
+
+}
+
+Device::~Device()
+{
+
+}
+
+void Device::addContext(Context *rsc)
+{
+ mContexts.add(rsc);
+}
+
+void Device::removeContext(Context *rsc)
+{
+ for (size_t idx=0; idx < mContexts.size(); idx++) {
+ if (mContexts[idx] == rsc) {
+ mContexts.removeAt(idx);
+ break;
+ }
+ }
+}
+
+
+
+RsDevice rsDeviceCreate()
+{
+ Device * d = new Device();
+ return d;
+}
+
+void rsDeviceDestroy(RsDevice dev)
+{
+ Device * d = static_cast<Device *>(dev);
+ delete d;
+
+}
+
diff --git a/libs/rs/rsDevice.h b/libs/rs/rsDevice.h
new file mode 100644
index 0000000..156315f
--- /dev/null
+++ b/libs/rs/rsDevice.h
@@ -0,0 +1,48 @@
+/*
+ * 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 ANDROID_RS_DEVICE_H
+#define ANDROID_RS_DEVICE_H
+
+#include "rsUtils.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class Device {
+public:
+ Device();
+ ~Device();
+
+ void addContext(Context *);
+ void removeContext(Context *);
+
+protected:
+ Vector<Context *> mContexts;
+
+
+};
+
+
+
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
new file mode 100644
index 0000000..97b18c0
--- /dev/null
+++ b/libs/rs/rsElement.cpp
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+void ElementState::initPredefined()
+{
+ Component * u_8 = new Component(Component::USER, Component::UNSIGNED, true, 8, 0);
+ Component * i_8 = new Component(Component::USER, Component::SIGNED, true, 8, 0);
+ Component * u_16 = new Component(Component::USER, Component::UNSIGNED, true, 16, 0);
+ Component * i_16 = new Component(Component::USER, Component::SIGNED, true, 16, 0);
+ Component * u_32 = new Component(Component::USER, Component::UNSIGNED, true, 32, 0);
+ Component * i_32 = new Component(Component::USER, Component::SIGNED, true, 32, 0);
+ Component * f_32 = new Component(Component::USER, Component::FLOAT, true, 32, 0);
+
+
+ Component * r_4 = new Component(Component::RED, Component::UNSIGNED, true, 4, 0);
+ Component * r_5 = new Component(Component::RED, Component::UNSIGNED, true, 5, 0);
+ Component * r_8 = new Component(Component::RED, Component::UNSIGNED, true, 8, 0);
+
+ Component * g_4 = new Component(Component::GREEN, Component::UNSIGNED, true, 4, 0);
+ Component * g_5 = new Component(Component::GREEN, Component::UNSIGNED, true, 5, 0);
+ Component * g_6 = new Component(Component::GREEN, Component::UNSIGNED, true, 6, 0);
+ Component * g_8 = new Component(Component::GREEN, Component::UNSIGNED, true, 8, 0);
+
+ Component * b_4 = new Component(Component::BLUE, Component::UNSIGNED, true, 4, 0);
+ Component * b_5 = new Component(Component::BLUE, Component::UNSIGNED, true, 5, 0);
+ Component * b_8 = new Component(Component::BLUE, Component::UNSIGNED, true, 8, 0);
+
+ Component * a_1 = new Component(Component::ALPHA, Component::UNSIGNED, true, 1, 0);
+ Component * a_4 = new Component(Component::ALPHA, Component::UNSIGNED, true, 4, 0);
+ Component * a_8 = new Component(Component::ALPHA, Component::UNSIGNED, true, 8, 0);
+
+ Component * idx_16 = new Component(Component::INDEX, Component::UNSIGNED, false, 16, 0);
+ Component * idx_32 = new Component(Component::INDEX, Component::UNSIGNED, false, 32, 0);
+
+ Component * x = new Component(Component::X, Component::FLOAT, false, 32, 0);
+ Component * y = new Component(Component::Y, Component::FLOAT, false, 32, 0);
+ Component * z = new Component(Component::Z, Component::FLOAT, false, 32, 0);
+
+ Component * nx = new Component(Component::NX, Component::FLOAT, false, 32, 0);
+ Component * ny = new Component(Component::NY, Component::FLOAT, false, 32, 0);
+ Component * nz = new Component(Component::NZ, Component::FLOAT, false, 32, 0);
+
+ Component * s = new Component(Component::S, Component::FLOAT, false, 32, 0);
+ Component * t = new Component(Component::T, Component::FLOAT, false, 32, 0);
+
+ Element * e;
+
+ e = new Element(1);
+ e->setComponent(0, u_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U8, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I8, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U16, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I16, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U32, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I32, e));
+
+ e = new Element(1);
+ e->setComponent(0, f_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_FLOAT, e));
+
+ e = new Element(1);
+ e->setComponent(0, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_A_8, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_6);
+ e->setComponent(2, b_5);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_565, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_5);
+ e->setComponent(2, b_5);
+ e->setComponent(3, a_1);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_5551, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_4);
+ e->setComponent(1, g_4);
+ e->setComponent(2, b_4);
+ e->setComponent(3, a_4);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_4444, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_888, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ e->setComponent(3, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_8888, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_16, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_32, e));
+
+ e = new Element(2);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XY_F32, e));
+
+ e = new Element(3);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ e->setComponent(2, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XYZ_F32, e));
+
+ e = new Element(4);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XY_F32, e));
+
+ e = new Element(5);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ e->setComponent(4, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XYZ_F32, e));
+
+ e = new Element(6);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, x);
+ e->setComponent(4, y);
+ e->setComponent(5, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_XYZ_F32, e));
+
+ e = new Element(8);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, s);
+ e->setComponent(4, t);
+ e->setComponent(5, x);
+ e->setComponent(6, y);
+ e->setComponent(7, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_ST_XYZ_F32, e));
+}
+
+
+Element::Element()
+{
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+Element::Element(uint32_t count)
+{
+ mComponents = new ObjectBaseRef<Component> [count];
+ mComponentCount = count;
+}
+
+Element::~Element()
+{
+ clear();
+}
+
+void Element::clear()
+{
+ delete [] mComponents;
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+void Element::setComponent(uint32_t idx, Component *c)
+{
+ rsAssert(!mComponents[idx].get());
+ rsAssert(idx < mComponentCount);
+ mComponents[idx].set(c);
+ c->incRef();
+}
+
+
+size_t Element::getSizeBits() const
+{
+ size_t total = 0;
+ for (size_t ct=0; ct < mComponentCount; ct++) {
+ total += mComponents[ct]->getBits();
+ }
+ return total;
+}
+
+size_t Element::getComponentOffsetBits(uint32_t componentNumber) const
+{
+ size_t offset = 0;
+ for (uint32_t ct = 0; ct < componentNumber; ct++) {
+ offset += mComponents[ct]->getBits();
+ }
+ return offset;
+}
+
+uint32_t Element::getGLType() const
+{
+ int bits[4];
+
+ if (mComponentCount > 4) {
+ return 0;
+ }
+
+ for (uint32_t ct=0; ct < mComponentCount; ct++) {
+ bits[ct] = mComponents[ct]->getBits();
+ if (mComponents[ct]->getType() != Component::UNSIGNED) {
+ return 0;
+ }
+ if (!mComponents[ct]->getIsNormalized()) {
+ return 0;
+ }
+ }
+
+ switch(mComponentCount) {
+ case 1:
+ if (bits[0] == 8) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 2:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 3:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 6) &&
+ (bits[2] == 5)) {
+ return GL_UNSIGNED_SHORT_5_6_5;
+ }
+ return 0;
+ case 4:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8) &&
+ (bits[3] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 4) &&
+ (bits[1] == 4) &&
+ (bits[2] == 4) &&
+ (bits[3] == 4)) {
+ return GL_UNSIGNED_SHORT_4_4_4_4;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 5) &&
+ (bits[2] == 5) &&
+ (bits[3] == 1)) {
+ return GL_UNSIGNED_SHORT_5_5_5_1;
+ }
+ }
+ return 0;
+}
+
+uint32_t Element::getGLFormat() const
+{
+ switch(mComponentCount) {
+ case 1:
+ if (mComponents[0]->getKind() == Component::ALPHA) {
+ return GL_ALPHA;
+ }
+ if (mComponents[0]->getKind() == Component::LUMINANCE) {
+ return GL_LUMINANCE;
+ }
+ break;
+ case 2:
+ if ((mComponents[0]->getKind() == Component::LUMINANCE) &&
+ (mComponents[1]->getKind() == Component::ALPHA)) {
+ return GL_LUMINANCE_ALPHA;
+ }
+ break;
+ case 3:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE)) {
+ return GL_RGB;
+ }
+ break;
+ case 4:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE) &&
+ (mComponents[3]->getKind() == Component::ALPHA)) {
+ return GL_RGBA;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+ElementState::ElementState()
+{
+}
+
+ElementState::~ElementState()
+{
+}
+
+/////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_ElementBegin(Context *rsc)
+{
+ rsc->mStateElement.mComponentBuildList.clear();
+}
+
+void rsi_ElementAddPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ RsElement ve = rsi_ElementGetPredefined(rsc, predef);
+ const Element *e = static_cast<const Element *>(ve);
+
+ for(size_t ct = 0; ct < sec->mPredefinedList[predef].mElement->getComponentCount(); ct++) {
+ sec->mComponentBuildList.add(sec->mPredefinedList[predef].mElement->getComponent(ct));
+ }
+}
+
+RsElement rsi_ElementGetPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ if (!sec->mPredefinedList.size()) {
+ sec->initPredefined();
+ }
+
+ if ((predef < 0) ||
+ (static_cast<uint32_t>(predef) >= sec->mPredefinedList.size())) {
+ LOGE("rsElementGetPredefined: Request for bad predefined type");
+ // error
+ return NULL;
+ }
+
+ rsAssert(sec->mPredefinedList[predef].mEnum == predef);
+ Element * e = sec->mPredefinedList[predef].mElement;
+ e->incRef();
+ return e;
+}
+
+void rsi_ElementAdd(Context *rsc, RsDataKind dk, RsDataType dt, bool isNormalized, size_t bits, const char *name)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Component *c = new Component(static_cast<Component::DataKind>(dk),
+ static_cast<Component::DataType>(dt),
+ isNormalized,
+ bits,
+ name);
+ sec->mComponentBuildList.add(c);
+}
+
+RsElement rsi_ElementCreate(Context *rsc)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Element *se = new Element(sec->mComponentBuildList.size());
+
+ for (size_t ct = 0; ct < se->getComponentCount(); ct++) {
+ se->setComponent(ct, sec->mComponentBuildList[ct]);
+ }
+
+ rsc->mStateElement.mComponentBuildList.clear();
+ se->incRef();
+ return se;
+}
+
+void rsi_ElementDestroy(Context *rsc, RsElement vse)
+{
+ Element * se = static_cast<Element *>(vse);
+ se->decRef();
+}
+
+
+}
+}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
new file mode 100644
index 0000000..0918522
--- /dev/null
+++ b/libs/rs/rsElement.h
@@ -0,0 +1,95 @@
+/*
+ * 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 ANDROID_STRUCTURED_ELEMENT_H
+#define ANDROID_STRUCTURED_ELEMENT_H
+
+#include "rsComponent.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Element : public ObjectBase
+{
+public:
+ Element(uint32_t count);
+ ~Element();
+
+
+ void setComponent(uint32_t idx, Component *c);
+
+ uint32_t getGLType() const;
+ uint32_t getGLFormat() const;
+
+
+ size_t getSizeBits() const;
+ size_t getSizeBytes() const {
+ return (getSizeBits() + 7) >> 3;
+ }
+
+ size_t getComponentOffsetBits(uint32_t componentNumber) const;
+ size_t getComponentOffsetBytes(uint32_t componentNumber) const {
+ return (getComponentOffsetBits(componentNumber) + 7) >> 3;
+ }
+
+ uint32_t getComponentCount() const {return mComponentCount;}
+ Component * getComponent(uint32_t idx) const {return mComponents[idx].get();}
+
+protected:
+ // deallocate any components that are part of this element.
+ void clear();
+
+ size_t mComponentCount;
+ ObjectBaseRef<Component> * mComponents;
+ //uint32_t *mOffsetTable;
+
+ Element();
+};
+
+
+class ElementState {
+public:
+ ElementState();
+ ~ElementState();
+
+ Vector<Component *> mComponentBuildList;
+
+
+
+ struct Predefined {
+ Predefined() {
+ mElement = NULL;
+ }
+ Predefined(RsElementPredefined en, Element *e) {
+ mEnum = en;
+ mElement = e;
+ }
+ RsElementPredefined mEnum;
+ Element * mElement;
+ };
+ Vector<Predefined> mPredefinedList;
+
+ void initPredefined();
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_ELEMENT_H
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
new file mode 100644
index 0000000..347ef23
--- /dev/null
+++ b/libs/rs/rsFileA3D.cpp
@@ -0,0 +1,384 @@
+
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+
+#include <utils/String8.h>
+#include "rsFileA3D.h"
+
+#include "rsMesh.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+FileA3D::FileA3D()
+{
+ mRsc = NULL;
+}
+
+FileA3D::~FileA3D()
+{
+}
+
+bool FileA3D::load(Context *rsc, FILE *f)
+{
+ char magicString[12];
+ size_t len;
+
+ LOGE("file open 1");
+ len = fread(magicString, 1, 12, f);
+ if ((len != 12) ||
+ memcmp(magicString, "Android3D_ff", 12)) {
+ return false;
+ }
+
+ LOGE("file open 2");
+ len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f);
+ if (len != sizeof(mMajorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 3");
+ len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f);
+ if (len != sizeof(mMinorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 4");
+ uint32_t flags;
+ len = fread(&flags, 1, sizeof(flags), f);
+ if (len != sizeof(flags)) {
+ return false;
+ }
+ mUse64BitOffsets = (flags & 1) != 0;
+
+ LOGE("file open 64bit = %i", mUse64BitOffsets);
+
+ if (mUse64BitOffsets) {
+ len = fread(&mDataSize, 1, sizeof(mDataSize), f);
+ if (len != sizeof(mDataSize)) {
+ return false;
+ }
+ } else {
+ uint32_t tmp;
+ len = fread(&tmp, 1, sizeof(tmp), f);
+ if (len != sizeof(tmp)) {
+ return false;
+ }
+ mDataSize = tmp;
+ }
+
+ LOGE("file open size = %lli", mDataSize);
+
+ // We should know enough to read the file in at this point.
+ fseek(f, SEEK_SET, 0);
+ mAlloc= malloc(mDataSize);
+ if (!mAlloc) {
+ return false;
+ }
+ mData = (uint8_t *)mAlloc;
+ len = fread(mAlloc, 1, mDataSize, f);
+ if (len != mDataSize) {
+ return false;
+ }
+
+ LOGE("file start processing");
+ return process(rsc);
+}
+
+bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie)
+{
+ bool ret = false;
+ IO io(mData + ie->mOffset, mUse64BitOffsets);
+
+ LOGE("process index, type %i", ie->mType);
+
+ switch(ie->mType) {
+ case CHUNK_ELEMENT:
+ processChunk_Element(rsc, &io, ie);
+ break;
+ case CHUNK_ELEMENT_SOURCE:
+ processChunk_ElementSource(rsc, &io, ie);
+ break;
+ case CHUNK_VERTICIES:
+ processChunk_Verticies(rsc, &io, ie);
+ break;
+ case CHUNK_MESH:
+ processChunk_Mesh(rsc, &io, ie);
+ break;
+ case CHUNK_PRIMITIVE:
+ processChunk_Primitive(rsc, &io, ie);
+ break;
+ default:
+ LOGE("FileA3D Unknown chunk type");
+ break;
+ }
+ return (ie->mRsObj != NULL);
+}
+
+bool FileA3D::process(Context *rsc)
+{
+ LOGE("process");
+ IO io(mData + 12, mUse64BitOffsets);
+ bool ret = true;
+
+ // Build the index first
+ LOGE("process 1");
+ io.loadU32(); // major version, already loaded
+ io.loadU32(); // minor version, already loaded
+ LOGE("process 2");
+
+ io.loadU32(); // flags
+ io.loadOffset(); // filesize, already loaded.
+ LOGE("process 4");
+ uint64_t mIndexOffset = io.loadOffset();
+ uint64_t mStringOffset = io.loadOffset();
+
+ LOGE("process mIndexOffset= 0x%016llx", mIndexOffset);
+ LOGE("process mStringOffset= 0x%016llx", mStringOffset);
+
+ IO index(mData + mIndexOffset, mUse64BitOffsets);
+ IO stringTable(mData + mStringOffset, mUse64BitOffsets);
+
+ uint32_t stringEntryCount = stringTable.loadU32();
+ LOGE("stringEntryCount %i", stringEntryCount);
+ mStrings.setCapacity(stringEntryCount);
+ mStringIndexValues.setCapacity(stringEntryCount);
+ if (stringEntryCount) {
+ uint32_t stringType = stringTable.loadU32();
+ LOGE("stringType %i", stringType);
+ rsAssert(stringType==0);
+ for (uint32_t ct = 0; ct < stringEntryCount; ct++) {
+ uint64_t offset = stringTable.loadOffset();
+ LOGE("string offset 0x%016llx", offset);
+ IO tmp(mData + offset, mUse64BitOffsets);
+ String8 s;
+ tmp.loadString(&s);
+ LOGE("string %s", s.string());
+ mStrings.push(s);
+ }
+ }
+
+ LOGE("strings done");
+ uint32_t indexEntryCount = index.loadU32();
+ LOGE("index count %i", indexEntryCount);
+ mIndex.setCapacity(indexEntryCount);
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ A3DIndexEntry e;
+ uint32_t stringIndex = index.loadU32();
+ LOGE("index %i", ct);
+ LOGE(" string index %i", stringIndex);
+ e.mType = (A3DChunkType)index.loadU32();
+ LOGE(" type %i", e.mType);
+ e.mOffset = index.loadOffset();
+ LOGE(" offset 0x%016llx", e.mOffset);
+
+ if (stringIndex && (stringIndex < mStrings.size())) {
+ e.mID = mStrings[stringIndex];
+ mStringIndexValues.editItemAt(stringIndex) = ct;
+ LOGE(" id %s", e.mID.string());
+ }
+
+ mIndex.push(e);
+ }
+ LOGE("index done");
+
+ // At this point the index should be fully populated.
+ // We can now walk though it and load all the objects.
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ LOGE("processing index entry %i", ct);
+ processIndex(rsc, &mIndex.editItemAt(ct));
+ }
+
+ return ret;
+}
+
+
+FileA3D::IO::IO(const uint8_t *buf, bool use64)
+{
+ mData = buf;
+ mPos = 0;
+ mUse64 = use64;
+}
+
+uint64_t FileA3D::IO::loadOffset()
+{
+ uint64_t tmp;
+ if (mUse64) {
+ mPos = (mPos + 7) & (~7);
+ tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint64_t);
+ return tmp;
+ }
+ return loadU32();
+}
+
+void FileA3D::IO::loadString(String8 *s)
+{
+ LOGE("loadString");
+ uint32_t len = loadU32();
+ LOGE("loadString len %i", len);
+ s->setTo((const char *)&mData[mPos], len);
+ mPos += len;
+}
+
+
+void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh * m = new Mesh;
+
+ m->mPrimitivesCount = io->loadU32();
+ m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount];
+
+ for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) {
+ uint32_t index = io->loadU32();
+
+ m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj;
+ }
+ ie->mRsObj = m;
+}
+
+void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Primitive_t * p = new Mesh::Primitive_t;
+
+ p->mIndexCount = io->loadU32();
+ uint32_t vertIdx = io->loadU32();
+ p->mRestartCounts = io->loadU16();
+ uint32_t bits = io->loadU8();
+ p->mType = (RsPrimitive)io->loadU8();
+
+ LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits);
+
+ p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj;
+
+ p->mIndicies = new uint16_t[p->mIndexCount];
+ for (uint32_t ct = 0; ct < p->mIndexCount; ct++) {
+ switch(bits) {
+ case 8:
+ p->mIndicies[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mIndicies[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mIndicies[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mIndicies[ct]);
+ }
+
+ if (p->mRestartCounts) {
+ p->mRestarts = new uint16_t[p->mRestartCounts];
+ for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) {
+ switch(bits) {
+ case 8:
+ p->mRestarts[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mRestarts[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mRestarts[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mRestarts[ct]);
+ }
+ } else {
+ p->mRestarts = NULL;
+ }
+
+ ie->mRsObj = p;
+}
+
+void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Verticies_t *cv = new Mesh::Verticies_t;
+ cv->mAllocationCount = io->loadU32();
+ cv->mAllocations = new Allocation *[cv->mAllocationCount];
+ LOGE("processChunk_Verticies count %i", cv->mAllocationCount);
+ for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) {
+ uint32_t i = io->loadU32();
+ cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj;
+ LOGE(" idx %i", i);
+ }
+ ie->mRsObj = cv;
+}
+
+void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ rsi_ElementBegin(rsc);
+
+ uint32_t count = io->loadU32();
+ LOGE("processChunk_Element count %i", count);
+ while (count--) {
+ RsDataKind dk = (RsDataKind)io->loadU8();
+ RsDataType dt = (RsDataType)io->loadU8();
+ uint32_t bits = io->loadU8();
+ bool isNorm = io->loadU8() != 0;
+ LOGE(" %i %i %i %i", dk, dt, bits, isNorm);
+ rsi_ElementAdd(rsc, dk, dt, isNorm, bits, 0);
+ }
+ LOGE("processChunk_Element create");
+ ie->mRsObj = rsi_ElementCreate(rsc);
+}
+
+void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ uint32_t index = io->loadU32();
+ uint32_t count = io->loadU32();
+
+ LOGE("processChunk_ElementSource count %i, index %i", count, index);
+
+ RsElement e = (RsElement)mIndex[index].mRsObj;
+
+ RsAllocation a = rsi_AllocationCreateSized(rsc, e, count);
+ Allocation * alloc = static_cast<Allocation *>(a);
+
+ float * data = (float *)alloc->getPtr();
+ while(count--) {
+ *data = io->loadF();
+ LOGE(" %f", *data);
+ data++;
+ }
+ ie->mRsObj = alloc;
+}
+
+namespace android {
+namespace renderscript {
+
+
+RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
+{
+ FileA3D *fa3d = new FileA3D;
+
+ FILE *f = fopen("/sdcard/test.a3d", "rb");
+ if (f) {
+ fa3d->load(rsc, f);
+ fclose(f);
+ return fa3d;
+ }
+ delete fa3d;
+ return NULL;
+}
+
+
+}
+}
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
new file mode 100644
index 0000000..9ee08ec
--- /dev/null
+++ b/libs/rs/rsFileA3D.h
@@ -0,0 +1,122 @@
+/*
+ * 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 ANDROID_RS_FILE_A3D_H
+#define ANDROID_RS_FILE_A3D_H
+
+#include "RenderScript.h"
+#include "rsFileA3DDecls.h"
+#include "rsMesh.h"
+
+#include <utils/String8.h>
+#include <stdio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class FileA3D
+{
+public:
+ FileA3D();
+ ~FileA3D();
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+ uint64_t mIndexOffset;
+ uint64_t mStringTableOffset;
+ bool mUse64BitOffsets;
+
+ struct A3DIndexEntry {
+ String8 mID;
+ A3DChunkType mType;
+ uint64_t mOffset;
+ void * mRsObj;
+ };
+
+ bool load(Context *rsc, FILE *f);
+
+protected:
+ class IO
+ {
+ public:
+ IO(const uint8_t *, bool use64);
+
+ float loadF() {
+ mPos = (mPos + 3) & (~3);
+ float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
+ mPos += sizeof(float);
+ return tmp;
+ }
+ int32_t loadI32() {
+ mPos = (mPos + 3) & (~3);
+ int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
+ mPos += sizeof(int32_t);
+ return tmp;
+ }
+ uint32_t loadU32() {
+ mPos = (mPos + 3) & (~3);
+ uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint32_t);
+ return tmp;
+ }
+ uint16_t loadU16() {
+ mPos = (mPos + 1) & (~1);
+ uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint16_t);
+ return tmp;
+ }
+ uint8_t loadU8() {
+ uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint8_t);
+ return tmp;
+ }
+ uint64_t loadOffset();
+ void loadString(String8 *s);
+ uint64_t getPos() const {return mPos;}
+ const uint8_t * getPtr() const;
+ protected:
+ const uint8_t * mData;
+ uint64_t mPos;
+ bool mUse64;
+ };
+
+
+ bool process(Context *rsc);
+ bool processIndex(Context *rsc, A3DIndexEntry *);
+ void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie);
+
+ const uint8_t * mData;
+ void * mAlloc;
+ uint64_t mDataSize;
+ Context * mRsc;
+
+ Vector<A3DIndexEntry> mIndex;
+ Vector<String8> mStrings;
+ Vector<uint32_t> mStringIndexValues;
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
diff --git a/libs/rs/rsFileA3DDecls.h b/libs/rs/rsFileA3DDecls.h
new file mode 100644
index 0000000..2a08bd3
--- /dev/null
+++ b/libs/rs/rsFileA3DDecls.h
@@ -0,0 +1,44 @@
+/*
+ * 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 ANDROID_RS_FILE_A3D_DECLS_H
+#define ANDROID_RS_FILE_A3D_DECLS_H
+
+
+#define A3D_MAGIC_KEY "Android3D_ff"
+
+namespace android {
+namespace renderscript {
+
+ enum A3DChunkType {
+ CHUNK_EMPTY,
+
+ CHUNK_ELEMENT,
+ CHUNK_ELEMENT_SOURCE,
+ CHUNK_VERTICIES,
+ CHUNK_MESH,
+ CHUNK_PRIMITIVE,
+
+ CHUNK_LAST
+ };
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
+
diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp
new file mode 100644
index 0000000..24b58b6
--- /dev/null
+++ b/libs/rs/rsLight.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Light::Light(bool isLocal, bool isMono)
+{
+ mIsLocal = isLocal;
+ mIsMono = isMono;
+
+ mPosition[0] = 0;
+ mPosition[1] = 0;
+ mPosition[2] = 1;
+ mPosition[3] = 0;
+
+ mColor[0] = 1.f;
+ mColor[1] = 1.f;
+ mColor[2] = 1.f;
+ mColor[3] = 1.f;
+}
+
+Light::~Light()
+{
+}
+
+void Light::setPosition(float x, float y, float z)
+{
+ mPosition[0] = x;
+ mPosition[1] = y;
+ mPosition[2] = z;
+}
+
+void Light::setColor(float r, float g, float b)
+{
+ mColor[0] = r;
+ mColor[1] = g;
+ mColor[2] = b;
+}
+
+void Light::setupGL(uint32_t num) const
+{
+ glLightfv(GL_LIGHT0 + num, GL_DIFFUSE, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_SPECULAR, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_POSITION, mPosition);
+}
+
+////////////////////////////////////////////
+
+LightState::LightState()
+{
+ clear();
+}
+
+LightState::~LightState()
+{
+}
+
+void LightState::clear()
+{
+ mIsLocal = false;
+ mIsMono = false;
+}
+
+
+////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_LightBegin(Context *rsc)
+{
+ rsc->mStateLight.clear();
+}
+
+void rsi_LightSetLocal(Context *rsc, bool isLocal)
+{
+ rsc->mStateLight.mIsLocal = isLocal;
+}
+
+void rsi_LightSetMonochromatic(Context *rsc, bool isMono)
+{
+ rsc->mStateLight.mIsMono = isMono;
+}
+
+RsLight rsi_LightCreate(Context *rsc)
+{
+ Light *l = new Light(rsc->mStateLight.mIsLocal,
+ rsc->mStateLight.mIsMono);
+ l->incRef();
+ 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);
+ l->setColor(r, g, b);
+}
+
+void rsi_LightSetPosition(Context *rsc, RsLight vl, float x, float y, float z)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->setPosition(x, y, z);
+}
+
+
+
+}
+}
diff --git a/libs/rs/rsLight.h b/libs/rs/rsLight.h
new file mode 100644
index 0000000..b0c3386
--- /dev/null
+++ b/libs/rs/rsLight.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ANDROID_LIGHT_H
+#define ANDROID_LIGHT_H
+
+
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Light : public ObjectBase
+{
+public:
+ Light(bool isLocal, bool isMono);
+ virtual ~Light();
+
+ // Values, mutable after creation.
+ void setPosition(float x, float y, float z);
+ void setColor(float r, float g, float b);
+
+ void setupGL(uint32_t num) const;
+
+protected:
+ float mColor[4];
+ float mPosition[4];
+ bool mIsLocal;
+ bool mIsMono;
+};
+
+
+class LightState {
+public:
+ LightState();
+ ~LightState();
+
+ void clear();
+
+ bool mIsMono;
+ bool mIsLocal;
+};
+
+
+}
+}
+#endif //ANDROID_LIGHT_H
+
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
new file mode 100644
index 0000000..c3fee54
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+#include "rsLocklessFifo.h"
+
+using namespace android;
+
+
+LocklessCommandFifo::LocklessCommandFifo()
+{
+}
+
+LocklessCommandFifo::~LocklessCommandFifo()
+{
+}
+
+bool LocklessCommandFifo::init(uint32_t sizeInBytes)
+{
+ // Add room for a buffer reset command
+ mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
+ if (!mBuffer) {
+ LOGE("LocklessFifo allocation failure");
+ return false;
+ }
+
+ if (!mSignalToControl.init() || !mSignalToWorker.init()) {
+ LOGE("Signal setup failed");
+ free(mBuffer);
+ return false;
+ }
+
+ mSize = sizeInBytes;
+ mPut = mBuffer;
+ mGet = mBuffer;
+ mEnd = mBuffer + (sizeInBytes) - 1;
+ dumpState("init");
+ return true;
+}
+
+uint32_t LocklessCommandFifo::getFreeSpace() const
+{
+ int32_t freeSpace = 0;
+ //dumpState("getFreeSpace");
+
+ if (mPut >= mGet) {
+ freeSpace = mEnd - mPut;
+ } else {
+ freeSpace = mGet - mPut;
+ }
+
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+ return freeSpace;
+}
+
+bool LocklessCommandFifo::isEmpty() const
+{
+ return mPut == mGet;
+}
+
+
+void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
+{
+ // Add space for command header and loop token;
+ sizeInBytes += 8;
+
+ //dumpState("reserve");
+ if (getFreeSpace() < sizeInBytes) {
+ makeSpace(sizeInBytes);
+ }
+
+ return mPut + 4;
+}
+
+void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
+{
+ //dumpState("commit 1");
+ reinterpret_cast<uint16_t *>(mPut)[0] = command;
+ reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
+ mPut += ((sizeInBytes + 3) & ~3) + 4;
+ //dumpState("commit 2");
+ mSignalToWorker.set();
+}
+
+void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
+{
+ commit(command, sizeInBytes);
+ flush();
+}
+
+void LocklessCommandFifo::flush()
+{
+ //dumpState("flush 1");
+ while(mPut != mGet) {
+ mSignalToControl.wait();
+ }
+ //dumpState("flush 2");
+}
+
+const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
+{
+ while(1) {
+ //dumpState("get");
+ while(isEmpty()) {
+ mSignalToControl.set();
+ mSignalToWorker.wait();
+ }
+
+ *command = reinterpret_cast<const uint16_t *>(mGet)[0];
+ *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
+ if (*command) {
+ // non-zero command is valid
+ return mGet+4;
+ }
+
+ // zero command means reset to beginning.
+ mGet = mBuffer;
+ }
+}
+
+void LocklessCommandFifo::next()
+{
+ uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
+ mGet += ((bytes + 3) & ~3) + 4;
+ if (isEmpty()) {
+ mSignalToControl.set();
+ }
+ //dumpState("next");
+}
+
+void LocklessCommandFifo::makeSpace(uint32_t bytes)
+{
+ //dumpState("make space");
+ if ((mPut+bytes) > mEnd) {
+ // Need to loop regardless of where get is.
+ while((mGet > mPut) && (mBuffer+4 >= mGet)) {
+ sleep(1);
+ }
+
+ // Toss in a reset then the normal wait for space will do the rest.
+ reinterpret_cast<uint16_t *>(mPut)[0] = 0;
+ reinterpret_cast<uint16_t *>(mPut)[1] = 0;
+ mPut = mBuffer;
+ }
+
+ // it will fit here so we just need to wait for space.
+ while(getFreeSpace() < bytes) {
+ sleep(1);
+ }
+
+}
+
+void LocklessCommandFifo::dumpState(const char *s) const
+{
+ LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
+}
+
+LocklessCommandFifo::Signal::Signal()
+{
+ mSet = true;
+}
+
+LocklessCommandFifo::Signal::~Signal()
+{
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCondition);
+}
+
+bool LocklessCommandFifo::Signal::init()
+{
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("LocklessFifo mutex init failure");
+ return false;
+ }
+
+ status = pthread_cond_init(&mCondition, NULL);
+ if (status) {
+ LOGE("LocklessFifo condition init failure");
+ pthread_mutex_destroy(&mMutex);
+ return false;
+ }
+
+ return true;
+}
+
+void LocklessCommandFifo::Signal::set()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
+ return;
+ }
+
+ mSet = true;
+
+ status = pthread_cond_signal(&mCondition);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i on set condition.", status);
+ }
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
+ }
+}
+
+void LocklessCommandFifo::Signal::wait()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for condition.", status);
+ return;
+ }
+
+ if (!mSet) {
+ status = pthread_cond_wait(&mCondition, &mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
+ }
+ }
+ mSet = false;
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
+ }
+}
+
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
new file mode 100644
index 0000000..abeddf7
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.h
@@ -0,0 +1,89 @@
+/*
+ * 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 ANDROID_RS_LOCKLESS_FIFO_H
+#define ANDROID_RS_LOCKLESS_FIFO_H
+
+
+#include "rsUtils.h"
+
+namespace android {
+
+
+// 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
+// readers or writers by design.
+
+class LocklessCommandFifo
+{
+public:
+ bool init(uint32_t size);
+
+ LocklessCommandFifo();
+ ~LocklessCommandFifo();
+
+
+protected:
+ class Signal {
+ public:
+ Signal();
+ ~Signal();
+
+ bool init();
+
+ void set();
+ void wait();
+
+ protected:
+ bool mSet;
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondition;
+ };
+
+ uint8_t * volatile mPut;
+ uint8_t * volatile mGet;
+ uint8_t * mBuffer;
+ uint8_t * mEnd;
+ uint8_t mSize;
+
+ Signal mSignalToWorker;
+ Signal mSignalToControl;
+
+
+
+public:
+ void * reserve(uint32_t bytes);
+ void commit(uint32_t command, uint32_t bytes);
+ void commitSync(uint32_t command, uint32_t bytes);
+
+ void flush();
+ const void * get(uint32_t *command, uint32_t *bytesData);
+ void next();
+
+ void makeSpace(uint32_t bytes);
+
+ bool isEmpty() const;
+ uint32_t getFreeSpace() const;
+
+
+private:
+ void dumpState(const char *) const;
+};
+
+
+}
+#endif
diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp
new file mode 100644
index 0000000..5f68197
--- /dev/null
+++ b/libs/rs/rsMatrix.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include "rsMatrix.h"
+
+#include "stdlib.h"
+#include "string.h"
+#include "math.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+void Matrix::loadIdentity()
+{
+ set(0, 0, 1);
+ set(1, 0, 0);
+ set(2, 0, 0);
+ set(3, 0, 0);
+
+ set(0, 1, 0);
+ set(1, 1, 1);
+ set(2, 1, 0);
+ set(3, 1, 0);
+
+ set(0, 2, 0);
+ set(1, 2, 0);
+ set(2, 2, 1);
+ set(3, 2, 0);
+
+ set(0, 3, 0);
+ set(1, 3, 0);
+ set(2, 3, 0);
+ set(3, 3, 1);
+}
+
+void Matrix::load(const float *v)
+{
+ memcpy(m, v, sizeof(m));
+}
+
+void Matrix::load(const Matrix *v)
+{
+ memcpy(m, v->m, sizeof(m));
+}
+
+void Matrix::loadRotate(float rot, float x, float y, float z)
+{
+ float c, s;
+ m[3] = 0;
+ m[7] = 0;
+ m[11]= 0;
+ m[12]= 0;
+ m[13]= 0;
+ m[14]= 0;
+ m[15]= 1;
+ rot *= float(M_PI / 180.0f);
+ c = cosf(rot);
+ s = sinf(rot);
+
+ const float len = sqrtf(x*x + y*y + z*z);
+ if (!(len != 1)) {
+ const float recipLen = 1.f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ const float nc = 1.0f - c;
+ const float xy = x * y;
+ const float yz = y * z;
+ const float zx = z * x;
+ const float xs = x * s;
+ const float ys = y * s;
+ const float zs = z * s;
+ m[ 0] = x*x*nc + c;
+ m[ 4] = xy*nc - zs;
+ m[ 8] = zx*nc + ys;
+ m[ 1] = xy*nc + zs;
+ m[ 5] = y*y*nc + c;
+ m[ 9] = yz*nc - xs;
+ m[ 2] = zx*nc - ys;
+ m[ 6] = yz*nc + xs;
+ m[10] = z*z*nc + c;
+}
+
+void Matrix::loadScale(float x, float y, float z)
+{
+ loadIdentity();
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+}
+
+void Matrix::loadTranslate(float x, float y, float z)
+{
+ loadIdentity();
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+}
+
+void Matrix::loadMultiply(const Matrix *lhs, const Matrix *rhs)
+{
+ for (int i=0 ; i<4 ; i++) {
+ float ri0 = 0;
+ float ri1 = 0;
+ float ri2 = 0;
+ float ri3 = 0;
+ for (int j=0 ; j<4 ; j++) {
+ const float rhs_ij = rhs->get(i,j);
+ ri0 += lhs->get(j,0) * rhs_ij;
+ ri1 += lhs->get(j,1) * rhs_ij;
+ ri2 += lhs->get(j,2) * rhs_ij;
+ ri3 += lhs->get(j,3) * rhs_ij;
+ }
+ set(i,0, ri0);
+ set(i,1, ri1);
+ set(i,2, ri2);
+ set(i,3, ri3);
+ }
+}
+
+void Matrix::loadOrtho(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 / (r - l);
+ m[5] = 2 / (t - b);
+ m[10]= -2 / (f - n);
+ m[12]= -(r + l) / (r - l);
+ m[13]= -(t + b) / (t - b);
+ m[14]= -(f + n) / (f - n);
+}
+
+void Matrix::loadFrustum(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 * n / (r - l);
+ m[5] = 2 * n / (t - b);
+ m[8] = (r + l) / (r - l);
+ m[9] = (t + b) / (t - b);
+ m[10]= -(f + n) / (f - n);
+ m[11]= -1;
+ m[14]= -2*f*n / (f - n);
+ m[15]= 0;
+}
+
+
diff --git a/libs/rs/rsMatrix.h b/libs/rs/rsMatrix.h
new file mode 100644
index 0000000..7dc4165
--- /dev/null
+++ b/libs/rs/rsMatrix.h
@@ -0,0 +1,87 @@
+/*
+ * 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 ANDROID_RS_MATRIX_H
+#define ANDROID_RS_MATRIX_H
+
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+struct Matrix
+{
+ float m[16];
+
+ inline float get(int i, int j) const {
+ return m[i*4 + j];
+ }
+
+ inline void set(int i, int j, float v) {
+ m[i*4 + j] = v;
+ }
+
+ void loadIdentity();
+ void load(const float *);
+ void load(const Matrix *);
+
+ void loadRotate(float rot, float x, float y, float z);
+ void loadScale(float x, float y, float z);
+ void loadTranslate(float x, float y, float z);
+ void loadMultiply(const Matrix *lhs, const Matrix *rhs);
+
+ void loadOrtho(float l, float r, float b, float t, float n, float f);
+ void loadFrustum(float l, float r, float b, float t, float n, float f);
+
+ void multiply(const Matrix *rhs) {
+ Matrix tmp;
+ tmp.loadMultiply(this, rhs);
+ load(&tmp);
+ }
+ void rotate(float rot, float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadRotate(rot, x, y, z);
+ multiply(&tmp);
+ }
+ void scale(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadScale(x, y, z);
+ multiply(&tmp);
+ }
+ void translate(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadTranslate(x, y, z);
+ multiply(&tmp);
+ }
+
+
+
+};
+
+
+
+}
+}
+
+
+
+
+#endif
+
+
+
+
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
new file mode 100644
index 0000000..aeb52ed
--- /dev/null
+++ b/libs/rs/rsMesh.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+Mesh::Mesh()
+{
+ mVerticies = NULL;
+ mVerticiesCount = 0;
+ mPrimitives = NULL;
+ mPrimitivesCount = 0;
+}
+
+Mesh::~Mesh()
+{
+}
+
+
+
+MeshContext::MeshContext()
+{
+}
+
+MeshContext::~MeshContext()
+{
+}
+
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
new file mode 100644
index 0000000..be207a3
--- /dev/null
+++ b/libs/rs/rsMesh.h
@@ -0,0 +1,90 @@
+/*
+ * 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 ANDROID_RS_MESH_H
+#define ANDROID_RS_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Mesh : public ObjectBase
+{
+public:
+ Mesh();
+ ~Mesh();
+
+ struct Verticies_t
+ {
+ Allocation ** mAllocations;
+ uint32_t mAllocationCount;
+
+ size_t mVertexDataSize;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ uint32_t mBufferObject;
+ };
+
+ struct Primitive_t
+ {
+ RsPrimitive mType;
+ Verticies_t *mVerticies;
+
+ uint32_t mIndexCount;
+ uint16_t *mIndicies;
+
+ uint32_t mRestartCounts;
+ uint16_t *mRestarts;
+ };
+
+ Verticies_t * mVerticies;
+ uint32_t mVerticiesCount;
+
+ Primitive_t ** mPrimitives;
+ uint32_t mPrimitivesCount;
+
+
+
+ void analyzeElement();
+protected:
+};
+
+class MeshContext
+{
+public:
+ MeshContext();
+ ~MeshContext();
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
+
diff --git a/libs/rs/rsNoise.cpp b/libs/rs/rsNoise.cpp
new file mode 100644
index 0000000..764dc1a
--- /dev/null
+++ b/libs/rs/rsNoise.cpp
@@ -0,0 +1,256 @@
+/*
+ * This implementation of the noise functions was ported from the Java
+ * implementation by Jerry Huxtable (http://www.jhlabs.com) under
+ * Apache License 2.0 (see http://jhlabs.com/ip/filters/download.html)
+ *
+ * Original header:
+ *
+ * Copyright 2006 Jerry Huxtable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsNoise.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+namespace android {
+namespace renderscript {
+
+#define B 0x100
+#define BM 0xff
+#define N 0x1000
+
+static int p[B + B + 2];
+static float g3[B + B + 2][3];
+static float g2[B + B + 2][2];
+static float g1[B + B + 2];
+static bool noise_start = true;
+
+#define lerpf(start, stop, amount) start + (stop - start) * amount
+
+static inline float noise_sCurve(float t)
+{
+ return t * t * (3.0f - 2.0f * t);
+}
+
+inline void SC_normalizef2(float v[])
+{
+ float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+}
+
+inline void SC_normalizef3(float v[])
+{
+ float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+ v[2] = v[2] / s;
+}
+
+static void noise_init()
+{
+ int i, j, k;
+
+ for (i = 0; i < B; i++) {
+ p[i] = i;
+
+ g1[i] = (float)((rand() % (B + B)) - B) / B;
+
+ for (j = 0; j < 2; j++)
+ g2[i][j] = (float)((rand() % (B + B)) - B) / B;
+ SC_normalizef2(g2[i]);
+
+ for (j = 0; j < 3; j++)
+ g3[i][j] = (float)((rand() % (B + B)) - B) / B;
+ SC_normalizef3(g3[i]);
+ }
+
+ for (i = B-1; i >= 0; i--) {
+ k = p[i];
+ p[i] = p[j = rand() % B];
+ p[j] = k;
+ }
+
+ for (i = 0; i < B + 2; i++) {
+ p[B + i] = p[i];
+ g1[B + i] = g1[i];
+ for (j = 0; j < 2; j++)
+ g2[B + i][j] = g2[i][j];
+ for (j = 0; j < 3; j++)
+ g3[B + i][j] = g3[i][j];
+ }
+}
+
+float SC_noisef(float x)
+{
+ srand(time(NULL));
+ int bx0, bx1;
+ float rx0, rx1, sx, t, u, v;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ sx = noise_sCurve(rx0);
+
+ u = rx0 * g1[p[bx0]];
+ v = rx1 * g1[p[bx1]];
+ return 2.3f * lerpf(u, v, sx);
+}
+
+float SC_noisef2(float x, float y)
+{
+ srand(time(NULL));
+ int bx0, bx1, by0, by1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
+ float *q;
+ int i, j;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ t = y + N;
+ by0 = ((int)t) & BM;
+ by1 = (by0+1) & BM;
+ ry0 = t - (int)t;
+ ry1 = ry0 - 1.0f;
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ sx = noise_sCurve(rx0);
+ sy = noise_sCurve(ry0);
+
+ q = g2[b00]; u = rx0 * q[0] + ry0 * q[1];
+ q = g2[b10]; v = rx1 * q[0] + ry0 * q[1];
+ a = lerpf(u, v, sx);
+
+ q = g2[b01]; u = rx0 * q[0] + ry1 * q[1];
+ q = g2[b11]; v = rx1 * q[0] + ry1 * q[1];
+ b = lerpf(u, v, sx);
+
+ return 1.5f*lerpf(a, b, sy);
+}
+
+float SC_noisef3(float x, float y, float z)
+{
+ srand(time(NULL));
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
+ float *q;
+ int i, j;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ t = y + N;
+ by0 = ((int)t) & BM;
+ by1 = (by0+1) & BM;
+ ry0 = t - (int)t;
+ ry1 = ry0 - 1.0f;
+
+ t = z + N;
+ bz0 = ((int)t) & BM;
+ bz1 = (bz0+1) & BM;
+ rz0 = t - (int)t;
+ rz1 = rz0 - 1.0f;
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ t = noise_sCurve(rx0);
+ sy = noise_sCurve(ry0);
+ sz = noise_sCurve(rz0);
+
+ q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2];
+ q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2];
+ a = lerpf(u, v, t);
+
+ q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2];
+ q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2];
+ b = lerpf(u, v, t);
+
+ c = lerpf(a, b, sy);
+
+ q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2];
+ q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2];
+ a = lerpf(u, v, t);
+
+ q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2];
+ q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2];
+ b = lerpf(u, v, t);
+
+ d = lerpf(a, b, sy);
+
+ return 1.5f*lerpf(c, d, sz);
+}
+
+float SC_turbulencef2(float x, float y, float octaves)
+{
+ srand(time(NULL));
+ float t = 0.0f;
+
+ for (float f = 1.0f; f <= octaves; f *= 2)
+ t += fabs(SC_noisef2(f * x, f * y)) / f;
+ return t;
+}
+
+float SC_turbulencef3(float x, float y, float z, float octaves)
+{
+ srand(time(NULL));
+ float t = 0.0f;
+
+ for (float f = 1.0f; f <= octaves; f *= 2)
+ t += fabs(SC_noisef3(f * x, f * y, f * z)) / f;
+ return t;
+}
+
+}
+}
\ No newline at end of file
diff --git a/libs/rs/rsNoise.h b/libs/rs/rsNoise.h
new file mode 100644
index 0000000..9040751
--- /dev/null
+++ b/libs/rs/rsNoise.h
@@ -0,0 +1,35 @@
+/*
+ * 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 ANDROID_RS_NOISE_H
+#define ANDROID_RS_NOISE_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+void SC_normalizef2(float v[]);
+void SC_normalizef3(float v[]);
+float SC_noisef(float x);
+float SC_noisef2(float x, float y);
+float SC_noisef3(float x, float y, float z);
+float SC_turbulencef2(float x, float y, float octaves);
+float SC_turbulencef3(float x, float y, float z, float octaves);
+
+}
+}
+
+#endif
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
new file mode 100644
index 0000000..6a5b7d8
--- /dev/null
+++ b/libs/rs/rsObjectBase.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include "rsObjectBase.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ObjectBase::ObjectBase()
+{
+ mRefCount = 0;
+ mName = NULL;
+}
+
+ObjectBase::~ObjectBase()
+{
+ //LOGV("~ObjectBase %p ref %i", this, mRefCount);
+ rsAssert(!mRefCount);
+}
+
+void ObjectBase::incRef() const
+{
+ mRefCount ++;
+ //LOGV("ObjectBase %p inc ref %i", this, mRefCount);
+}
+
+void ObjectBase::decRef() const
+{
+ rsAssert(mRefCount > 0);
+ mRefCount --;
+ //LOGV("ObjectBase %p dec ref %i", this, mRefCount);
+ if (!mRefCount) {
+ delete this;
+ }
+}
+
+void ObjectBase::setName(const char *name)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[strlen(name) +1];
+ strcpy(mName, name);
+ }
+}
+
+void ObjectBase::setName(const char *name, uint32_t len)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[len + 1];
+ memcpy(mName, name, len);
+ mName[len] = 0;
+ }
+}
+
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
new file mode 100644
index 0000000..b2c3338
--- /dev/null
+++ b/libs/rs/rsObjectBase.h
@@ -0,0 +1,114 @@
+/*
+ * 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 ANDROID_RS_OBJECT_BASE_H
+#define ANDROID_RS_OBJECT_BASE_H
+
+#include "rsUtils.h"
+
+
+namespace android {
+namespace renderscript {
+
+// An element is a group of Components that occupies one cell in a structure.
+class ObjectBase
+{
+public:
+ ObjectBase();
+ virtual ~ObjectBase();
+
+ void incRef() const;
+ void decRef() const;
+
+ const char * getName() const {
+ return mName;
+ }
+ void setName(const char *);
+ void setName(const char *, uint32_t len);
+
+private:
+ char * mName;
+ mutable int32_t mRefCount;
+
+
+};
+
+template<class T>
+class ObjectBaseRef
+{
+public:
+ ObjectBaseRef() {
+ mRef = NULL;
+ }
+
+ ObjectBaseRef(const ObjectBaseRef &ref) {
+ mRef = ref.get();
+ if (mRef) {
+ mRef->incRef();
+ }
+ }
+
+ ObjectBaseRef(T *ref) {
+ mRef = ref;
+ if (mRef) {
+ ref->incRef();
+ }
+ }
+
+ ~ObjectBaseRef() {
+ clear();
+ }
+
+ void set(T *ref) {
+ if (mRef != ref) {
+ clear();
+ mRef = ref;
+ if (mRef) {
+ ref->incRef();
+ }
+ }
+ }
+
+ void set(const ObjectBaseRef &ref) {
+ set(ref.mRef);
+ }
+
+ void clear() {
+ if (mRef) {
+ mRef->decRef();
+ }
+ mRef = NULL;
+ }
+
+ inline T * get() const {
+ return mRef;
+ }
+
+ inline T * operator-> () const {
+ return mRef;
+ }
+
+protected:
+ T * mRef;
+
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
new file mode 100644
index 0000000..6606daa
--- /dev/null
+++ b/libs/rs/rsProgram.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgram.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Program::Program(Element *in, Element *out)
+{
+ mElementIn.set(in);
+ mElementOut.set(out);
+
+
+}
+
+Program::~Program()
+{
+}
+
+
+void Program::bindAllocation(Allocation *alloc)
+{
+ mConstants.set(alloc);
+ mDirty = true;
+}
+
+void Program::checkUpdatedAllocation(const Allocation *alloc)
+{
+ if (mConstants.get() == alloc) {
+ mDirty = true;
+ }
+}
+
+void Program::setupGL()
+{
+
+}
+
+
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
new file mode 100644
index 0000000..251072f
--- /dev/null
+++ b/libs/rs/rsProgram.h
@@ -0,0 +1,60 @@
+/*
+ * 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 ANDROID_RS_PROGRAM_H
+#define ANDROID_RS_PROGRAM_H
+
+#include "rsObjectBase.h"
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Program : public ObjectBase
+{
+public:
+ Program(Element *in, Element *out);
+ virtual ~Program();
+
+
+ void bindAllocation(Allocation *);
+
+ virtual void setupGL();
+
+ void checkUpdatedAllocation(const Allocation *);
+
+protected:
+ // Components not listed in "in" will be passed though
+ // unless overwritten by components in out.
+ ObjectBaseRef<Element> mElementIn;
+ ObjectBaseRef<Element> mElementOut;
+
+ ObjectBaseRef<Allocation> mConstants;
+
+ mutable bool mDirty;
+};
+
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
new file mode 100644
index 0000000..a315658
--- /dev/null
+++ b/libs/rs/rsProgramFragment.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragment::ProgramFragment(Element *in, Element *out) :
+ Program(in, out)
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ mEnvModes[ct] = RS_TEX_ENV_MODE_REPLACE;
+ mTextureDimensions[ct] = 2;
+ }
+ mTextureEnableMask = 0;
+ mEnvModes[1] = RS_TEX_ENV_MODE_DECAL;
+}
+
+ProgramFragment::~ProgramFragment()
+{
+}
+
+void ProgramFragment::setupGL(ProgramFragmentState *state)
+{
+ if ((state->mLast.get() == this) && !mDirty) {
+ return;
+ }
+ state->mLast.set(this);
+
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
+ glDisable(GL_TEXTURE_2D);
+ continue;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
+
+ switch(mEnvModes[ct]) {
+ case RS_TEX_ENV_MODE_REPLACE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ break;
+ case RS_TEX_ENV_MODE_MODULATE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ break;
+ case RS_TEX_ENV_MODE_DECAL:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ break;
+ }
+
+ if (mSamplers[ct].get()) {
+ mSamplers[ct]->setupGL();
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+
+ // Gross hack.
+ if (ct == 2) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ mDirty = false;
+}
+
+
+void ProgramFragment::bindTexture(uint32_t slot, Allocation *a)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ //LOGE("bindtex %i %p", slot, a);
+ mTextures[slot].set(a);
+ mDirty = true;
+}
+
+void ProgramFragment::bindSampler(uint32_t slot, Sampler *s)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a Sampler to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mSamplers[slot].set(s);
+ mDirty = true;
+}
+
+void ProgramFragment::setType(uint32_t slot, const Element *e, uint32_t dim)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setType to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ if (dim >= 4) {
+ LOGE("Attempt to setType to a dimension > 3");
+ return;
+ }
+
+ mTextureFormats[slot].set(e);
+ mTextureDimensions[slot] = dim;
+}
+
+void ProgramFragment::setEnvMode(uint32_t slot, RsTexEnvMode env)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mEnvModes[slot] = env;
+}
+
+void ProgramFragment::setTexEnable(uint32_t slot, bool enable)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ uint32_t bit = 1 << slot;
+ mTextureEnableMask &= ~bit;
+ if (enable) {
+ mTextureEnableMask |= bit;
+ }
+}
+
+
+
+ProgramFragmentState::ProgramFragmentState()
+{
+ mPF = NULL;
+}
+
+ProgramFragmentState::~ProgramFragmentState()
+{
+ delete mPF;
+
+}
+
+void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragment *pf = new ProgramFragment(NULL, NULL);
+ mDefault.set(pf);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragment.mPF;
+ rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out);
+}
+
+void rsi_ProgramFragmentBindTexture(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsAllocation a)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindTexture(slot, static_cast<Allocation *>(a));
+}
+
+void rsi_ProgramFragmentBindSampler(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsSampler s)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindSampler(slot, static_cast<Sampler *>(s));
+}
+
+void rsi_ProgramFragmentSetType(Context *rsc, uint32_t slot, RsType vt)
+{
+ const Type *t = static_cast<const Type *>(vt);
+ uint32_t dim = 1;
+ if (t->getDimY()) {
+ dim ++;
+ if (t->getDimZ()) {
+ 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);
+}
+
+RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc)
+{
+ ProgramFragment *pf = rsc->mStateFragment.mPF;
+ pf->incRef();
+ rsc->mStateFragment.mPF = 0;
+ 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
new file mode 100644
index 0000000..57fb6a5
--- /dev/null
+++ b/libs/rs/rsProgramFragment.h
@@ -0,0 +1,92 @@
+/*
+ * 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 ANDROID_RS_PROGRAM_FRAGMENT_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramFragmentState;
+
+class ProgramFragment : public Program
+{
+public:
+ const static uint32_t MAX_TEXTURE = 2;
+
+
+
+ ProgramFragment(Element *in, Element *out);
+ virtual ~ProgramFragment();
+
+ virtual void setupGL(ProgramFragmentState *);
+
+
+
+ void bindTexture(uint32_t slot, Allocation *);
+ void bindSampler(uint32_t slot, Sampler *);
+ void setType(uint32_t slot, const Element *, uint32_t dim);
+
+ void setEnvMode(uint32_t slot, RsTexEnvMode);
+ void setTexEnable(uint32_t slot, bool);
+
+
+
+protected:
+ // The difference between Textures and Constants is how they are accessed
+ // Texture lookups go though a sampler which in effect converts normalized
+ // coordinates into type specific. Multiple samples may also be taken
+ // and filtered.
+ //
+ // Constants are strictly accessed by programetic loads.
+ ObjectBaseRef<Allocation> mTextures[MAX_TEXTURE];
+ ObjectBaseRef<Sampler> mSamplers[MAX_TEXTURE];
+ ObjectBaseRef<const Element> mTextureFormats[MAX_TEXTURE];
+ uint32_t mTextureDimensions[MAX_TEXTURE];
+
+
+ // Hacks to create a program for now
+ RsTexEnvMode mEnvModes[MAX_TEXTURE];
+ uint32_t mTextureEnableMask;
+};
+
+class ProgramFragmentState
+{
+public:
+ ProgramFragmentState();
+ ~ProgramFragmentState();
+
+ ProgramFragment *mPF;
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+ ObjectBaseRef<ProgramFragment> mDefault;
+ Vector<ProgramFragment *> mPrograms;
+
+ ObjectBaseRef<ProgramFragment> mLast;
+};
+
+
+}
+}
+#endif
+
+
+
+
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
new file mode 100644
index 0000000..27f4015
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramFragmentStore.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragmentStore::ProgramFragmentStore(Element *in, Element *out) :
+ Program(in, out)
+{
+ mDitherEnable = true;
+ mBlendEnable = false;
+ mColorRWriteEnable = true;
+ mColorGWriteEnable = true;
+ mColorBWriteEnable = true;
+ mColorAWriteEnable = true;
+ mBlendSrc = GL_ONE;
+ mBlendDst = GL_ZERO;
+
+
+ mDepthTestEnable = false;
+ mDepthWriteEnable = true;
+ mDepthFunc = GL_LESS;
+
+
+}
+
+ProgramFragmentStore::~ProgramFragmentStore()
+{
+}
+
+void ProgramFragmentStore::setupGL(ProgramFragmentStoreState *state)
+{
+ if (state->mLast.get() == this) {
+ return;
+ }
+ state->mLast.set(this);
+
+ glColorMask(mColorRWriteEnable,
+ mColorGWriteEnable,
+ mColorBWriteEnable,
+ mColorAWriteEnable);
+ if (mBlendEnable) {
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendSrc, mBlendDst);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ //LOGE("pfs %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc);
+
+ glDepthMask(mDepthWriteEnable);
+ if(mDepthTestEnable || mDepthWriteEnable) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(mDepthFunc);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if (mDitherEnable) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+
+}
+
+void ProgramFragmentStore::setDitherEnable(bool enable)
+{
+ mDitherEnable = enable;
+}
+
+void ProgramFragmentStore::setDepthFunc(RsDepthFunc func)
+{
+ mDepthTestEnable = true;
+
+ switch(func) {
+ case RS_DEPTH_FUNC_ALWAYS:
+ mDepthTestEnable = false;
+ mDepthFunc = GL_ALWAYS;
+ break;
+ case RS_DEPTH_FUNC_LESS:
+ mDepthFunc = GL_LESS;
+ break;
+ case RS_DEPTH_FUNC_LEQUAL:
+ mDepthFunc = GL_LEQUAL;
+ break;
+ case RS_DEPTH_FUNC_GREATER:
+ mDepthFunc = GL_GREATER;
+ break;
+ case RS_DEPTH_FUNC_GEQUAL:
+ mDepthFunc = GL_GEQUAL;
+ break;
+ case RS_DEPTH_FUNC_EQUAL:
+ mDepthFunc = GL_EQUAL;
+ break;
+ case RS_DEPTH_FUNC_NOTEQUAL:
+ mDepthFunc = GL_NOTEQUAL;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setDepthMask(bool mask)
+{
+ mDepthWriteEnable = mask;
+}
+
+void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ mBlendEnable = true;
+ if ((src == RS_BLEND_SRC_ONE) &&
+ (dst == RS_BLEND_DST_ZERO)) {
+ mBlendEnable = false;
+ }
+
+ switch(src) {
+ case RS_BLEND_SRC_ZERO:
+ mBlendSrc = GL_ZERO;
+ break;
+ case RS_BLEND_SRC_ONE:
+ mBlendSrc = GL_ONE;
+ break;
+ case RS_BLEND_SRC_DST_COLOR:
+ mBlendSrc = GL_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_COLOR:
+ mBlendSrc = GL_ONE_MINUS_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA:
+ mBlendSrc = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_DST_ALPHA:
+ mBlendSrc = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA_SATURATE:
+ mBlendSrc = GL_SRC_ALPHA_SATURATE;
+ break;
+ }
+
+ switch(dst) {
+ case RS_BLEND_DST_ZERO:
+ mBlendDst = GL_ZERO;
+ break;
+ case RS_BLEND_DST_ONE:
+ mBlendDst = GL_ONE;
+ break;
+ case RS_BLEND_DST_SRC_COLOR:
+ mBlendDst = GL_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_COLOR:
+ mBlendDst = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_SRC_ALPHA:
+ mBlendDst = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA:
+ mBlendDst = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_DST_ALPHA:
+ mBlendDst = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_DST_ALPHA:
+ mBlendDst = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a)
+{
+ mColorRWriteEnable = r;
+ mColorGWriteEnable = g;
+ mColorBWriteEnable = b;
+ mColorAWriteEnable = a;
+}
+
+
+ProgramFragmentStoreState::ProgramFragmentStoreState()
+{
+ mPFS = NULL;
+}
+
+ProgramFragmentStoreState::~ProgramFragmentStoreState()
+{
+ delete mPFS;
+
+}
+
+void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragmentStore *pfs = new ProgramFragmentStore(NULL, NULL);
+ mDefault.set(pfs);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentStoreBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragmentStore.mPFS;
+ rsc->mStateFragmentStore.mPFS = new ProgramFragmentStore((Element *)in, (Element *)out);
+
+}
+
+void rsi_ProgramFragmentStoreDepthFunc(Context *rsc, RsDepthFunc func)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthFunc(func);
+}
+
+void rsi_ProgramFragmentStoreDepthMask(Context *rsc, bool mask)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthMask(mask);
+}
+
+void rsi_ProgramFragmentStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a)
+{
+ rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a);
+}
+
+void rsi_ProgramFragmentStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst);
+}
+
+RsProgramFragmentStore rsi_ProgramFragmentStoreCreate(Context *rsc)
+{
+ ProgramFragmentStore *pfs = rsc->mStateFragmentStore.mPFS;
+ pfs->incRef();
+ rsc->mStateFragmentStore.mPFS = 0;
+ return pfs;
+}
+
+void rsi_ProgramFragmentStoreDither(Context *rsc, bool enable)
+{
+ 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
new file mode 100644
index 0000000..0de5c3a
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramFragmentStoreState;
+
+class ProgramFragmentStore : public Program
+{
+public:
+ ProgramFragmentStore(Element *in, Element *out);
+ virtual ~ProgramFragmentStore();
+
+ virtual void setupGL(ProgramFragmentStoreState *);
+
+ void setDepthFunc(RsDepthFunc);
+ void setDepthMask(bool);
+
+ void setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst);
+ void setColorMask(bool, bool, bool, bool);
+
+ void setDitherEnable(bool);
+
+protected:
+ bool mDitherEnable;
+
+ bool mBlendEnable;
+ bool mColorRWriteEnable;
+ bool mColorGWriteEnable;
+ bool mColorBWriteEnable;
+ bool mColorAWriteEnable;
+ int32_t mBlendSrc;
+ int32_t mBlendDst;
+
+ bool mDepthTestEnable;
+ bool mDepthWriteEnable;
+ int32_t mDepthFunc;
+
+ bool mStencilTestEnable;
+};
+
+class ProgramFragmentStoreState
+{
+public:
+ ProgramFragmentStoreState();
+ ~ProgramFragmentStoreState();
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramFragmentStore> mDefault;
+ ObjectBaseRef<ProgramFragmentStore> mLast;
+
+
+ ProgramFragmentStore *mPFS;
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
new file mode 100644
index 0000000..6ef5456
--- /dev/null
+++ b/libs/rs/rsProgramVertex.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramVertex::ProgramVertex(Element *in, Element *out) :
+ Program(in, out)
+{
+ mTextureMatrixEnable = false;
+ mLightCount = 0;
+}
+
+ProgramVertex::~ProgramVertex()
+{
+}
+
+static void logMatrix(const char *txt, const float *f)
+{
+ LOGV("Matrix %s, %p", txt, f);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[0], f[4], f[8], f[12]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[1], f[5], f[9], f[13]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[2], f[6], f[10], f[14]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]);
+}
+
+void ProgramVertex::setupGL(ProgramVertexState *state)
+{
+ if ((state->mLast.get() == this) && !mDirty) {
+ return;
+ }
+ state->mLast.set(this);
+
+ const float *f = static_cast<const float *>(mConstants->getPtr());
+
+ glMatrixMode(GL_TEXTURE);
+ if (mTextureMatrixEnable) {
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
+ } else {
+ glLoadIdentity();
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ if (mLightCount) {
+ int v = 0;
+ glEnable(GL_LIGHTING);
+ glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v);
+ for (uint32_t ct = 0; ct < mLightCount; ct++) {
+ const Light *l = mLights[ct].get();
+ glEnable(GL_LIGHT0 + ct);
+ l->setupGL(ct);
+ }
+ for (uint32_t ct = mLightCount; ct < MAX_LIGHTS; ct++) {
+ glDisable(GL_LIGHT0 + ct);
+ }
+ } else {
+ glDisable(GL_LIGHTING);
+ }
+
+ if (!f) {
+ LOGE("Must bind constants to vertex program");
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
+
+ mDirty = false;
+}
+
+void ProgramVertex::addLight(const Light *l)
+{
+ if (mLightCount < MAX_LIGHTS) {
+ mLights[mLightCount].set(l);
+ mLightCount++;
+ }
+}
+
+void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+
+
+ProgramVertexState::ProgramVertexState()
+{
+ mPV = NULL;
+}
+
+ProgramVertexState::~ProgramVertexState()
+{
+ delete mPV;
+}
+
+void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramVertex *pv = new ProgramVertex(NULL, NULL);
+ Allocation *alloc = (Allocation *)
+ rsi_AllocationCreatePredefSized(rsc, RS_ELEMENT_USER_FLOAT, 48);
+ mDefaultAlloc.set(alloc);
+ mDefault.set(pv);
+
+ pv->bindAllocation(alloc);
+
+ Matrix m;
+ m.loadOrtho(0,w, h,0, -1,1);
+ alloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0]);
+
+ m.loadIdentity();
+ alloc->subData(RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0]);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramVertexBegin(Context *rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateVertex.mPV;
+ rsc->mStateVertex.mPV = new ProgramVertex((Element *)in, (Element *)out);
+}
+
+RsProgramVertex rsi_ProgramVertexCreate(Context *rsc)
+{
+ ProgramVertex *pv = rsc->mStateVertex.mPV;
+ pv->incRef();
+ rsc->mStateVertex.mPV = 0;
+ return pv;
+}
+
+void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, RsAllocation constants)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpgm);
+ pv->bindAllocation(static_cast<Allocation *>(constants));
+}
+
+void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable)
+{
+ rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
+}
+
+void rsi_ProgramVertexAddLight(Context *rsc, RsLight light)
+{
+ rsc->mStateVertex.mPV->addLight(static_cast<const Light *>(light));
+}
+
+
+}
+}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
new file mode 100644
index 0000000..c9ce7aa
--- /dev/null
+++ b/libs/rs/rsProgramVertex.h
@@ -0,0 +1,81 @@
+/*
+ * 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 ANDROID_RS_PROGRAM_VERTEX_H
+#define ANDROID_RS_PROGRAM_VERTEX_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramVertexState;
+
+class ProgramVertex : public Program
+{
+public:
+ const static uint32_t MAX_LIGHTS = 8;
+
+ ProgramVertex(Element *in, Element *out);
+ virtual ~ProgramVertex();
+
+ virtual void setupGL(ProgramVertexState *state);
+
+
+ void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
+ void addLight(const Light *);
+
+ void setProjectionMatrix(const rsc_Matrix *) const;
+ void setModelviewMatrix(const rsc_Matrix *) const;
+ void setTextureMatrix(const rsc_Matrix *) const;
+
+protected:
+ uint32_t mLightCount;
+ ObjectBaseRef<const Light> mLights[MAX_LIGHTS];
+
+ // Hacks to create a program for now
+ bool mTextureMatrixEnable;
+};
+
+
+class ProgramVertexState
+{
+public:
+ ProgramVertexState();
+ ~ProgramVertexState();
+
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramVertex> mDefault;
+ ObjectBaseRef<ProgramVertex> mLast;
+ ObjectBaseRef<Allocation> mDefaultAlloc;
+
+
+
+ ProgramVertex *mPV;
+
+ //ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+
+
+};
+
+
+}
+}
+#endif
+
+
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
new file mode 100644
index 0000000..418f127
--- /dev/null
+++ b/libs/rs/rsSampler.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "rsContext.h"
+#include "rsSampler.h"
+
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Sampler::Sampler()
+{
+ // Should not get called.
+ rsAssert(0);
+}
+
+Sampler::Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR)
+{
+ mMagFilter = magFilter;
+ mMinFilter = minFilter;
+ mWrapS = wrapS;
+ mWrapT = wrapT;
+ mWrapR = wrapR;
+}
+
+Sampler::~Sampler()
+{
+}
+
+void Sampler::setupGL()
+{
+ GLenum trans[] = {
+ GL_NEAREST, //RS_SAMPLER_NEAREST,
+ GL_LINEAR, //RS_SAMPLER_LINEAR,
+ GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
+ GL_REPEAT, //RS_SAMPLER_WRAP,
+ GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
+
+ };
+
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]);
+
+}
+
+void Sampler::bindToContext(SamplerState *ss, uint32_t slot)
+{
+ ss->mSamplers[slot].set(this);
+ mBoundSlot = slot;
+}
+
+void Sampler::unbindFromContext(SamplerState *ss)
+{
+ int32_t slot = mBoundSlot;
+ mBoundSlot = -1;
+ ss->mSamplers[slot].clear();
+}
+
+void SamplerState::setupGL()
+{
+ for (uint32_t ct=0; ct < RS_MAX_SAMPLER_SLOT; ct++) {
+ Sampler *s = mSamplers[ct].get();
+ if (s) {
+ s->setupGL();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+}
+
+////////////////////////////////
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_SamplerBegin(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ ss->mMagFilter = RS_SAMPLER_LINEAR;
+ ss->mMinFilter = RS_SAMPLER_LINEAR;
+ ss->mWrapS = RS_SAMPLER_WRAP;
+ ss->mWrapT = RS_SAMPLER_WRAP;
+ ss->mWrapR = RS_SAMPLER_WRAP;
+}
+
+void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ switch(param) {
+ case RS_SAMPLER_MAG_FILTER:
+ ss->mMagFilter = value;
+ break;
+ case RS_SAMPLER_MIN_FILTER:
+ ss->mMinFilter = value;
+ break;
+ case RS_SAMPLER_WRAP_S:
+ ss->mWrapS = value;
+ break;
+ case RS_SAMPLER_WRAP_T:
+ ss->mWrapT = value;
+ break;
+ case RS_SAMPLER_WRAP_R:
+ ss->mWrapR = value;
+ break;
+ }
+
+}
+
+RsSampler rsi_SamplerCreate(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+
+ Sampler * s = new Sampler(ss->mMagFilter,
+ ss->mMinFilter,
+ ss->mWrapS,
+ ss->mWrapT,
+ ss->mWrapR);
+ return s;
+}
+
+void rsi_SamplerDestroy(Context *rsc, RsSampler vs)
+{
+ Sampler * s = static_cast<Sampler *>(vs);
+ s->decRef();
+
+}
+
+
+}}
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
new file mode 100644
index 0000000..4b504f6
--- /dev/null
+++ b/libs/rs/rsSampler.h
@@ -0,0 +1,87 @@
+/*
+ * 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 ANDROID_RS_SAMPLER_H
+#define ANDROID_RS_SAMPLER_H
+
+#include "rsAllocation.h"
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+const static uint32_t RS_MAX_SAMPLER_SLOT = 16;
+
+class SamplerState;
+
+class Sampler : public ObjectBase
+{
+public:
+ Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR);
+
+ virtual ~Sampler();
+
+ void bind(Allocation *);
+ void setupGL();
+
+ void bindToContext(SamplerState *, uint32_t slot);
+ void unbindFromContext(SamplerState *);
+
+protected:
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+ int32_t mBoundSlot;
+
+private:
+ Sampler();
+
+};
+
+
+class SamplerState
+{
+public:
+
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+
+ ObjectBaseRef<Sampler> mSamplers[RS_MAX_SAMPLER_SLOT];
+
+ void setupGL();
+
+};
+
+
+
+}
+}
+#endif //ANDROID_RS_SAMPLER_H
+
+
+
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
new file mode 100644
index 0000000..6bcb8f2
--- /dev/null
+++ b/libs/rs/rsScript.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Script::Script()
+{
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+}
+
+Script::~Script()
+{
+}
+
+namespace android {
+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);
+ s->mSlots[slot].set(static_cast<Allocation *>(va));
+}
+
+void rsi_ScriptSetClearColor(Context * rsc, RsScript vs, float r, float g, float b, float a)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearColor[0] = r;
+ s->mEnviroment.mClearColor[1] = g;
+ s->mEnviroment.mClearColor[2] = b;
+ s->mEnviroment.mClearColor[3] = a;
+}
+
+void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mTimeZone = timeZone;
+}
+
+void rsi_ScriptSetClearDepth(Context * rsc, RsScript vs, float v)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearDepth = v;
+}
+
+void rsi_ScriptSetClearStencil(Context * rsc, RsScript vs, uint32_t v)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearStencil = v;
+}
+
+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 {
+ ss->mSlotNames[slot].setTo("");
+ }
+}
+
+void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mIsRoot = isRoot;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
new file mode 100644
index 0000000..60f83a6
--- /dev/null
+++ b/libs/rs/rsScript.h
@@ -0,0 +1,74 @@
+/*
+ * 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 ANDROID_RS_SCRIPT_H
+#define ANDROID_RS_SCRIPT_H
+
+#include "rsAllocation.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramVertex;
+class ProgramFragment;
+class ProgramRaster;
+class ProgramFragmentStore;
+
+#define MAX_SCRIPT_BANKS 16
+
+class Script : public ObjectBase
+{
+public:
+
+ Script();
+ virtual ~Script();
+
+
+ struct Enviroment_t {
+ bool mIsRoot;
+ float mClearColor[4];
+ float mClearDepth;
+ uint32_t mClearStencil;
+
+ uint32_t mStartTimeMillis;
+ const char* mTimeZone;
+
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ //ObjectBaseRef<ProgramRaster> mRaster;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+ };
+ Enviroment_t mEnviroment;
+
+ uint32_t mCounstantBufferCount;
+
+ 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;
+};
+
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
new file mode 100644
index 0000000..db4fd09
--- /dev/null
+++ b/libs/rs/rsScriptC.cpp
@@ -0,0 +1,367 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+
+#include "acc/acc.h"
+#include "utils/Timers.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+ScriptC::ScriptC()
+{
+ mAccScript = NULL;
+ memset(&mProgram, 0, sizeof(mProgram));
+}
+
+ScriptC::~ScriptC()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+
+bool ScriptC::run(Context *rsc, uint32_t launchIndex)
+{
+ Context::ScriptTLSStruct * tls =
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
+
+ if (mEnviroment.mFragmentStore.get()) {
+ rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
+ }
+ if (mEnviroment.mFragment.get()) {
+ rsc->setFragment(mEnviroment.mFragment.get());
+ }
+ if (mEnviroment.mVertex.get()) {
+ rsc->setVertex(mEnviroment.mVertex.get());
+ }
+
+ if (launchIndex == 0) {
+ mEnviroment.mStartTimeMillis
+ = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ }
+
+ bool ret = false;
+ tls->mScript = this;
+ ret = mProgram.mScript(launchIndex) != 0;
+ tls->mScript = NULL;
+ return ret;
+}
+
+ScriptCState::ScriptCState()
+{
+ clear();
+}
+
+ScriptCState::~ScriptCState()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+void ScriptCState::clear()
+{
+ memset(&mProgram, 0, sizeof(mProgram));
+
+ for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ mConstantBufferTypes[ct].clear();
+ mSlotNames[ct].setTo("");
+ mSlotWritable[ct] = false;
+ }
+
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+ mEnviroment.mClearStencil = 0;
+ mEnviroment.mIsRoot = false;
+
+ mAccScript = NULL;
+
+ mInt32Defines.clear();
+ mFloatDefines.clear();
+}
+
+static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name)
+{
+ const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name);
+ if (sym) {
+ return sym->mPtr;
+ }
+ LOGE("ScriptC sym lookup failed for %s", name);
+ return NULL;
+}
+
+void ScriptCState::runCompiler(Context *rsc)
+{
+ mAccScript = accCreateScript();
+ String8 tmp;
+
+ rsc->appendNameDefines(&tmp);
+ appendDecls(&tmp);
+ rsc->appendVarDefines(&tmp);
+ appendVarDefines(&tmp);
+ appendTypes(&tmp);
+ tmp.append("#line 1\n");
+
+ const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
+ int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
+ accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+ accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
+ accCompileScript(mAccScript);
+ accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
+ rsAssert(mProgram.mScript);
+
+ if (!mProgram.mScript) {
+ ACCchar buf[4096];
+ ACCsizei len;
+ accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+ LOGE(buf);
+ }
+
+ mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+ mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+ mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+ if (mProgram.mScript) {
+ const static int pragmaMax = 16;
+ ACCsizei pragmaCount;
+ ACCchar * str[pragmaMax];
+ accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+
+ for (int ct=0; ct < pragmaCount; ct+=2) {
+ if (!strcmp(str[ct], "version")) {
+ continue;
+ }
+
+ if (!strcmp(str[ct], "stateVertex")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mVertex.clear();
+ continue;
+ }
+ ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
+ if (pv != NULL) {
+ mEnviroment.mVertex.set(pv);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateRaster")) {
+ LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragment")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragment.clear();
+ continue;
+ }
+ ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
+ if (pf != NULL) {
+ mEnviroment.mFragment.set(pf);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragmentStore")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragmentStore.clear();
+ continue;
+ }
+ ProgramFragmentStore * pfs =
+ (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
+ if (pfs != NULL) {
+ mEnviroment.mFragmentStore.set(pfs);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
+ }
+
+ }
+
+
+ } else {
+ // Deal with an error.
+ }
+}
+
+
+void ScriptCState::appendVarDefines(String8 *str)
+{
+ char buf[256];
+ LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n",
+ mInt32Defines.size(), mFloatDefines.size());
+ for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+ str->append("#define ");
+ str->append(mInt32Defines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+ str->append(buf);
+ }
+ for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+ str->append("#define ");
+ str->append(mFloatDefines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+ str->append(buf);
+ }
+}
+
+void ScriptCState::appendTypes(String8 *str)
+{
+ char buf[256];
+ String8 tmp;
+
+ for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ const Type *t = mConstantBufferTypes[ct].get();
+ if (!t) {
+ continue;
+ }
+ const Element *e = t->getElement();
+
+ if (t->getName()) {
+ for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
+ const Component *c = e->getComponent(ct2);
+ tmp.setTo("#define OFFSETOF_");
+ tmp.append(t->getName());
+ tmp.append("_");
+ tmp.append(c->getComponentName());
+ sprintf(buf, " %i\n", ct2);
+ tmp.append(buf);
+ LOGD(tmp);
+ str->append(tmp);
+ }
+ }
+
+ if (mSlotNames[ct].length() > 0) {
+ for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
+ const Component *c = e->getComponent(ct2);
+ tmp.setTo("#define ");
+ tmp.append(mSlotNames[ct]);
+ tmp.append("_");
+ tmp.append(c->getComponentName());
+ switch (c->getType()) {
+ case Component::FLOAT:
+ tmp.append(" loadF(");
+ break;
+ case Component::SIGNED:
+ sprintf(buf, " loadI%i(", c->getBits());
+ tmp.append(buf);
+ break;
+ case Component::UNSIGNED:
+ sprintf(buf, " loadU%i(", c->getBits());
+ tmp.append(buf);
+ break;
+ }
+ sprintf(buf, "%i, %i)\n", ct, ct2);
+ tmp.append(buf);
+
+ LOGD(tmp);
+ str->append(tmp);
+ }
+ }
+ }
+
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ScriptCBegin(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->clear();
+}
+
+void rsi_ScriptCSetScript(Context * rsc, void *vp)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+}
+
+void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScriptText = text;
+ ss->mProgram.mScriptTextLength = len;
+}
+
+
+RsScript rsi_ScriptCCreate(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+
+ ss->runCompiler(rsc);
+
+ ScriptC *s = new ScriptC();
+ s->incRef();
+ s->mAccScript = ss->mAccScript;
+ ss->mAccScript = NULL;
+ s->mEnviroment = ss->mEnviroment;
+ s->mProgram = ss->mProgram;
+ 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();
+ return s;
+}
+
+void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mFloatDefines.add(String8(name), value);
+}
+
+void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mInt32Defines.add(String8(name), value);
+}
+
+}
+}
+
+
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
new file mode 100644
index 0000000..302515e
--- /dev/null
+++ b/libs/rs/rsScriptC.h
@@ -0,0 +1,100 @@
+/*
+ * 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 ANDROID_RS_SCRIPT_C_H
+#define ANDROID_RS_SCRIPT_C_H
+
+#include "rsScript.h"
+
+#include "RenderScriptEnv.h"
+
+#include <utils/KeyedVector.h>
+
+struct ACCscript;
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class ScriptC : public Script
+{
+public:
+ typedef int (*RunScript_t)(uint32_t launchIndex);
+
+ ScriptC();
+ virtual ~ScriptC();
+
+ struct Program_t {
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
+
+
+ int mVersionMajor;
+ int mVersionMinor;
+
+ RunScript_t mScript;
+ };
+
+ Program_t mProgram;
+
+ ACCscript* mAccScript;
+
+ virtual bool run(Context *, uint32_t launchID);
+};
+
+class ScriptCState
+{
+public:
+ ScriptCState();
+ ~ScriptCState();
+
+ ACCscript* mAccScript;
+
+ ScriptC::Program_t mProgram;
+ Script::Enviroment_t mEnviroment;
+
+ ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
+ String8 mSlotNames[MAX_SCRIPT_BANKS];
+ bool mSlotWritable[MAX_SCRIPT_BANKS];
+
+ void clear();
+ void runCompiler(Context *rsc);
+ void appendVarDefines(String8 *str);
+ void appendTypes(String8 *str);
+
+ struct SymbolTable_t {
+ const char * mName;
+ void * mPtr;
+ const char * mRet;
+ const char * mParam;
+ };
+ static SymbolTable_t gSyms[];
+ static const SymbolTable_t * lookupSymbol(const char *);
+ static void appendDecls(String8 *str);
+
+ KeyedVector<String8,int> mInt32Defines;
+ KeyedVector<String8,float> mFloatDefines;
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
new file mode 100644
index 0000000..0ecdf9a
--- /dev/null
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -0,0 +1,1080 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+#include "rsNoise.h"
+
+#include "acc/acc.h"
+#include "utils/Timers.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <time.h>
+#include <cutils/tztime.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+//////////////////////////////////////////////////////////////////////////////
+// IO routines
+//////////////////////////////////////////////////////////////////////////////
+
+static float SC_loadF(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ //LOGE("loadF %i %i = %f %x", bank, offset, f, ((int *)&f)[0]);
+ return f[offset];
+}
+
+static int32_t SC_loadI32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const int32_t *i = static_cast<const int32_t *>(vp);
+ //LOGE("loadI32 %i %i = %i", bank, offset, t);
+ return i[offset];
+}
+
+static float* SC_loadArrayF(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ return f + offset;
+}
+
+static int32_t* SC_loadArrayI32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ int32_t *i = static_cast<int32_t *>(vp);
+ return i + offset;
+}
+
+static float* SC_loadTriangleMeshVerticesF(RsTriangleMesh mesh)
+{
+ TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+ void *vp = tm->mVertexData;
+ float *f = static_cast<float *>(vp);
+ return f;
+}
+
+static void SC_updateTriangleMesh(RsTriangleMesh mesh)
+{
+ TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const uint32_t *i = static_cast<const uint32_t *>(vp);
+ return i[offset];
+}
+
+static void SC_loadVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(v, &f[offset], sizeof(rsc_Vector4));
+}
+
+static void SC_loadMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(m, &f[offset], sizeof(rsc_Matrix));
+}
+
+
+static void SC_storeF(uint32_t bank, uint32_t offset, float v)
+{
+ //LOGE("storeF %i %i %f", bank, offset, v);
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ f[offset] = v;
+}
+
+static void SC_storeI32(uint32_t bank, uint32_t offset, int32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ int32_t *f = static_cast<int32_t *>(vp);
+ static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeU32(uint32_t bank, uint32_t offset, uint32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ uint32_t *f = static_cast<uint32_t *>(vp);
+ static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], v, sizeof(rsc_Vector4));
+}
+
+static void SC_storeMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], m, sizeof(rsc_Matrix));
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Math routines
+//////////////////////////////////////////////////////////////////////////////
+
+#define PI 3.1415926f
+#define DEG_TO_RAD PI / 180.0f
+#define RAD_TO_DEG 180.0f / PI
+
+static float SC_randf(float max)
+{
+ float r = (float)rand();
+ return r / RAND_MAX * max;
+}
+
+static float SC_randf2(float min, float max)
+{
+ float r = (float)rand();
+ return r / RAND_MAX * (max - min) + min;
+}
+
+static float SC_clampf(float amount, float low, float high)
+{
+ return amount < low ? low : (amount > high ? high : amount);
+}
+
+static int SC_clamp(int amount, int low, int high)
+{
+ return amount < low ? low : (amount > high ? high : amount);
+}
+
+static float SC_maxf(float a, float b)
+{
+ return a > b ? a : b;
+}
+
+static float SC_minf(float a, float b)
+{
+ return a < b ? a : b;
+}
+
+static float SC_sqrf(float v)
+{
+ return v * v;
+}
+
+static int SC_sqr(int v)
+{
+ return v * v;
+}
+
+static float SC_distf2(float x1, float y1, float x2, float y2)
+{
+ float x = x2 - x1;
+ float y = y2 - y1;
+ return sqrtf(x * x + y * y);
+}
+
+static float SC_distf3(float x1, float y1, float z1, float x2, float y2, float z2)
+{
+ float x = x2 - x1;
+ float y = y2 - y1;
+ float z = z2 - z1;
+ return sqrtf(x * x + y * y + z * z);
+}
+
+static float SC_magf2(float a, float b)
+{
+ return sqrtf(a * a + b * b);
+}
+
+static float SC_magf3(float a, float b, float c)
+{
+ return sqrtf(a * a + b * b + c * c);
+}
+
+static float SC_radf(float degrees)
+{
+ return degrees * DEG_TO_RAD;
+}
+
+static float SC_degf(float radians)
+{
+ return radians * RAD_TO_DEG;
+}
+
+static float SC_lerpf(float start, float stop, float amount)
+{
+ return start + (stop - start) * amount;
+}
+
+static float SC_normf(float start, float stop, float value)
+{
+ return (value - start) / (stop - start);
+}
+
+static float SC_mapf(float minStart, float minStop, float maxStart, float maxStop, float value)
+{
+ return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Time routines
+//////////////////////////////////////////////////////////////////////////////
+
+static int32_t SC_second()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_sec;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_sec;
+ }
+}
+
+static int32_t SC_minute()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_min;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_min;
+ }
+}
+
+static int32_t SC_hour()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_hour;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_hour;
+ }
+}
+
+static int32_t SC_day()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_mday;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_mday;
+ }
+}
+
+static int32_t SC_month()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_mon;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_mon;
+ }
+}
+
+static int32_t SC_year()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_year;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_year;
+ }
+}
+
+static int32_t SC_uptimeMillis()
+{
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+}
+
+static int32_t SC_startTimeMillis()
+{
+ GET_TLS();
+ return sc->mEnviroment.mStartTimeMillis;
+}
+
+static int32_t SC_elapsedTimeMillis()
+{
+ GET_TLS();
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC))
+ - sc->mEnviroment.mStartTimeMillis;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Matrix routines
+//////////////////////////////////////////////////////////////////////////////
+
+
+static void SC_matrixLoadIdentity(rsc_Matrix *mat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadIdentity();
+}
+
+static void SC_matrixLoadFloat(rsc_Matrix *mat, const float *f)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(f);
+}
+
+static void SC_matrixLoadMat(rsc_Matrix *mat, const rsc_Matrix *newmat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(reinterpret_cast<const Matrix *>(newmat));
+}
+
+static void SC_matrixLoadRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadRotate(rot, x, y, z);
+}
+
+static void SC_matrixLoadScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadScale(x, y, z);
+}
+
+static void SC_matrixLoadTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadTranslate(x, y, z);
+}
+
+static void SC_matrixLoadMultiply(rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadMultiply(reinterpret_cast<const Matrix *>(lhs),
+ reinterpret_cast<const Matrix *>(rhs));
+}
+
+static void SC_matrixMultiply(rsc_Matrix *mat, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->multiply(reinterpret_cast<const Matrix *>(rhs));
+}
+
+static void SC_matrixRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->rotate(rot, x, y, z);
+}
+
+static void SC_matrixScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->scale(x, y, z);
+}
+
+static void SC_matrixTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->translate(x, y, z);
+}
+
+
+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);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Context
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindTexture(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Allocation *>(va));
+
+}
+
+static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindSampler(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Sampler *>(vs));
+
+}
+
+static void SC_bindProgramFragmentStore(RsProgramFragmentStore pfs)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragmentStore(rsc, pfs);
+
+}
+
+static void SC_bindProgramFragment(RsProgramFragment pf)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragment(rsc, pf);
+
+}
+
+static void SC_bindProgramVertex(RsProgramVertex pv)
+{
+ GET_TLS();
+ rsi_ContextBindProgramVertex(rsc, pv);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_drawTriangleMesh(RsTriangleMesh mesh)
+{
+ GET_TLS();
+ rsi_TriangleMeshRender(rsc, mesh);
+}
+
+static void SC_drawTriangleMeshRange(RsTriangleMesh mesh, uint32_t start, uint32_t count)
+{
+ GET_TLS();
+ rsi_TriangleMeshRenderRange(rsc, mesh, start, count);
+}
+
+static void SC_drawLine(float x1, float y1, float z1,
+ float x2, float y2, float z2)
+{
+ GET_TLS();
+ rsc->setupCheck();
+
+ float vtx[] = { x1, y1, z1, x2, y2, z2 };
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDrawArrays(GL_LINES, 0, 2);
+}
+
+static void SC_drawQuadTexCoords(float x1, float y1, float z1,
+ float u1, float v1,
+ float x2, float y2, float z2,
+ float u2, float v2,
+ float x3, float y3, float z3,
+ float u3, float v3,
+ float x4, float y4, float z4,
+ float u4, float v4)
+{
+ GET_TLS();
+
+ //LOGE("Quad");
+ //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
+ //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
+ //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
+ //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
+
+ float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
+ const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
+
+ rsc->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE1);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE0);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
+static void SC_drawQuad(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+{
+ SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
+ x2, y2, z2, 1, 1,
+ x3, y3, z3, 1, 0,
+ x4, y4, z4, 0, 0);
+}
+
+static void SC_drawRect(float x1, float y1,
+ float x2, float y2, float z)
+{
+ SC_drawQuad(x1, y2, z,
+ x2, y2, z,
+ x2, y1, z,
+ x1, y1, z);
+}
+
+static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ rsc->setupCheck();
+ sm->render();
+}
+
+static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ rsc->setupCheck();
+ sm->renderRange(start, len);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_color(float r, float g, float b, float a)
+{
+ glColor4f(r, g, b, a);
+}
+
+static void SC_ambient(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, params);
+}
+
+static void SC_diffuse(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
+}
+
+static void SC_specular(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, params);
+}
+
+static void SC_emission(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
+}
+
+static void SC_shininess(float s)
+{
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
+}
+
+static void SC_hsb(float h, float s, float b, float a)
+{
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ float x = h;
+ float y = s;
+ float z = b;
+
+ float hf = (x - (int) x) * 6.0f;
+ int ihf = (int) hf;
+ float f = hf - ihf;
+ float pv = z * (1.0f - y);
+ float qv = z * (1.0f - y * f);
+ float tv = z * (1.0f - y * (1.0f - f));
+
+ switch (ihf) {
+ case 0: // Red is the dominant color
+ red = z;
+ green = tv;
+ blue = pv;
+ break;
+ case 1: // Green is the dominant color
+ red = qv;
+ green = z;
+ blue = pv;
+ break;
+ case 2:
+ red = pv;
+ green = z;
+ blue = tv;
+ break;
+ case 3: // Blue is the dominant color
+ red = pv;
+ green = qv;
+ blue = z;
+ break;
+ case 4:
+ red = tv;
+ green = pv;
+ blue = z;
+ break;
+ case 5: // Red is the dominant color
+ red = z;
+ green = pv;
+ blue = qv;
+ break;
+ }
+
+ glColor4f(red, green, blue, a);
+}
+
+static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+{
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
+}
+
+static void SC_uploadToBufferObject(RsAllocation va)
+{
+ GET_TLS();
+ rsi_AllocationUploadToBufferObject(rsc, va);
+}
+
+static void SC_ClearColor(float r, float g, float b, float a)
+{
+ //LOGE("c %f %f %f %f", r, g, b, a);
+ GET_TLS();
+ sc->mEnviroment.mClearColor[0] = r;
+ sc->mEnviroment.mClearColor[1] = g;
+ sc->mEnviroment.mClearColor[2] = b;
+ sc->mEnviroment.mClearColor[3] = a;
+}
+
+static void SC_debugF(const char *s, float f)
+{
+ LOGE("%s %f", s, f);
+}
+
+static void SC_debugI32(const char *s, int32_t i)
+{
+ LOGE("%s %i", s, i);
+}
+
+static uint32_t SC_getWidth()
+{
+ GET_TLS();
+ return rsc->getWidth();
+}
+
+static uint32_t SC_getHeight()
+{
+ GET_TLS();
+ 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
+//////////////////////////////////////////////////////////////////////////////
+
+ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
+ // IO
+ { "loadI32", (void *)&SC_loadI32,
+ "int", "(int, int)" },
+ //{ "loadU32", (void *)&SC_loadU32, "unsigned int", "(int, int)" },
+ { "loadF", (void *)&SC_loadF,
+ "float", "(int, int)" },
+ { "loadArrayF", (void *)&SC_loadArrayF,
+ "float*", "(int, int)" },
+ { "loadArrayI32", (void *)&SC_loadArrayI32,
+ "int*", "(int, int)" },
+ { "loadVec4", (void *)&SC_loadVec4,
+ "void", "(int, int, float *)" },
+ { "loadMatrix", (void *)&SC_loadMatrix,
+ "void", "(int, int, float *)" },
+ { "storeI32", (void *)&SC_storeI32,
+ "void", "(int, int, int)" },
+ //{ "storeU32", (void *)&SC_storeU32, "void", "(int, int, unsigned int)" },
+ { "storeF", (void *)&SC_storeF,
+ "void", "(int, int, float)" },
+ { "storeVec4", (void *)&SC_storeVec4,
+ "void", "(int, int, float *)" },
+ { "storeMatrix", (void *)&SC_storeMatrix,
+ "void", "(int, int, float *)" },
+ { "loadTriangleMeshVerticesF", (void *)&SC_loadTriangleMeshVerticesF,
+ "float*", "(int)" },
+ { "updateTriangleMesh", (void *)&SC_updateTriangleMesh,
+ "void", "(int)" },
+
+ // math
+ { "modf", (void *)&fmod,
+ "float", "(float, float)" },
+ { "abs", (void *)&abs,
+ "int", "(int)" },
+ { "absf", (void *)&fabs,
+ "float", "(float)" },
+ { "sinf", (void *)&sinf,
+ "float", "(float)" },
+ { "cosf", (void *)&cosf,
+ "float", "(float)" },
+ { "asinf", (void *)&asinf,
+ "float", "(float)" },
+ { "acosf", (void *)&acosf,
+ "float", "(float)" },
+ { "atanf", (void *)&atanf,
+ "float", "(float)" },
+ { "atan2f", (void *)&atan2f,
+ "float", "(float, float)" },
+ { "fabsf", (void *)&fabsf,
+ "float", "(float)" },
+ { "randf", (void *)&SC_randf,
+ "float", "(float)" },
+ { "randf2", (void *)&SC_randf2,
+ "float", "(float, float)" },
+ { "floorf", (void *)&floorf,
+ "float", "(float)" },
+ { "ceilf", (void *)&ceilf,
+ "float", "(float)" },
+ { "expf", (void *)&expf,
+ "float", "(float)" },
+ { "logf", (void *)&logf,
+ "float", "(float)" },
+ { "powf", (void *)&powf,
+ "float", "(float, float)" },
+ { "maxf", (void *)&SC_maxf,
+ "float", "(float, float)" },
+ { "minf", (void *)&SC_minf,
+ "float", "(float, float)" },
+ { "sqrt", (void *)&sqrt,
+ "int", "(int)" },
+ { "sqrtf", (void *)&sqrtf,
+ "float", "(float)" },
+ { "sqr", (void *)&SC_sqr,
+ "int", "(int)" },
+ { "sqrf", (void *)&SC_sqrf,
+ "float", "(float)" },
+ { "clamp", (void *)&SC_clamp,
+ "int", "(int, int, int)" },
+ { "clampf", (void *)&SC_clampf,
+ "float", "(float, float, float)" },
+ { "distf2", (void *)&SC_distf2,
+ "float", "(float, float, float, float)" },
+ { "distf3", (void *)&SC_distf3,
+ "float", "(float, float, float, float, float, float)" },
+ { "magf2", (void *)&SC_magf2,
+ "float", "(float, float)" },
+ { "magf3", (void *)&SC_magf3,
+ "float", "(float, float, float)" },
+ { "radf", (void *)&SC_radf,
+ "float", "(float)" },
+ { "degf", (void *)&SC_degf,
+ "float", "(float)" },
+ { "lerpf", (void *)&SC_lerpf,
+ "float", "(float, float, float)" },
+ { "normf", (void *)&SC_normf,
+ "float", "(float, float, float)" },
+ { "mapf", (void *)&SC_mapf,
+ "float", "(float, float, float, float, float)" },
+ { "noisef", (void *)&SC_noisef,
+ "float", "(float)" },
+ { "noisef2", (void *)&SC_noisef2,
+ "float", "(float, float)" },
+ { "noisef3", (void *)&SC_noisef3,
+ "float", "(float, float, float)" },
+ { "turbulencef2", (void *)&SC_turbulencef2,
+ "float", "(float, float, float)" },
+ { "turbulencef3", (void *)&SC_turbulencef3,
+ "float", "(float, float, float, float)" },
+
+ // time
+ { "second", (void *)&SC_second,
+ "int", "()" },
+ { "minute", (void *)&SC_minute,
+ "int", "()" },
+ { "hour", (void *)&SC_hour,
+ "int", "()" },
+ { "day", (void *)&SC_day,
+ "int", "()" },
+ { "month", (void *)&SC_month,
+ "int", "()" },
+ { "year", (void *)&SC_year,
+ "int", "()" },
+ { "uptimeMillis", (void*)&SC_uptimeMillis,
+ "int", "()" }, // TODO: use long instead
+ { "startTimeMillis", (void*)&SC_startTimeMillis,
+ "int", "()" }, // TODO: use long instead
+ { "elapsedTimeMillis", (void*)&SC_elapsedTimeMillis,
+ "int", "()" }, // TODO: use long instead
+
+ // matrix
+ { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
+ "void", "(float *mat)" },
+ { "matrixLoadFloat", (void *)&SC_matrixLoadFloat,
+ "void", "(float *mat, float *f)" },
+ { "matrixLoadMat", (void *)&SC_matrixLoadMat,
+ "void", "(float *mat, float *newmat)" },
+ { "matrixLoadRotate", (void *)&SC_matrixLoadRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixLoadScale", (void *)&SC_matrixLoadScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadTranslate", (void *)&SC_matrixLoadTranslate,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadMultiply", (void *)&SC_matrixLoadMultiply,
+ "void", "(float *mat, float *lhs, float *rhs)" },
+ { "matrixMultiply", (void *)&SC_matrixMultiply,
+ "void", "(float *mat, float *rhs)" },
+ { "matrixRotate", (void *)&SC_matrixRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixScale", (void *)&SC_matrixScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "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)" },
+ { "bindProgramFragmentStore", (void *)&SC_bindProgramFragmentStore,
+ "void", "(int)" },
+ { "bindProgramVertex", (void *)&SC_bindProgramVertex,
+ "void", "(int)" },
+ { "bindSampler", (void *)&SC_bindSampler,
+ "void", "(int, int, int)" },
+ { "bindTexture", (void *)&SC_bindTexture,
+ "void", "(int, int, int)" },
+
+ // vp
+ { "vpLoadModelMatrix", (void *)&SC_vpLoadModelMatrix,
+ "void", "(void *)" },
+ { "vpLoadTextureMatrix", (void *)&SC_vpLoadTextureMatrix,
+ "void", "(void *)" },
+
+
+
+ // drawing
+ { "drawRect", (void *)&SC_drawRect,
+ "void", "(float x1, float y1, float x2, float y2, float z)" },
+ { "drawQuad", (void *)&SC_drawQuad,
+ "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
+ { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords,
+ "void", "(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4)" },
+ { "drawTriangleMesh", (void *)&SC_drawTriangleMesh,
+ "void", "(int mesh)" },
+ { "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
+ "void", "(int mesh, int start, int count)" },
+ { "drawLine", (void *)&SC_drawLine,
+ "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
+ { "drawSimpleMesh", (void *)&SC_drawSimpleMesh,
+ "void", "(int ism)" },
+ { "drawSimpleMeshRange", (void *)&SC_drawSimpleMeshRange,
+ "void", "(int ism, int start, int len)" },
+
+
+ // misc
+ { "pfClearColor", (void *)&SC_ClearColor,
+ "void", "(float, float, float, float)" },
+ { "color", (void *)&SC_color,
+ "void", "(float, float, float, float)" },
+ { "hsb", (void *)&SC_hsb,
+ "void", "(float, float, float, float)" },
+ { "ambient", (void *)&SC_ambient,
+ "void", "(float, float, float, float)" },
+ { "diffuse", (void *)&SC_diffuse,
+ "void", "(float, float, float, float)" },
+ { "specular", (void *)&SC_specular,
+ "void", "(float, float, float, float)" },
+ { "emission", (void *)&SC_emission,
+ "void", "(float, float, float, float)" },
+ { "shininess", (void *)&SC_shininess,
+ "void", "(float)" },
+
+ { "uploadToTexture", (void *)&SC_uploadToTexture,
+ "void", "(int, int)" },
+ { "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,
+ "int", "()" },
+
+
+
+ { "debugF", (void *)&SC_debugF,
+ "void", "(void *, float)" },
+ { "debugI32", (void *)&SC_debugI32,
+ "void", "(void *, int)" },
+
+
+ { NULL, NULL, NULL, NULL }
+};
+
+const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+
+ while (syms->mPtr) {
+ if (!strcmp(syms->mName, sym)) {
+ return syms;
+ }
+ syms++;
+ }
+ return NULL;
+}
+
+void ScriptCState::appendDecls(String8 *str)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+ while (syms->mPtr) {
+ str->append(syms->mRet);
+ str->append(" ");
+ str->append(syms->mName);
+ str->append(syms->mParam);
+ str->append(";\n");
+ syms++;
+ }
+}
+
+
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
new file mode 100644
index 0000000..08e36ac
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+SimpleMesh::SimpleMesh()
+{
+}
+
+SimpleMesh::~SimpleMesh()
+{
+}
+
+void SimpleMesh::render() const
+{
+ if (mPrimitiveType.get()) {
+ renderRange(0, mPrimitiveType->getDimX());
+ return;
+ }
+
+ if (mIndexType.get()) {
+ renderRange(0, mIndexType->getDimX());
+ return;
+ }
+
+ renderRange(0, mVertexTypes[0]->getDimX());
+}
+
+void SimpleMesh::renderRange(uint32_t start, uint32_t len) const
+{
+ if (len < 1) {
+ return;
+ }
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+ glClientActiveTexture(GL_TEXTURE0 + ct);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ glClientActiveTexture(GL_TEXTURE0);
+
+ for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+ glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[ct]->getBufferObjectID());
+ mVertexTypes[ct]->enableGLVertexBuffer();
+ }
+
+ if (mIndexType.get()) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
+ glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (GLvoid *)(start * 2));
+ } else {
+ glDrawArrays(mGLPrimitive, start, len);
+ }
+}
+
+
+
+SimpleMeshContext::SimpleMeshContext()
+{
+}
+
+SimpleMeshContext::~SimpleMeshContext()
+{
+}
+
+
+namespace android {
+namespace renderscript {
+
+
+RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
+{
+ SimpleMesh *sm = new SimpleMesh();
+ sm->incRef();
+
+ sm->mIndexType.set((const Type *)idx);
+ sm->mPrimitiveType.set((const Type *)prim);
+
+ sm->mVertexTypeCount = vtxCount;
+ sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+ sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+ for (uint32_t ct=0; ct < vtxCount; ct++) {
+ sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
+ }
+
+ sm->mPrimitive = (RsPrimitive)primType;
+ switch(sm->mPrimitive) {
+ case RS_PRIMITIVE_POINT: sm->mGLPrimitive = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: sm->mGLPrimitive = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: sm->mGLPrimitive = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: sm->mGLPrimitive = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: sm->mGLPrimitive = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: sm->mGLPrimitive = GL_TRIANGLE_FAN; break;
+ }
+ return sm;
+}
+
+void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ rsAssert(slot < sm->mVertexTypeCount);
+
+ sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ sm->mIndexBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ 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/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h
new file mode 100644
index 0000000..03b6c2c
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.h
@@ -0,0 +1,68 @@
+/*
+ * 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 ANDROID_RS_SIMPLE_MESH_H
+#define ANDROID_RS_SIMPLE_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class SimpleMesh : public ObjectBase
+{
+public:
+ SimpleMesh();
+ ~SimpleMesh();
+
+ ObjectBaseRef<const Type> mIndexType;
+ ObjectBaseRef<const Type> mPrimitiveType;
+ ObjectBaseRef<const Type> *mVertexTypes;
+ uint32_t mVertexTypeCount;
+
+ ObjectBaseRef<Allocation> mIndexBuffer;
+ ObjectBaseRef<Allocation> mPrimitiveBuffer;
+ ObjectBaseRef<Allocation> *mVertexBuffers;
+
+ RsPrimitive mPrimitive;
+ uint32_t mGLPrimitive;
+
+
+ void render() const;
+ void renderRange(uint32_t start, uint32_t len) const;
+
+
+protected:
+};
+
+class SimpleMeshContext
+{
+public:
+ SimpleMeshContext();
+ ~SimpleMeshContext();
+
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_SIMPLE_MESH_H
+
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
new file mode 100644
index 0000000..20b0a94
--- /dev/null
+++ b/libs/rs/rsThreadIO.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include "rsThreadIO.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ThreadIO::ThreadIO()
+{
+ mToCore.init(16 * 1024);
+}
+
+ThreadIO::~ThreadIO()
+{
+}
+
+bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
+{
+ uint32_t cmdID = 0;
+ uint32_t cmdSize = 0;
+ bool ret = false;
+ while(!mToCore.isEmpty() || waitForCommand) {
+ ret = true;
+ const void * data = mToCore.get(&cmdID, &cmdSize);
+ waitForCommand = false;
+ //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
+
+ gPlaybackFuncs[cmdID](con, data);
+ mToCore.next();
+ }
+ return ret;
+}
+
+
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
new file mode 100644
index 0000000..4aab1b4
--- /dev/null
+++ b/libs/rs/rsThreadIO.h
@@ -0,0 +1,50 @@
+/*
+ * 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 ANDROID_RS_THREAD_IO_H
+#define ANDROID_RS_THREAD_IO_H
+
+#include "rsUtils.h"
+#include "rsLocklessFifo.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class ThreadIO {
+public:
+ ThreadIO();
+ ~ThreadIO();
+
+ // Plays back commands from the client.
+ // Returns true if any commands were processed.
+ bool playCoreCommands(Context *con, bool waitForCommand);
+
+
+ LocklessCommandFifo mToCore;
+ //LocklessCommandFifo mToClient;
+
+ intptr_t mToCoreRet;
+
+};
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsTriangleMesh.cpp b/libs/rs/rsTriangleMesh.cpp
new file mode 100644
index 0000000..8c7bc92
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.cpp
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+TriangleMesh::TriangleMesh()
+{
+ mVertexElement = NULL;
+ mIndexElement = NULL;
+ mVertexData = NULL;
+ mIndexData = NULL;
+ mTriangleCount = 0;
+ mVertexDataSize = 0;
+ mIndexDataSize = 0;
+
+ mBufferObjects[0] = 0;
+ mBufferObjects[1] = 0;
+
+ mOffsetCoord = 0;
+ mOffsetTex = 0;
+ mOffsetNorm = 0;
+
+ mSizeCoord = 0;
+ mSizeTex = 0;
+ mSizeNorm = 0;
+
+}
+
+TriangleMesh::~TriangleMesh()
+{
+ free(mVertexData);
+ free(mIndexData);
+}
+
+
+
+TriangleMeshContext::TriangleMeshContext()
+{
+ clear();
+}
+
+TriangleMeshContext::~TriangleMeshContext()
+{
+}
+
+void TriangleMeshContext::clear()
+{
+ mVertexElement = NULL;
+ mVertexSizeBits = 0;
+ mIndexElement = NULL;
+ mIndexSizeBits = 0;
+ mTriangleCount = 0;
+ mVertexData.clear();
+ mIndexData.clear();
+}
+
+void TriangleMesh::analyzeElement()
+{
+ for (uint32_t ct=0; ct < mVertexElement->getComponentCount(); ct++) {
+ const Component *c = mVertexElement->getComponent(ct);
+
+ if (c->getKind() == Component::X) {
+ rsAssert(mSizeCoord == 0);
+ mSizeCoord = 1;
+ mOffsetCoord = ct;
+ }
+ if (c->getKind() == Component::Y) {
+ rsAssert(mSizeCoord == 1);
+ mSizeCoord = 2;
+ }
+ if (c->getKind() == Component::Z) {
+ rsAssert(mSizeCoord == 2);
+ mSizeCoord = 3;
+ }
+ if (c->getKind() == Component::W) {
+ rsAssert(mSizeCoord == 4);
+ mSizeCoord = 4;
+ }
+
+ if (c->getKind() == Component::NX) {
+ rsAssert(mSizeNorm == 0);
+ mSizeNorm = 1;
+ mOffsetNorm = ct;
+ }
+ if (c->getKind() == Component::NY) {
+ rsAssert(mSizeNorm == 1);
+ mSizeNorm = 2;
+ }
+ if (c->getKind() == Component::NZ) {
+ rsAssert(mSizeNorm == 2);
+ mSizeNorm = 3;
+ }
+
+ if (c->getKind() == Component::S) {
+ rsAssert(mSizeTex == 0);
+ mSizeTex = 1;
+ mOffsetTex = ct;
+ }
+ if (c->getKind() == Component::T) {
+ rsAssert(mSizeTex == 1);
+ mSizeTex = 2;
+ }
+ }
+ LOGV("TriangleMesh %i,%i %i,%i %i,%i", mSizeCoord, mOffsetCoord, mSizeNorm, mOffsetNorm, mSizeTex, mOffsetTex);
+
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_TriangleMeshBegin(Context *rsc, RsElement vertex, RsElement index)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ tmc->clear();
+ tmc->mVertexElement = static_cast<Element *>(vertex);
+ tmc->mVertexSizeBits = tmc->mVertexElement->getSizeBits();
+ tmc->mIndexElement = static_cast<Element *>(index);
+ tmc->mIndexSizeBits = tmc->mIndexElement->getSizeBits();
+
+ assert(!(tmc->mVertexSizeBits & 0x7));
+ assert(!(tmc->mIndexSizeBits & 0x7));
+}
+
+void rsi_TriangleMeshAddVertex(Context *rsc, const void *data)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ for (uint32_t ct = 0; (ct * 8) < tmc->mVertexSizeBits; ct++) {
+ tmc->mVertexData.add(static_cast<const uint8_t *>(data) [ct]);
+ }
+}
+
+void rsi_TriangleMeshAddTriangle(Context *rsc, uint32_t idx1, uint32_t idx2, uint32_t idx3)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ switch(tmc->mIndexSizeBits) {
+ case 16:
+ tmc->mIndexData.add(idx1);
+ tmc->mIndexData.add(idx2);
+ tmc->mIndexData.add(idx3);
+ break;
+ default:
+ assert(0);
+ }
+
+ tmc->mTriangleCount++;
+}
+
+RsTriangleMesh rsi_TriangleMeshCreate(Context *rsc)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ TriangleMesh * tm = new TriangleMesh();
+ if (!tm) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ // error
+ return 0;
+ }
+
+ tm->mTriangleCount = tmc->mTriangleCount;
+ tm->mIndexDataSize = tmc->mIndexData.size() * tmc->mIndexSizeBits >> 3;
+ tm->mVertexDataSize = tmc->mVertexData.size();
+ tm->mIndexElement = tmc->mIndexElement;
+ tm->mVertexElement = tmc->mVertexElement;
+
+ tm->mIndexData = malloc(tm->mIndexDataSize);
+ tm->mVertexData = malloc(tm->mVertexDataSize);
+ if (!tm->mIndexData || !tm->mVertexData) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ delete tm;
+ return 0;
+ }
+
+ memcpy(tm->mVertexData, tmc->mVertexData.array(), tm->mVertexDataSize);
+ memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize);
+ tm->analyzeElement();
+
+ return tm;
+}
+
+void rsi_TriangleMeshDestroy(Context *rsc, RsTriangleMesh vtm)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ free(tm->mIndexData);
+ free(tm->mVertexData);
+ delete tm;
+}
+
+
+
+void rsi_TriangleMeshRenderRange(Context *rsc, RsTriangleMesh vtm, uint32_t first, uint32_t count)
+{
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ rsc->setupCheck();
+
+ if (!tm->mBufferObjects[0]) {
+ glGenBuffers(2, &tm->mBufferObjects[0]);
+
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ if (first >= tm->mTriangleCount) {
+ return;
+ }
+ if (count >= (tm->mTriangleCount - first)) {
+ count = tm->mTriangleCount - first;
+ }
+ if (!count) {
+ return;
+ }
+
+ const float *f = (const float *)tm->mVertexData;
+
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ 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(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetTex));
+ } else {
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+
+ if (tm->mSizeNorm) {
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetNorm));
+ } else {
+ glDisableClientState(GL_NORMAL_ARRAY);
+ }
+
+ glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, (GLvoid *)(first * 3 * 2));
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+void rsi_TriangleMeshRender(Context *rsc, RsTriangleMesh vtm)
+{
+ rsi_TriangleMeshRenderRange(rsc, vtm, 0, 0xffffff);
+}
+
+}}
diff --git a/libs/rs/rsTriangleMesh.h b/libs/rs/rsTriangleMesh.h
new file mode 100644
index 0000000..e56c7c2
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.h
@@ -0,0 +1,83 @@
+/*
+ * 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 ANDROID_RS_TRIANGLE_MESH_H
+#define ANDROID_RS_TRIANGLE_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class TriangleMesh : public ObjectBase
+{
+public:
+ TriangleMesh();
+ ~TriangleMesh();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+
+ void * mVertexData;
+ void * mIndexData;
+
+ size_t mVertexDataSize;
+ size_t mIndexDataSize;
+ uint32_t mTriangleCount;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ // GL buffer info
+ uint32_t mBufferObjects[2];
+
+ void analyzeElement();
+protected:
+};
+
+class TriangleMeshContext
+{
+public:
+ TriangleMeshContext();
+ ~TriangleMeshContext();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+ size_t mVertexSizeBits;
+ size_t mIndexSizeBits;
+
+ Vector<uint8_t> mVertexData;
+ Vector<uint16_t> mIndexData;
+
+ uint32_t mTriangleCount;
+
+ void clear();
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
new file mode 100644
index 0000000..43c3bda
--- /dev/null
+++ b/libs/rs/rsType.cpp
@@ -0,0 +1,363 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Type::Type()
+{
+ mLODs = 0;
+ mLODCount = 0;
+ memset(&mGL, 0, sizeof(mGL));
+ clear();
+}
+
+Type::~Type()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ }
+}
+
+void Type::clear()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ mLODs = NULL;
+ }
+ mDimX = 0;
+ mDimY = 0;
+ mDimZ = 0;
+ mDimLOD = 0;
+ mFaces = false;
+ mElement.clear();
+}
+
+TypeState::TypeState()
+{
+}
+
+TypeState::~TypeState()
+{
+}
+
+size_t Type::getOffsetForFace(uint32_t face) const
+{
+ rsAssert(mFaces);
+ return 0;
+}
+
+void Type::compute()
+{
+ uint32_t oldLODCount = mLODCount;
+ if (mDimLOD) {
+ uint32_t l2x = rsFindHighBit(mDimX) + 1;
+ uint32_t l2y = rsFindHighBit(mDimY) + 1;
+ uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+
+ mLODCount = rsMax(l2x, l2y);
+ mLODCount = rsMax(mLODCount, l2z);
+ } else {
+ mLODCount = 1;
+ }
+ if (mLODCount != oldLODCount) {
+ delete [] mLODs;
+ mLODs = new LOD[mLODCount];
+ }
+
+ uint32_t tx = mDimX;
+ uint32_t ty = mDimY;
+ uint32_t tz = mDimZ;
+ size_t offset = 0;
+ for (uint32_t lod=0; lod < mLODCount; lod++) {
+ mLODs[lod].mX = tx;
+ mLODs[lod].mY = ty;
+ mLODs[lod].mZ = tz;
+ mLODs[lod].mOffset = offset;
+ offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes();
+ tx = (tx + 1) >> 1;
+ ty = (ty + 1) >> 1;
+ tz = (tz + 1) >> 1;
+ }
+
+ // At this point the offset is the size of a mipmap chain;
+ mMipChainSizeBytes = offset;
+
+ if (mFaces) {
+ offset *= 6;
+ }
+ mTotalSizeBytes = offset;
+
+ makeGLComponents();
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += x * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y*mLODs[lod].mX + z*mLODs[lod].mX*mLODs[lod].mY) * mElement->getSizeBytes();
+ return offset;
+}
+
+
+void Type::makeGLComponents()
+{
+ uint32_t texNum = 0;
+ memset(&mGL, 0, sizeof(mGL));
+
+ for (uint32_t ct=0; ct < getElement()->getComponentCount(); ct++) {
+ const Component *c = getElement()->getComponent(ct);
+
+ switch(c->getKind()) {
+ case Component::X:
+ rsAssert(mGL.mVtx.size == 0);
+ mGL.mVtx.size = 1;
+ mGL.mVtx.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mVtx.type = c->getGLType();
+ break;
+ case Component::Y:
+ rsAssert(mGL.mVtx.size == 1);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 2;
+ break;
+ case Component::Z:
+ rsAssert(mGL.mVtx.size == 2);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 3;
+ break;
+ case Component::W:
+ rsAssert(mGL.mVtx.size == 4);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 4;
+ break;
+
+ case Component::RED:
+ rsAssert(mGL.mColor.size == 0);
+ mGL.mColor.size = 1;
+ mGL.mColor.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mColor.type = c->getGLType();
+ break;
+ case Component::GREEN:
+ rsAssert(mGL.mColor.size == 1);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 2;
+ break;
+ case Component::BLUE:
+ rsAssert(mGL.mColor.size == 2);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 3;
+ break;
+ case Component::ALPHA:
+ rsAssert(mGL.mColor.size == 3);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 4;
+ break;
+
+ case Component::NX:
+ rsAssert(mGL.mNorm.size == 0);
+ mGL.mNorm.size = 1;
+ mGL.mNorm.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mNorm.type = c->getGLType();
+ break;
+ case Component::NY:
+ rsAssert(mGL.mNorm.size == 1);
+ rsAssert(mGL.mNorm.type == c->getGLType());
+ mGL.mNorm.size = 2;
+ break;
+ case Component::NZ:
+ rsAssert(mGL.mNorm.size == 2);
+ rsAssert(mGL.mNorm.type == c->getGLType());
+ mGL.mNorm.size = 3;
+ break;
+
+ case Component::S:
+ if (mGL.mTex[texNum].size) {
+ texNum++;
+ }
+ mGL.mTex[texNum].size = 1;
+ mGL.mTex[texNum].offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mTex[texNum].type = c->getGLType();
+ break;
+ case Component::T:
+ rsAssert(mGL.mTex[texNum].size == 1);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 2;
+ break;
+ case Component::R:
+ rsAssert(mGL.mTex[texNum].size == 2);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 3;
+ break;
+ case Component::Q:
+ rsAssert(mGL.mTex[texNum].size == 3);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 4;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Type::enableGLVertexBuffer() const
+{
+ // Note: We are only going to enable buffers and never disable them
+ // here. The reasonis more than one Allocation may be used as a vertex
+ // source. So we cannot disable arrays that may have been in use by
+ // another allocation.
+
+ uint32_t stride = mElement->getSizeBytes();
+ if (mGL.mVtx.size) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(mGL.mVtx.size,
+ mGL.mVtx.type,
+ stride,
+ (void *)mGL.mVtx.offset);
+ }
+
+ if (mGL.mNorm.size) {
+ glEnableClientState(GL_NORMAL_ARRAY);
+ rsAssert(mGL.mNorm.size == 3);
+ glNormalPointer(mGL.mNorm.size,
+ stride,
+ (void *)mGL.mNorm.offset);
+ }
+
+ if (mGL.mColor.size) {
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(mGL.mColor.size,
+ mGL.mColor.type,
+ stride,
+ (void *)mGL.mColor.offset);
+ }
+
+ for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+ if (mGL.mTex[ct].size) {
+ glClientActiveTexture(GL_TEXTURE0 + ct);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(mGL.mTex[ct].size,
+ mGL.mTex[ct].type,
+ stride,
+ (void *)mGL.mTex[ct].offset);
+ }
+ }
+ glClientActiveTexture(GL_TEXTURE0);
+
+}
+
+
+//////////////////////////////////////////////////
+//
+namespace android {
+namespace renderscript {
+
+void rsi_TypeBegin(Context *rsc, RsElement vse)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ stc->mX = 0;
+ stc->mY = 0;
+ stc->mZ = 0;
+ stc->mLOD = false;
+ stc->mFaces = false;
+ stc->mElement.set(static_cast<const Element *>(vse));
+}
+
+void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ if (dim < 0) {
+ //error
+ return;
+ }
+
+
+ switch (dim) {
+ case RS_DIMENSION_X:
+ stc->mX = value;
+ return;
+ case RS_DIMENSION_Y:
+ stc->mY = value;
+ return;
+ case RS_DIMENSION_Z:
+ stc->mZ = value;
+ return;
+ case RS_DIMENSION_FACE:
+ stc->mFaces = (value != 0);
+ return;
+ case RS_DIMENSION_LOD:
+ stc->mLOD = (value != 0);
+ return;
+ default:
+ break;
+ }
+
+
+ int32_t arrayNum = dim - RS_DIMENSION_ARRAY_0;
+ if ((dim < 0) || (dim > RS_DIMENSION_MAX)) {
+ LOGE("rsTypeAdd: Bad dimension");
+ //error
+ return;
+ }
+
+ // todo: implement array support
+
+}
+
+RsType rsi_TypeCreate(Context *rsc)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ Type * st = new Type();
+ st->incRef();
+ st->setDimX(stc->mX);
+ st->setDimY(stc->mY);
+ st->setDimZ(stc->mZ);
+ st->setElement(stc->mElement.get());
+ st->setDimLOD(stc->mLOD);
+ st->setDimFaces(stc->mFaces);
+ st->compute();
+
+ 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
new file mode 100644
index 0000000..60d75d7
--- /dev/null
+++ b/libs/rs/rsType.h
@@ -0,0 +1,152 @@
+/*
+ * 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 ANDROID_STRUCTURED_TYPE_H
+#define ANDROID_STRUCTURED_TYPE_H
+
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Type : public ObjectBase
+{
+public:
+ Type();
+ virtual ~Type();
+
+ Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
+
+
+ size_t getOffsetForFace(uint32_t face) const;
+
+ size_t getSizeBytes() const {return mTotalSizeBytes;}
+ size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
+ const Element * getElement() const {return mElement.get();}
+
+ uint32_t getDimX() const {return mDimX;}
+ uint32_t getDimY() const {return mDimY;}
+ uint32_t getDimZ() const {return mDimZ;}
+ uint32_t getDimLOD() const {return mDimLOD;}
+ bool getDimFaces() const {return mFaces;}
+
+ uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
+ uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
+ uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
+ uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+
+ uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
+
+ uint32_t getLODCount() const {return mLODCount;}
+
+
+ void setElement(const Element *e) {mElement.set(e);}
+ void setDimX(uint32_t v) {mDimX = v;}
+ void setDimY(uint32_t v) {mDimY = v;}
+ void setDimZ(uint32_t v) {mDimZ = v;}
+ void setDimFaces(bool v) {mFaces = v;}
+ void setDimLOD(bool v) {mDimLOD = v;}
+
+ void clear();
+ void compute();
+
+ void enableGLVertexBuffer() const;
+
+
+protected:
+ struct LOD {
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ size_t mOffset;
+ };
+
+ void makeLODTable();
+
+ // Internal structure from most to least significant.
+ // * Array dimensions
+ // * Faces
+ // * Mipmaps
+ // * xyz
+
+ ObjectBaseRef<const Element> mElement;
+
+ // Size of the structure in the various dimensions. A missing Dimension is
+ // specified as a 0 and not a 1.
+ size_t mDimX;
+ size_t mDimY;
+ size_t mDimZ;
+ bool mDimLOD;
+ bool mFaces;
+
+ // A list of array dimensions. The count is the number of array dimensions and the
+ // sizes is a per array size.
+ //Vector<size_t> mDimArraysSizes;
+
+ // count of mipmap levels, 0 indicates no mipmapping
+
+ size_t mMipChainSizeBytes;
+ size_t mTotalSizeBytes;
+ LOD *mLODs;
+ uint32_t mLODCount;
+
+ struct VertexComponent_t {
+ uint32_t offset;
+ uint32_t type;
+ uint32_t size;
+ uint32_t stride;
+ };
+ struct GLState_t {
+ VertexComponent_t mVtx;
+ VertexComponent_t mNorm;
+ VertexComponent_t mColor;
+ VertexComponent_t mTex[RS_MAX_TEXTURE];
+ };
+ GLState_t mGL;
+ void makeGLComponents();
+
+private:
+ Type(const Type &);
+};
+
+
+class TypeState {
+public:
+ TypeState();
+ ~TypeState();
+
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ uint32_t mLOD;
+ bool mFaces;
+ ObjectBaseRef<const Element> mElement;
+
+ ObjectBaseRef<const Type> mIndexType;
+ ObjectBaseRef<const Type> mPrimitiveType;
+ ObjectBaseRef<const Type> *mVertexTypes;
+
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_TYPE
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
new file mode 100644
index 0000000..ec928db
--- /dev/null
+++ b/libs/rs/rsUtils.h
@@ -0,0 +1,133 @@
+/*
+ * 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 ANDROID_RS_UTILS_H
+#define ANDROID_RS_UTILS_H
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "rs"
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <EGL/egl.h>
+#include <math.h>
+
+#include "RenderScript.h"
+
+namespace android {
+namespace renderscript {
+
+#if 1
+#define rsAssert(v) do {if(!(v)) LOGE("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__);} while(0)
+#else
+#define rsAssert(v) while(0)
+#endif
+
+#define RS_LOG_TIMES 0
+
+template<typename T>
+T rsMin(T in1, T in2)
+{
+ if (in1 > in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsMax(T in1, T in2)
+{
+ if (in1 < in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsFindHighBit(T val)
+{
+ uint32_t bit = 0;
+ while(val > 1) {
+ bit++;
+ val>>=1;
+ }
+ return bit;
+}
+
+template<typename T>
+bool rsIsPow2(T val)
+{
+ return (val & (val-1)) == 0;
+}
+
+template<typename T>
+T rsHigherPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << (rsFindHighBit(v) + 1);
+}
+
+template<typename T>
+T rsLowerPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << rsFindHighBit(v);
+}
+
+
+static inline uint16_t rs888to565(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint16_t t = 0;
+ t |= b >> 3;
+ t |= (g >> 2) << 5;
+ t |= (r >> 3) << 11;
+ return t;
+}
+
+static inline uint16_t rsBoxFilter565(uint16_t i1, uint16_t i2, uint16_t i3, uint16_t i4)
+{
+ uint32_t r = ((i1 & 0x1f) + (i2 & 0x1f) + (i3 & 0x1f) + (i4 & 0x1f));
+ uint32_t g = ((i1 >> 5) & 0x3f) + ((i2 >> 5) & 0x3f) + ((i3 >> 5) & 0x3f) + ((i4 >> 5) & 0x3f);
+ uint32_t b = ((i1 >> 11) + (i2 >> 11) + (i3 >> 11) + (i4 >> 11));
+ return (r >> 2) | ((g >> 2) << 5) | ((b >> 2) << 11);
+}
+
+static inline uint32_t rsBoxFilter8888(uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4)
+{
+ uint32_t r = (i1 & 0xff) + (i2 & 0xff) + (i3 & 0xff) + (i4 & 0xff);
+ uint32_t g = ((i1 >> 8) & 0xff) + ((i2 >> 8) & 0xff) + ((i3 >> 8) & 0xff) + ((i4 >> 8) & 0xff);
+ uint32_t b = ((i1 >> 16) & 0xff) + ((i2 >> 16) & 0xff) + ((i3 >> 16) & 0xff) + ((i4 >> 16) & 0xff);
+ uint32_t a = ((i1 >> 24) & 0xff) + ((i2 >> 24) & 0xff) + ((i3 >> 24) & 0xff) + ((i4 >> 24) & 0xff);
+ return (r >> 2) | ((g >> 2) << 8) | ((b >> 2) << 16) | ((a >> 2) << 24);
+}
+
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
+
diff --git a/libs/rs/rsgApi.cpp.rsg b/libs/rs/rsgApi.cpp.rsg
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/libs/rs/rsgApi.cpp.rsg
@@ -0,0 +1 @@
+2
diff --git a/libs/rs/rsgApiFuncDecl.h.rsg b/libs/rs/rsgApiFuncDecl.h.rsg
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/libs/rs/rsgApiFuncDecl.h.rsg
@@ -0,0 +1 @@
+1
diff --git a/libs/rs/rsgApiReplay.cpp.rsg b/libs/rs/rsgApiReplay.cpp.rsg
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/libs/rs/rsgApiReplay.cpp.rsg
@@ -0,0 +1 @@
+3
diff --git a/libs/rs/rsgApiStructs.h.rsg b/libs/rs/rsgApiStructs.h.rsg
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/libs/rs/rsgApiStructs.h.rsg
@@ -0,0 +1 @@
+0
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
new file mode 100644
index 0000000..e3f816f
--- /dev/null
+++ b/libs/rs/rsg_generator.c
@@ -0,0 +1,293 @@
+
+#include "spec.h"
+#include <stdio.h>
+
+void printFileHeader(FILE *f)
+{
+ fprintf(f, "/*\n");
+ fprintf(f, " * Copyright (C) 2009 The Android Open Source Project\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n");
+ fprintf(f, " * you may not use this file except in compliance with the License.\n");
+ fprintf(f, " * You may obtain a copy of the License at\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * http://www.apache.org/licenses/LICENSE-2.0\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Unless required by applicable law or agreed to in writing, software\n");
+ fprintf(f, " * distributed under the License is distributed on an \"AS IS\" BASIS,\n");
+ fprintf(f, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
+ fprintf(f, " * See the License for the specific language governing permissions and\n");
+ fprintf(f, " * limitations under the License.\n");
+ fprintf(f, " */\n\n");
+}
+
+void printVarType(FILE *f, const VarType *vt)
+{
+ int ct;
+ if (vt->isConst) {
+ fprintf(f, "const ");
+ }
+
+ switch(vt->type) {
+ case 0:
+ fprintf(f, "void");
+ break;
+ case 1:
+ fprintf(f, "int%i_t", vt->bits);
+ break;
+ case 2:
+ fprintf(f, "uint%i_t", vt->bits);
+ break;
+ case 3:
+ if (vt->bits == 32)
+ fprintf(f, "float");
+ else
+ fprintf(f, "double");
+ break;
+ case 4:
+ fprintf(f, "%s", vt->typeName);
+ break;
+ }
+
+ if(vt->ptrLevel) {
+ fprintf(f, " ");
+ for(ct=0; ct < vt->ptrLevel; ct++) {
+ fprintf(f, "*");
+ }
+ }
+
+ if(vt->name[0]) {
+ fprintf(f, " %s", vt->name);
+ }
+}
+
+void printArgList(FILE *f, const ApiEntry * api, int assumePrevious)
+{
+ int ct;
+ for(ct=0; ct < api->paramCount; ct++) {
+ if (ct || assumePrevious) {
+ fprintf(f, ", ");
+ }
+ printVarType(f, &api->params[ct]);
+ }
+}
+
+void printStructures(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "typedef struct RS_CMD_%s_rec RS_CMD_%s;\n", apis[ct].name, apis[ct].name);
+ }
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+ fprintf(f, "#define RS_CMD_ID_%s %i\n", api->name, ct+1);
+ fprintf(f, "struct RS_CMD_%s_rec {\n", api->name);
+ //fprintf(f, " RsCommandHeader _hdr;\n");
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ fprintf(f, " ");
+ printVarType(f, &api->params[ct2]);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext)
+{
+ printVarType(f, &api->ret);
+ fprintf(f, " %s%s (", prefix, api->name);
+ if (addContext) {
+ fprintf(f, "Context *");
+ } else {
+ fprintf(f, "RsContext rsc");
+ }
+ printArgList(f, api, 1);
+ fprintf(f, ")");
+}
+
+void printFuncDecls(FILE *f, const char *prefix, int addContext)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ printFuncDecl(f, &apis[ct], prefix, addContext);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "\n\n");
+}
+
+void printPlaybackFuncs(FILE *f, const char *prefix)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name);
+ }
+}
+
+void printApiCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "using namespace android;\n");
+ fprintf(f, "using namespace android::renderscript;\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ int needFlush = 0;
+ const ApiEntry * api = &apis[ct];
+
+ printFuncDecl(f, api, "rs", 0);
+ fprintf(f, "\n{\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);
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ needFlush += vt->ptrLevel;
+ fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name);
+ }
+ if (api->ret.typeName[0]) {
+ needFlush = 1;
+ }
+
+ fprintf(f, " io->mToCore.commit");
+ if (needFlush) {
+ fprintf(f, "Sync");
+ }
+ fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name);
+
+ if (api->ret.typeName[0]) {
+ fprintf(f, " return reinterpret_cast<");
+ printVarType(f, &api->ret);
+ fprintf(f, ">(io->mToCoreRet);\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printPlaybackCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+
+ fprintf(f, "void rsp_%s(Context *con, const void *vp)\n", api->name);
+ fprintf(f, "{\n");
+ //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name);
+ 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, "con->mIO.mToCoreRet = (intptr_t)");
+ }
+ fprintf(f, "rsi_%s(con", api->name);
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ fprintf(f, ",");
+ fprintf(f, "\n cmd->%s", vt->name);
+ }
+ fprintf(f, ");\n");
+
+ fprintf(f, "};\n\n");
+ }
+
+ fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n");
+ fprintf(f, " NULL,\n");
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, " %s%s,\n", "rsp_", apis[ct].name);
+ }
+ fprintf(f, "};\n");
+
+ fprintf(f, "};\n");
+ fprintf(f, "};\n");
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]);
+ return 1;
+ }
+ const char* rsgFile = argv[1];
+ const char* outFile = argv[2];
+ FILE* input = fopen(rsgFile, "r");
+
+ char choice = fgetc(input);
+ fclose(input);
+
+ if (choice < '0' || choice > '3') {
+ fprintf(stderr, "Uknown command: \'%c\'\n", choice);
+ return -2;
+ }
+
+ yylex();
+ // printf("# of lines = %d\n", num_lines);
+
+ FILE *f = fopen(outFile, "w");
+
+ printFileHeader(f);
+ switch(choice) {
+ case '0': // rsgApiStructs.h
+ {
+ fprintf(f, "\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ printStructures(f);
+ printFuncDecls(f, "rsi_", 1);
+ printPlaybackFuncs(f, "rsp_");
+ fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n");
+ fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n");
+
+ fprintf(f, "}\n");
+ fprintf(f, "}\n");
+ }
+ break;
+
+ case '1': // rsgApiFuncDecl.h
+ {
+ printFuncDecls(f, "rs", 0);
+ }
+ break;
+
+ case '2': // rsgApi.cpp
+ {
+ printApiCpp(f);
+ }
+ break;
+
+ case '3': // rsgApiReplay.cpp
+ {
+ printFileHeader(f);
+ printPlaybackCpp(f);
+ }
+ break;
+ }
+ fclose(f);
+ return 0;
+}
diff --git a/libs/rs/spec.h b/libs/rs/spec.h
new file mode 100644
index 0000000..ba802f7
--- /dev/null
+++ b/libs/rs/spec.h
@@ -0,0 +1,41 @@
+#ifndef SPEC_H
+#define SPEC_H
+
+#include <string.h>
+#include <stdlib.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern int num_lines;
+
+typedef struct {
+ int isConst;
+ int type;
+ int bits;
+ int ptrLevel;
+ char name[256];
+ char typeName[256];
+} VarType;
+
+extern VarType *currType;
+
+typedef struct {
+ char name[256];
+ int sync;
+ int paramCount;
+ VarType ret;
+ VarType params[16];
+} ApiEntry;
+
+extern ApiEntry apis[128];
+extern int apiCount;
+
+extern int typeNextState;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // SPEC_H
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
new file mode 100644
index 0000000..62fcb63
--- /dev/null
+++ b/libs/rs/spec.l
@@ -0,0 +1,157 @@
+%option stack
+
+%x comment
+%x api_entry
+%x api_entry2
+%x api_entry_param
+%x var_type
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_]*
+
+ #include "spec.h"
+
+ int num_lines = 0;
+
+ VarType *currType = 0;
+
+ ApiEntry apis[128];
+ int apiCount = 0;
+
+ int typeNextState;
+
+ extern "C" int yylex();
+
+%%
+
+"/*" BEGIN(comment);
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++num_lines;
+<comment>"*"+"/" BEGIN(INITIAL);
+
+<*>" " //printf("found ' '\n");
+<*>"\n" ++num_lines; //printf("found lf \n");
+
+{ID} {
+ memset(&apis[apiCount], 0, sizeof(ApiEntry));
+ memcpy(apis[apiCount].name, yytext, yyleng);
+ BEGIN(api_entry);
+ }
+
+<api_entry>"{" {
+ BEGIN(api_entry2);
+ }
+
+<api_entry2>"sync" {
+ apis[apiCount].sync = 1;
+ }
+
+<api_entry2>"ret" {
+ currType = &apis[apiCount].ret;
+ typeNextState = api_entry2;
+ BEGIN(var_type);
+ }
+
+<api_entry2>"param" {
+ currType = &apis[apiCount].params[apis[apiCount].paramCount];
+ apis[apiCount].paramCount++;
+ typeNextState = api_entry_param;
+ BEGIN(var_type);
+ }
+
+<var_type>"const" {
+ currType->isConst = 1;
+ }
+
+<var_type>"i8" {
+ currType->type = 1;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i16" {
+ currType->type = 1;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i32" {
+ currType->type = 1;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i64" {
+ currType->type = 1;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u8" {
+ currType->type = 2;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u16" {
+ currType->type = 2;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u32" {
+ currType->type = 2;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u64" {
+ currType->type = 2;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"f" {
+ currType->type = 3;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"d" {
+ currType->type = 3;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>{ID} {
+ currType->type = 4;
+ currType->bits = 32;
+ memcpy(currType->typeName, yytext, yyleng);
+ BEGIN(typeNextState);
+ }
+
+<api_entry_param>"*" {
+ currType->ptrLevel ++;
+ }
+
+<api_entry_param>{ID} {
+ memcpy(currType->name, yytext, yyleng);
+ BEGIN(api_entry2);
+ }
+
+
+<api_entry2>"}" {
+ apiCount++;
+ BEGIN(INITIAL);
+ }
+
+
+%%
+
+
+int yywrap()
+{
+ return 1;
+}
+
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index ec5aa3f..c4a70c8 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -5,44 +5,52 @@
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- GPUHardware/GPUHardware.cpp \
BlurFilter.cpp.arm \
- CPUGauge.cpp \
+ BufferAllocator.cpp \
Layer.cpp \
LayerBase.cpp \
LayerBuffer.cpp \
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
- LayerOrientationAnim.cpp \
- OrientationAnimation.cpp \
+ MessageQueue.cpp \
SurfaceFlinger.cpp \
Tokenizer.cpp \
- Transform.cpp \
- VRamHeap.cpp
+ Transform.cpp
+LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+ifeq ($(TARGET_BOARD_PLATFORM), msm7k)
+ LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
+ifeq ($(TARGET_BOARD_PLATFORM), qsd8k)
+ LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
+ LOCAL_LDLIBS += -lrt -lpthread
endif
endif
LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libpixelflinger \
libhardware \
libutils \
- libcutils \
- libui \
- libcorecg \
- libsgl \
- libpixelflinger \
+ libskia \
libEGL \
- libGLESv1_CM
+ libGLESv1_CM \
+ libbinder \
+ libui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
+LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc
+
LOCAL_MODULE:= libsurfaceflinger
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/BufferAllocator.cpp b/libs/surfaceflinger/BufferAllocator.cpp
new file mode 100644
index 0000000..cee8b64
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.cpp
@@ -0,0 +1,118 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
+
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include "BufferAllocator.h"
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferAllocator )
+
+Mutex BufferAllocator::sLock;
+KeyedVector<buffer_handle_t, BufferAllocator::alloc_rec_t> BufferAllocator::sAllocList;
+
+BufferAllocator::BufferAllocator()
+ : mAllocDev(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ gralloc_open(module, &mAllocDev);
+ }
+}
+
+BufferAllocator::~BufferAllocator()
+{
+ gralloc_close(mAllocDev);
+}
+
+void BufferAllocator::dump(String8& result) const
+{
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ size_t total = 0;
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "Allocated buffers:\n");
+ result.append(buffer);
+ const size_t c = list.size();
+ for (size_t i=0 ; i<c ; i++) {
+ const alloc_rec_t& rec(list.valueAt(i));
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u x %4u | %2d | 0x%08x\n",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.h, rec.format, rec.usage);
+ result.append(buffer);
+ total += rec.size;
+ }
+ snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ result.append(buffer);
+}
+
+status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
+ int usage, buffer_handle_t* handle, int32_t* stride)
+{
+ Mutex::Autolock _l(mLock);
+
+ // we have a h/w allocator and h/w buffer is requested
+ status_t err = mAllocDev->alloc(mAllocDev,
+ w, h, format, usage, handle, stride);
+ LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
+ w, h, format, usage, err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ alloc_rec_t rec;
+ rec.w = w;
+ rec.h = h;
+ rec.format = format;
+ rec.usage = usage;
+ rec.vaddr = 0;
+ rec.size = h * stride[0] * bytesPerPixel(format);
+ list.add(*handle, rec);
+ }
+
+ return err;
+}
+
+status_t BufferAllocator::free(buffer_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+
+ status_t err = mAllocDev->free(mAllocDev, handle);
+ LOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ list.removeItem(handle);
+ }
+
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/BufferAllocator.h b/libs/surfaceflinger/BufferAllocator.h
new file mode 100644
index 0000000..a279ded
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.h
@@ -0,0 +1,96 @@
+/*
+**
+** Copyright 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 ANDROID_BUFFER_ALLOCATOR_H
+#define ANDROID_BUFFER_ALLOCATOR_H
+
+#include <stdint.h>
+
+#include <cutils/native_handle.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Singleton.h>
+
+#include <ui/PixelFormat.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class BufferAllocator : public Singleton<BufferAllocator>
+{
+public:
+ enum {
+ USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER,
+ USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY,
+ USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN,
+ USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK,
+
+ USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER,
+ USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY,
+ USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN,
+ USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK,
+
+ USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
+
+ USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE,
+ USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER,
+ USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
+ USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
+ };
+
+ static inline BufferAllocator& get() { return getInstance(); }
+
+
+ status_t alloc(uint32_t w, uint32_t h, PixelFormat format, int usage,
+ buffer_handle_t* handle, int32_t* stride);
+
+ status_t free(buffer_handle_t handle);
+
+ void dump(String8& res) const;
+
+private:
+ struct alloc_rec_t {
+ uint32_t w;
+ uint32_t h;
+ PixelFormat format;
+ uint32_t usage;
+ void* vaddr;
+ size_t size;
+ };
+
+ static Mutex sLock;
+ static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList;
+
+ friend class Singleton<BufferAllocator>;
+ BufferAllocator();
+ ~BufferAllocator();
+
+ mutable Mutex mLock;
+ alloc_device_t *mAllocDev;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFER_ALLOCATOR_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
deleted file mode 100644
index 74a9270..0000000
--- a/libs/surfaceflinger/CPUGauge.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "CPUGauge"
-
-#include <stdint.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <math.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/DisplayInfo.h>
-#include <ui/ISurfaceComposer.h>
-#include <ui/ISurfaceFlingerClient.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "CPUGauge.h"
-
-namespace android {
-
-CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval,
- int clock,
- int refclock)
- : Thread(false),
- mInterval(interval), mClock(clock), mRefClock(refclock),
- mReferenceTime(0),
- mReferenceWorkingTime(0), mCpuUsage(0),
- mRefIdleTime(0), mIdleTime(0)
-{
- mFd = fopen("/proc/stat", "r");
- setvbuf(mFd, NULL, _IONBF, 0);
-
- mSession = SurfaceComposerClient::clientForConnection(
- composer->createConnection()->asBinder());
-}
-
-CPUGauge::~CPUGauge()
-{
- fclose(mFd);
-}
-
-const sp<SurfaceComposerClient>& CPUGauge::session() const
-{
- return mSession;
-}
-
-void CPUGauge::onFirstRef()
-{
- run("CPU Gauge");
-}
-
-status_t CPUGauge::readyToRun()
-{
- LOGI("Starting CPU gauge...");
- return NO_ERROR;
-}
-
-bool CPUGauge::threadLoop()
-{
- DisplayInfo dinfo;
- session()->getDisplayInfo(0, &dinfo);
- sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
- session()->openTransaction();
- s->setLayer(INT_MAX);
- session()->closeTransaction();
-
- static const GGLfixed colors[4][4] = {
- { 0x00000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x00000, 0x00000, 0x10000 },
- { 0x00000, 0x00000, 0x00000, 0x10000 },
- };
-
- GGLContext* gl;
- gglInit(&gl);
- gl->activeTexture(gl, 0);
- gl->disable(gl, GGL_TEXTURE_2D);
- gl->disable(gl, GGL_BLEND);
-
- const int w = dinfo.w;
-
- while(!exitPending())
- {
- mLock.lock();
- const float cpuUsage = this->cpuUsage();
- const float totalCpuUsage = 1.0f - idle();
- mLock.unlock();
-
- Surface::SurfaceInfo info;
- s->lock(&info);
- GGLSurface fb;
- fb.version = sizeof(GGLSurface);
- fb.width = info.w;
- fb.height = info.h;
- fb.stride = info.w;
- fb.format = info.format;
- fb.data = (GGLubyte*)info.bits;
-
- gl->colorBuffer(gl, &fb);
- gl->color4xv(gl, colors[3]);
- gl->recti(gl, 0, 0, w, 4);
- gl->color4xv(gl, colors[2]); // red
- gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
- gl->color4xv(gl, colors[0]); // green
- gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
-
- s->unlockAndPost();
-
- usleep(ns2us(mInterval));
- }
-
- gglUninit(gl);
- return false;
-}
-
-void CPUGauge::sample()
-{
- if (mLock.tryLock() == NO_ERROR) {
- const nsecs_t now = systemTime(mRefClock);
- const nsecs_t referenceTime = now-mReferenceTime;
- if (referenceTime >= mInterval) {
- const float reftime = 1.0f / referenceTime;
- const nsecs_t nowWorkingTime = systemTime(mClock);
-
- char buf[256];
- fgets(buf, 256, mFd);
- rewind(mFd);
- char *str = buf+5;
- char const * const usermode = strsep(&str, " "); (void)usermode;
- char const * const usernice = strsep(&str, " "); (void)usernice;
- char const * const systemmode = strsep(&str, " ");(void)systemmode;
- char const * const idle = strsep(&str, " ");
- const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
- mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
- mRefIdleTime = nowIdleTime;
-
- const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
- const float newCpuUsage = float(workingTime) * reftime;
- if (mCpuUsage != newCpuUsage) {
- mCpuUsage = newCpuUsage;
- mReferenceWorkingTime = nowWorkingTime;
- mReferenceTime = now;
- }
- }
- mLock.unlock();
- }
-}
-
-
-}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
deleted file mode 100644
index 5bb53c0..0000000
--- a/libs/surfaceflinger/CPUGauge.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_CPUGAUGE_H
-#define ANDROID_CPUGAUGE_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/SurfaceComposerClient.h>
-
-namespace android {
-
-class CPUGauge : public Thread
-{
-public:
- CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval=s2ns(1),
- int clock=SYSTEM_TIME_THREAD,
- int refclock=SYSTEM_TIME_MONOTONIC);
-
- ~CPUGauge();
-
- const sp<SurfaceComposerClient>& session() const;
-
- void sample();
-
- inline float cpuUsage() const { return mCpuUsage; }
- inline float idle() const { return mIdleTime; }
-
-private:
- virtual void onFirstRef();
- virtual status_t readyToRun();
- virtual bool threadLoop();
-
- Mutex mLock;
-
- sp<SurfaceComposerClient> mSession;
-
- const nsecs_t mInterval;
- const int mClock;
- const int mRefClock;
-
- nsecs_t mReferenceTime;
- nsecs_t mReferenceWorkingTime;
- float mCpuUsage;
- nsecs_t mRefIdleTime;
- float mIdleTime;
- FILE* mFd;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index ab02fa0..3f607f6 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -23,43 +21,27 @@
#include <cutils/properties.h>
+#include <utils/RefBase.h>
#include <utils/Log.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/PixelFormat.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
#include <hardware/overlay.h>
+#include <hardware/gralloc.h>
using namespace android;
-static __attribute__((noinline))
-const char *egl_strerror(EGLint err)
-{
- switch (err){
- case EGL_SUCCESS: return "EGL_SUCCESS";
- case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
- case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
- case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
- case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
- case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
- case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
- case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
- case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
- case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
- case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
- default: return "UNKNOWN";
- }
-}
static __attribute__((noinline))
void checkGLErrors()
@@ -76,7 +58,7 @@
// GLESonGL seems to be returning 0 when there is no errors?
if (error && error != EGL_SUCCESS)
LOGE("%s error 0x%04x (%s)",
- token, int(error), egl_strerror(error));
+ token, int(error), EGLUtils::strerror(error));
}
@@ -108,17 +90,22 @@
void DisplayHardware::init(uint32_t dpy)
{
+ mNativeWindow = new FramebufferNativeWindow();
+ framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+
+ mOverlayEngine = NULL;
+ hw_module_t const* module;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+
// initialize EGL
const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 0,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLint w, h, dummy;
- EGLint numConfigs, n;
- EGLConfig config;
+ EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
mFlags = 0;
@@ -129,7 +116,17 @@
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
- eglChooseConfig(display, attribs, &config, 1, &n);
+
+ EGLConfig config;
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ display, attribs, mNativeWindow.get(), &config);
+ LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
/*
* Gather EGL extensions
@@ -144,13 +141,13 @@
LOGI("version : %s", eglQueryString(display, EGL_VERSION));
LOGI("extensions: %s", egl_extensions);
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-
- // TODO: get this from the devfb driver (probably should be HAL module)
- mFlags |= SWAP_RECTANGLE_EXTENSION;
+ LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
- // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
- mFlags |= UPDATE_ON_DEMAND;
+ if (mNativeWindow->isUpdateOnDemand()) {
+ mFlags |= UPDATE_ON_DEMAND;
+ }
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -160,37 +157,43 @@
* Create our main surface
*/
- mDisplaySurface = new EGLDisplaySurface();
-
- surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
- //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+ checkEGLErrors("eglCreateWindowSurface");
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
-
- GLint value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiX = 160.0f;
- } else {
- mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
+ if (eglSetSwapRectangleANDROID(display, surface,
+ 0, 0, mWidth, mHeight) == EGL_TRUE) {
+ // This could fail if this extension is not supported by this
+ // specific surface (of config)
+ mFlags |= SWAP_RECTANGLE;
+ }
}
- value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiY = 160.0f;
- } else {
- mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
- }
- mRefreshRate = 60.f; // TODO: get the real refresh rate
+ // when we have the choice between UPDATE_ON_DEMAND and SWAP_RECTANGLE
+ // choose UPDATE_ON_DEMAND, which is more efficient
+ if (mFlags & UPDATE_ON_DEMAND)
+ mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+ LOGI("flags : %08x", mFlags);
+
+ mDpiX = mNativeWindow->xdpi;
+ mDpiY = mNativeWindow->ydpi;
+ mRefreshRate = fbDev->fps;
char property[PROPERTY_VALUE_MAX];
/* Read density from build-specific ro.sf.lcd_density property
- * except if it is overriden by qemu.sf.lcd_density.
+ * except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
@@ -211,9 +214,6 @@
context = eglCreateContext(display, config, NULL, NULL);
//checkEGLErrors("eglCreateContext");
- eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
- eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
-
/*
* Gather OpenGL ES extensions
@@ -233,7 +233,10 @@
if (strstr(gl_extensions, "GL_OES_draw_texture")) {
mFlags |= DRAW_TEXTURE_EXTENSION;
}
- if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+ if (strstr( gl_extensions, "GL_OES_EGL_image") &&
+ (strstr(egl_extensions, "EGL_KHR_image_base") ||
+ strstr(egl_extensions, "EGL_KHR_image")) &&
+ strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
mFlags |= DIRECT_TEXTURE;
}
@@ -244,19 +247,8 @@
mConfig = config;
mSurface = surface;
mContext = context;
- mFormat = GGL_PIXEL_FORMAT_RGB_565;
-
- hw_module_t const* module;
-
- mBlitEngine = NULL;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- mOverlayEngine = NULL;
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- overlay_control_open(module, &mOverlayEngine);
- }
+ mFormat = fbDev->format;
+ mPageFlipCount = 0;
}
/*
@@ -270,7 +262,6 @@
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- copybit_close(mBlitEngine);
overlay_control_close(mOverlayEngine);
}
@@ -284,28 +275,8 @@
DisplayHardwareBase::acquireScreen();
}
-void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
-{
- img->w = mDisplaySurface->stride;
- img->h = mDisplaySurface->height;
- img->format = mDisplaySurface->format;
- img->offset = mDisplaySurface->offset;
- img->base = (void*)mDisplaySurface->base;
- img->fd = mDisplaySurface->fd;
-}
-
-void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
-{
- fb->version= sizeof(GGLSurface);
- fb->width = mDisplaySurface->width;
- fb->height = mDisplaySurface->height;
- fb->stride = mDisplaySurface->stride;
- fb->format = mDisplaySurface->format;
- fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
-}
-
uint32_t DisplayHardware::getPageFlipCount() const {
- return mDisplaySurface->getPageFlipCount();
+ return mPageFlipCount;
}
/*
@@ -319,21 +290,20 @@
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
- Region newDirty(dirty);
- newDirty.andSelf(Rect(mWidth, mHeight));
-
- if (mFlags & BUFFER_PRESERVED) {
- const Region copyback(mDirty.subtract(newDirty));
- mDirty = newDirty;
- mDisplaySurface->copyFrontToBack(copyback);
- }
-
- if (mFlags & SWAP_RECTANGLE_EXTENSION) {
- const Rect& b(newDirty.bounds());
- mDisplaySurface->setSwapRectangle(
+#ifdef EGL_ANDROID_swap_rectangle
+ if (mFlags & SWAP_RECTANGLE) {
+ const Region newDirty(dirty.intersect(bounds()));
+ const Rect b(newDirty.getBounds());
+ eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
+ }
+#endif
+
+ if (mFlags & UPDATE_ON_DEMAND) {
+ mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
-
+
+ mPageFlipCount++;
eglSwapBuffers(dpy, surface);
checkEGLErrors("eglSwapBuffers");
@@ -351,11 +321,3 @@
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
-
-void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyFrontToImage(front);
-}
-
-void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyBackToImage(front);
-}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 550a4d1..8972d51 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,31 +22,35 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
-struct copybit_device_t;
+struct framebuffer_device_t;
struct copybit_image_t;
-struct copybit_t;
namespace android {
-class EGLDisplaySurface;
+class FramebufferNativeWindow;
class DisplayHardware : public DisplayHardwareBase
{
public:
enum {
DIRECT_TEXTURE = 0x00000002,
- SWAP_RECTANGLE_EXTENSION= 0x00000004,
COPY_BITS_EXTENSION = 0x00000008,
NPOT_EXTENSION = 0x00000100,
DRAW_TEXTURE_EXTENSION = 0x00000200,
BUFFER_PRESERVED = 0x00010000,
UPDATE_ON_DEMAND = 0x00020000, // video driver feature
SLOW_CONFIG = 0x00040000, // software
+ SWAP_RECTANGLE = 0x00080000,
};
DisplayHardware(
@@ -73,15 +77,9 @@
void makeCurrent() const;
uint32_t getPageFlipCount() const;
- void getDisplaySurface(copybit_image_t* img) const;
- void getDisplaySurface(GGLSurface* fb) const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
- copybit_device_t* getBlitEngine() const { return mBlitEngine; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
- void copyFrontToImage(const copybit_image_t& front) const;
- void copyBackToImage(const copybit_image_t& front) const;
-
Rect bounds() const {
return Rect(mWidth, mHeight);
}
@@ -102,9 +100,9 @@
int mHeight;
PixelFormat mFormat;
uint32_t mFlags;
- mutable Region mDirty;
- sp<EGLDisplaySurface> mDisplaySurface;
- copybit_device_t* mBlitEngine;
+ mutable uint32_t mPageFlipCount;
+
+ sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f75e5c2..1d09f84 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
deleted file mode 100644
index 7168bf2..0000000
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ /dev/null
@@ -1,585 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/IBinder.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IPCThreadState.h>
-#include <utils/StopWatch.h>
-
-#include <ui/ISurfaceComposer.h>
-
-#include "VRamHeap.h"
-#include "GPUHardware.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include "GPUHardware/GPUHardware.h"
-
-
-/*
- * Manage the GPU. This implementation is very specific to the G1.
- * There are no abstraction here.
- *
- * All this code will soon go-away and be replaced by a new architecture
- * for managing graphics accelerators.
- *
- * In the meantime, it is conceptually possible to instantiate a
- * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
- * of this file); practically... doubtful.
- *
- */
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class GPUClientHeap;
-class GPUAreaHeap;
-
-class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
-{
-public:
- static const int GPU_RESERVED_SIZE;
- static const int GPUR_SIZE;
-
- GPUHardware();
- virtual ~GPUHardware();
-
- virtual void revoke(int pid);
- virtual sp<MemoryDealer> request(int pid);
- virtual status_t request(int pid,
- const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu);
-
- virtual status_t friendlyRevoke();
- virtual void unconditionalRevoke();
-
- virtual pid_t getOwner() const { return mOwner; }
-
- // used for debugging only...
- virtual sp<SimpleBestFitAllocator> getAllocator() const;
-
-private:
-
-
- enum {
- NO_OWNER = -1,
- };
-
- struct GPUArea {
- sp<GPUAreaHeap> heap;
- sp<MemoryHeapPmem> clientHeap;
- sp<IMemory> map();
- };
-
- struct Client {
- pid_t pid;
- GPUArea smi;
- GPUArea ebi;
- GPUArea reg;
- void createClientHeaps();
- void revokeAllHeaps();
- };
-
- Client& getClientLocked(pid_t pid);
- status_t requestLocked(int pid);
- void releaseLocked();
- void takeBackGPULocked();
- void registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client);
-
- virtual void binderDied(const wp<IBinder>& who);
-
- mutable Mutex mLock;
- sp<GPUAreaHeap> mSMIHeap;
- sp<GPUAreaHeap> mEBIHeap;
- sp<GPUAreaHeap> mREGHeap;
-
- KeyedVector<pid_t, Client> mClients;
- DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
-
- pid_t mOwner;
-
- sp<MemoryDealer> mCurrentAllocator;
- sp<IGPUCallback> mCallback;
-
- sp<SimpleBestFitAllocator> mAllocator;
-
- Condition mCondition;
-};
-
-// size reserved for GPU surfaces
-// 1200 KB fits exactly:
-// - two 320*480 16-bits double-buffered surfaces
-// - one 320*480 32-bits double-buffered surface
-// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
-const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
-const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
-
-// ---------------------------------------------------------------------------
-
-/*
- * GPUHandle is a special IMemory given to the client. It represents their
- * handle to the GPU. Once they give it up, they loose GPU access, or if
- * they explicitly revoke their access through the binder code 1000.
- * In both cases, this triggers a callback to revoke()
- * first, and then actually powers down the chip.
- *
- * In the case of a misbehaving app, GPUHardware can ask for an immediate
- * release of the GPU to the target process which should answer by calling
- * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
- * be revoked from under their feet.
- *
- * We should never hold a strong reference on GPUHandle. In practice this
- * shouldn't be a big issue though because clients should use code 1000 and
- * not rely on the dtor being called.
- *
- */
-
-class GPUClientHeap : public MemoryHeapPmem
-{
-public:
- GPUClientHeap(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : MemoryHeapPmem(heap), mGPU(gpu) { }
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPUAreaHeap : public MemoryHeapBase
-{
-public:
- GPUAreaHeap(const wp<GPUHardware>& gpu,
- const char* const vram, size_t size=0, size_t reserved=0)
- : MemoryHeapBase(vram, size), mGPU(gpu) {
- if (base() != MAP_FAILED) {
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
- }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new GPUClientHeap(mGPU, parentHeap);
- }
- virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
- return mAllocator;
- }
-private:
- sp<SimpleBestFitAllocator> mAllocator;
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPURegisterHeap : public GPUAreaHeap
-{
-public:
- GPURegisterHeap(const sp<GPUHardware>& gpu)
- : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapRegs(mGPU, parentHeap);
- }
-private:
- class MemoryHeapRegs : public GPUClientHeap {
- public:
- MemoryHeapRegs(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : GPUClientHeap(gpu, heap) { }
- sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
- virtual void revoke();
- private:
- class GPUHandle : public MemoryHeapPmem::MemoryPmem {
- public:
- GPUHandle(const sp<GPUHardware>& gpu,
- const sp<MemoryHeapPmem>& heap)
- : MemoryHeapPmem::MemoryPmem(heap),
- mGPU(gpu), mOwner(gpu->getOwner()) { }
- virtual ~GPUHandle();
- virtual sp<IMemoryHeap> getMemory(
- ssize_t* offset, size_t* size) const;
- virtual void revoke() { };
- virtual status_t onTransact(
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- private:
- void revokeNotification();
- wp<GPUHardware> mGPU;
- pid_t mOwner;
- };
- };
-};
-
-GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
- //LOGD("GPUHandle %p released, revoking GPU", this);
- revokeNotification();
-}
-void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
- sp<GPUHardware> hw(mGPU.promote());
- if (hw != 0) {
- hw->revoke(mOwner);
- }
-}
-sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
- ssize_t* offset, size_t* size) const
-{
- sp<MemoryHeapPmem> heap = getHeap();
- if (offset) *offset = 0;
- if (size) *size = heap !=0 ? heap->virtualSize() : 0;
- return heap;
-}
-status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- status_t err = BnMemory::onTransact(code, data, reply, flags);
- if (err == UNKNOWN_TRANSACTION && code == 1000) {
- int callingPid = IPCThreadState::self()->getCallingPid();
- //LOGD("pid %d voluntarily revoking gpu", callingPid);
- if (callingPid == mOwner) {
- revokeNotification();
- // we've revoked the GPU, don't do it again later when we
- // are destroyed.
- mGPU.clear();
- } else {
- LOGW("%d revoking someone else's gpu? (owner=%d)",
- callingPid, mOwner);
- }
- err = NO_ERROR;
- }
- return err;
-}
-
-// ---------------------------------------------------------------------------
-
-
-sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
- size_t offset, size_t size)
-{
- sp<GPUHandle> memory;
- sp<GPUHardware> gpu = mGPU.promote();
- if (heapID()>0 && gpu!=0) {
-#if HAVE_ANDROID_OS
- /* this is where the GPU is powered on and the registers are mapped
- * in the client */
- //LOGD("ioctl(HW3D_GRANT_GPU)");
- int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
- if (err) {
- // it can happen if the master heap has been closed already
- // in which case the GPU already is revoked (app crash for
- // instance).
- LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
- memory = new GPUHandle(gpu, this);
-#endif
- }
- return memory;
-}
-
-void GPURegisterHeap::MemoryHeapRegs::revoke()
-{
- MemoryHeapPmem::revoke();
-#if HAVE_ANDROID_OS
- if (heapID() > 0) {
- //LOGD("ioctl(HW3D_REVOKE_GPU)");
- int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
- LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
-#endif
-}
-
-/*****************************************************************************/
-
-GPUHardware::GPUHardware()
- : mOwner(NO_OWNER)
-{
-}
-
-GPUHardware::~GPUHardware()
-{
-}
-
-status_t GPUHardware::requestLocked(int pid)
-{
- const int self_pid = getpid();
- if (pid == self_pid) {
- // can't use GPU from surfaceflinger's process
- return PERMISSION_DENIED;
- }
-
- if (mOwner != pid) {
- if (mREGHeap != 0) {
- if (mOwner != NO_OWNER) {
- // someone already has the gpu.
- takeBackGPULocked();
- releaseLocked();
- }
- } else {
- // first time, initialize the stuff.
- if (mSMIHeap == 0)
- mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
- if (mEBIHeap == 0)
- mEBIHeap = new GPUAreaHeap(this,
- "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
- mREGHeap = new GPURegisterHeap(this);
- mAllocator = mEBIHeap->getAllocator();
- if (mAllocator == NULL) {
- // something went terribly wrong.
- mSMIHeap.clear();
- mEBIHeap.clear();
- mREGHeap.clear();
- return INVALID_OPERATION;
- }
- }
- Client& client = getClientLocked(pid);
- mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
- mOwner = pid;
- }
- return NO_ERROR;
-}
-
-sp<MemoryDealer> GPUHardware::request(int pid)
-{
- sp<MemoryDealer> dealer;
- Mutex::Autolock _l(mLock);
- Client* client;
- LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
- if (requestLocked(pid) == NO_ERROR) {
- dealer = mCurrentAllocator;
- LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
- }
- return dealer;
-}
-
-status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu)
-{
- if (callback == 0)
- return BAD_VALUE;
-
- sp<IMemory> gpuHandle;
- LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
- Mutex::Autolock _l(mLock);
- status_t err = requestLocked(pid);
- if (err == NO_ERROR) {
- // it's guaranteed to be there, be construction
- Client& client = mClients.editValueFor(pid);
- registerCallbackLocked(callback, client);
- gpu->count = 2;
- gpu->regions[0].region = client.smi.map();
- gpu->regions[1].region = client.ebi.map();
- gpu->regs = client.reg.map();
- gpu->regions[0].reserved = 0;
- gpu->regions[1].reserved = GPU_RESERVED_SIZE;
- if (gpu->regs != 0) {
- //LOGD("gpu core granted to pid %d, handle base=%p",
- // mOwner, gpu->regs->pointer());
- }
- mCallback = callback;
- } else {
- LOGW("couldn't grant gpu core to pid %d", pid);
- }
- return err;
-}
-
-void GPUHardware::revoke(int pid)
-{
- Mutex::Autolock _l(mLock);
- if (mOwner > 0) {
- if (pid != mOwner) {
- LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
- return;
- }
- //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
- // mOwner could be <0 if the same process acquired the GPU
- // several times without releasing it first.
- mCondition.signal();
- releaseLocked();
- }
-}
-
-status_t GPUHardware::friendlyRevoke()
-{
- Mutex::Autolock _l(mLock);
- //LOGD("friendlyRevoke owner=%d", mOwner);
- takeBackGPULocked();
- releaseLocked();
- return NO_ERROR;
-}
-
-void GPUHardware::takeBackGPULocked()
-{
- sp<IGPUCallback> callback = mCallback;
- mCallback.clear();
- if (callback != 0) {
- callback->gpuLost(); // one-way
- mCondition.waitRelative(mLock, ms2ns(250));
- }
-}
-
-void GPUHardware::releaseLocked()
-{
- //LOGD("revoking gpu from pid %d", mOwner);
- if (mOwner != NO_OWNER) {
- // this may fail because the client might have died, and have
- // been removed from the list.
- ssize_t index = mClients.indexOfKey(mOwner);
- if (index >= 0) {
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps();
- }
- mOwner = NO_OWNER;
- mCurrentAllocator.clear();
- mCallback.clear();
- }
-}
-
-GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
-{
- ssize_t index = mClients.indexOfKey(pid);
- if (index < 0) {
- Client client;
- client.pid = pid;
- client.smi.heap = mSMIHeap;
- client.ebi.heap = mEBIHeap;
- client.reg.heap = mREGHeap;
- index = mClients.add(pid, client);
- }
- Client& client(mClients.editValueAt(index));
- client.createClientHeaps();
- return client;
-}
-
-// ----------------------------------------------------------------------------
-// for debugging / testing ...
-
-sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
- Mutex::Autolock _l(mLock);
- return mAllocator;
-}
-
-void GPUHardware::unconditionalRevoke()
-{
- Mutex::Autolock _l(mLock);
- releaseLocked();
-}
-
-// ---------------------------------------------------------------------------
-
-sp<IMemory> GPUHardware::GPUArea::map() {
- sp<IMemory> memory;
- if (clientHeap != 0 && heap != 0) {
- memory = clientHeap->mapMemory(0, heap->virtualSize());
- }
- return memory;
-}
-
-void GPUHardware::Client::createClientHeaps()
-{
- if (smi.clientHeap == 0)
- smi.clientHeap = smi.heap->createClientHeap();
- if (ebi.clientHeap == 0)
- ebi.clientHeap = ebi.heap->createClientHeap();
- if (reg.clientHeap == 0)
- reg.clientHeap = reg.heap->createClientHeap();
-}
-
-void GPUHardware::Client::revokeAllHeaps()
-{
- if (smi.clientHeap != 0)
- smi.clientHeap->revoke();
- if (ebi.clientHeap != 0)
- ebi.clientHeap->revoke();
- if (reg.clientHeap != 0)
- reg.clientHeap->revoke();
-}
-
-void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client)
-{
- sp<IBinder> binder = callback->asBinder();
- if (mRegisteredClients.add(binder, client.pid) >= 0) {
- binder->linkToDeath(this);
- }
-}
-
-void GPUHardware::binderDied(const wp<IBinder>& who)
-{
- Mutex::Autolock _l(mLock);
- pid_t pid = mRegisteredClients.valueFor(who);
- if (pid != 0) {
- ssize_t index = mClients.indexOfKey(pid);
- if (index >= 0) {
- //LOGD("*** removing client at %d", index);
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps(); // not really needed in theory
- mClients.removeItemsAt(index);
- if (mClients.size() == 0) {
- //LOGD("*** was last client closing everything");
- mCallback.clear();
- mAllocator.clear();
- mCurrentAllocator.clear();
- mSMIHeap.clear();
- mREGHeap.clear();
-
- // NOTE: we cannot clear the EBI heap because surfaceflinger
- // itself may be using it, since this is where surfaces
- // are allocated. if we're in the middle of compositing
- // a surface (even if its process just died), we cannot
- // rip the heap under our feet.
-
- mOwner = NO_OWNER;
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-sp<GPUHardwareInterface> GPUFactory::getGPU()
-{
- sp<GPUHardwareInterface> gpu;
- if (access("/dev/hw3d", F_OK) == 0) {
- gpu = new GPUHardware();
- }
- return gpu;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 96395a8..6f92515 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -14,26 +14,24 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <cutils/properties.h>
+#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/Surface.h>
#include "clz.h"
#include "Layer.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
@@ -49,13 +47,12 @@
// ---------------------------------------------------------------------------
-Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i),
mSecure(false),
mFrontBufferIndex(1),
mNeedsBlending(true),
- mResizeTransactionDone(false),
- mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+ mResizeTransactionDone(false)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
@@ -63,12 +60,25 @@
Layer::~Layer()
{
- client->free(clientIndex());
- // this should always be called from the OpenGL thread
- if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ destroy();
+ // the actual buffers will be destroyed here
+}
+
+void Layer::destroy()
+{
+ for (int i=0 ; i<NUM_BUFFERS ; i++) {
+ if (mTextures[i].name != -1U) {
+ glDeleteTextures(1, &mTextures[i].name);
+ mTextures[i].name = -1U;
+ }
+ if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[i].image);
+ mTextures[i].image = EGL_NO_IMAGE_KHR;
+ }
+ mBuffers[i].free();
}
+ mSurface.clear();
}
void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
@@ -79,148 +89,193 @@
lcblk->flags |= eNoCopyBack;
}
-sp<LayerBaseClient::Surface> Layer::getSurface() const
+sp<LayerBaseClient::Surface> Layer::createSurface() const
{
return mSurface;
}
-status_t Layer::setBuffers( Client* client,
- uint32_t w, uint32_t h,
+status_t Layer::ditch()
+{
+ // the layer is not on screen anymore. free as much resources as possible
+ destroy();
+ return NO_ERROR;
+}
+
+status_t Layer::setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags)
{
PixelFormatInfo info;
status_t err = getPixelFormatInfo(format, &info);
if (err) return err;
- // TODO: if eHardware is explicitly requested, we should fail
- // on systems where we can't allocate memory that can be used with
- // DMA engines for instance.
-
- // FIXME: we always ask for hardware for now (this should come from copybit)
- flags |= ISurfaceComposer::eHardware;
+ uint32_t bufferFlags = 0;
+ if (flags & ISurfaceComposer::eSecure)
+ bufferFlags |= Buffer::SECURE;
- const uint32_t memory_flags = flags &
- (ISurfaceComposer::eGPU |
- ISurfaceComposer::eHardware |
- ISurfaceComposer::eSecure);
-
- // pixel-alignment. the final alignment may be bigger because
- // we always force a 4-byte aligned bpr.
- uint32_t alignment = 1;
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this value should come from the h/w
- alignment = 8;
- // FIXME: this is msm7201A specific, as its GPU only supports
- // BGRA_8888.
- if (format == PIXEL_FORMAT_RGBA_8888) {
- format = PIXEL_FORMAT_BGRA_8888;
+ mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
+ mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+ for (int i=0 ; i<2 ; i++) {
+ err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags);
+ if (err != NO_ERROR) {
+ return err;
}
}
-
- mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
- mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
- sp<MemoryDealer> allocators[2];
- for (int i=0 ; i<2 ; i++) {
- allocators[i] = client->createAllocator(memory_flags);
- if (allocators[i] == 0)
- return NO_MEMORY;
- mBuffers[i].init(allocators[i]);
- int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
- if (err != NO_ERROR)
- return err;
- mBuffers[i].clear(); // clear the bits for security
- mBuffers[i].getInfo(lcblk->surface + i);
- }
-
- mSurface = new Surface(clientIndex(),
- allocators[0]->getMemoryHeap(),
- allocators[1]->getMemoryHeap(),
- mIdentity);
-
+ mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
}
void Layer::reloadTexture(const Region& dirty)
{
- if (UNLIKELY(mTextureName == -1U)) {
- // create the texture name the first time
- // can't do that in the ctor, because it runs in another thread.
- mTextureName = createTexture();
+ const sp<Buffer>& buffer(frontBuffer().getBuffer());
+ if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) {
+ int index = mFrontBufferIndex;
+ if (LIKELY(!mTextures[index].dirty)) {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ } else {
+ // we need to recreate the texture
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+ // create the new texture name if needed
+ if (UNLIKELY(mTextures[index].name == -1U)) {
+ mTextures[index].name = createTexture();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ }
+
+ // free the previous image
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, mTextures[index].image);
+ mTextures[index].image = EGL_NO_IMAGE_KHR;
+ }
+
+ // construct an EGL_NATIVE_BUFFER_ANDROID
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ // create the new EGLImageKHR
+ const EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE, EGL_NONE
+ };
+ mTextures[index].image = eglCreateImageKHR(
+ dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)clientBuf, attrs);
+
+ LOGE_IF(mTextures[index].image == EGL_NO_IMAGE_KHR,
+ "eglCreateImageKHR() failed. err=0x%4x",
+ eglGetError());
+
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+ (GLeglImageOES)mTextures[index].image);
+ GLint error = glGetError();
+ if (UNLIKELY(error != GL_NO_ERROR)) {
+ // this failed, for instance, because we don't support
+ // NPOT.
+ // FIXME: do something!
+ mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+ } else {
+ // Everything went okay!
+ mTextures[index].dirty = false;
+ mTextures[index].width = clientBuf->width;
+ mTextures[index].height = clientBuf->height;
+ }
+ }
+ }
+ } else {
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_RARELY);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ if (UNLIKELY(mTextures[0].name == -1U)) {
+ mTextures[0].name = createTexture();
+ }
+ loadTexture(&mTextures[0], mTextures[0].name, dirty, t);
+ buffer->unlock();
+ }
}
- const GGLSurface& t(frontBuffer().surface());
- loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
}
void Layer::onDraw(const Region& clip) const
{
- if (UNLIKELY(mTextureName == -1LU)) {
- //LOGW("Layer %p doesn't have a texture", this);
+ const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
+ mFrontBufferIndex : 0;
+ GLuint textureName = mTextures[index].name;
+
+ if (UNLIKELY(textureName == -1LU)) {
+ LOGW("Layer %p doesn't have a texture", this);
// the texture has not been created yet, this Layer has
// in fact never been drawn into. this happens frequently with
// SurfaceView.
clearWithOpenGL(clip);
return;
}
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- const LayerBitmap& front(frontBuffer());
- const GGLSurface& t(front.surface());
-
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- const State& s(drawingState());
-
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- front.getBitmapSurface(&src);
- copybit_rect_t srect = { 0, 0, t.width, t.height };
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER,
- s.flags & ISurfaceComposer::eLayerDither ?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
-
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
- }
-
- if (!can_use_copybit || err) {
- drawWithOpenGL(clip, mTextureName, t);
- }
+ drawWithOpenGL(clip, mTextures[index]);
}
-status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+sp<SurfaceBuffer> Layer::peekBuffer(int usage)
{
- LOGD_IF(DEBUG_RESIZE,
- "reallocateBuffer (layer=%p), "
- "requested (%dx%d), "
- "index=%d, (%dx%d), (%dx%d)",
- this,
- int(w), int(h),
- int(index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ /*
+ * This is called from the client's Surface::lock(), after it locked
+ * the surface successfully. We're therefore guaranteed that the
+ * back-buffer is not in use by ourselves.
+ * Of course, we need to validate all this, which is not trivial.
+ *
+ * FIXME: A resize could happen at any time here. What to do about this?
+ * - resize() form post()
+ * - resize() from doTransaction()
+ *
+ * We'll probably need an internal lock for this.
+ *
+ *
+ * TODO: We need to make sure that post() doesn't swap
+ * the buffers under us.
+ */
- status_t err = mBuffers[index].resize(w, h);
- if (err == NO_ERROR) {
- mBuffers[index].getInfo(lcblk->surface + index);
- } else {
- LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
- index, w, h, err, strerror(err));
- // XXX: what to do, what to do? We could try to free some
- // hidden surfaces, instead of killing this one?
+ // it's okay to read swapState for the purpose of figuring out the
+ // backbuffer index, which cannot change (since the app has locked it).
+ const uint32_t state = lcblk->swapState;
+ const int32_t backBufferIndex = layer_cblk_t::backBuffer(state);
+
+ // get rid of the EGL image, since we shouldn't need it anymore
+ // (note that we're in a different thread than where it is being used)
+ if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image);
+ mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR;
}
- return err;
+
+ LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
+ sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage);
+
+ LOGD_IF(DEBUG_RESIZE,
+ "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)",
+ this, backBufferIndex,
+ layerBitmap.getWidth(),
+ layerBitmap.getHeight(),
+ layerBitmap.getBuffer()->getWidth(),
+ layerBitmap.getBuffer()->getHeight());
+
+ if (UNLIKELY(buffer == 0)) {
+ // XXX: what to do, what to do?
+ } else {
+ // texture is now dirty...
+ mTextures[backBufferIndex].dirty = true;
+ // ... so it the visible region (because we consider the surface's
+ // buffer size for visibility calculations)
+ forceVisibilityTransaction();
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ return buffer;
+}
+
+void Layer::scheduleBroadcast()
+{
+ sp<Client> ourClient(client.promote());
+ if (ourClient != 0) {
+ mFlinger->scheduleBroadcast(ourClient);
+ }
}
uint32_t Layer::doTransaction(uint32_t flags)
@@ -232,7 +287,7 @@
// that the size changed back to its previous value before the buffer
// was resized (in the eLocked case below), in which case, we still
// need to execute the code below so the clients have a chance to be
- // release. resze() deals with the fact that the size can be the same.
+ // release. resize() deals with the fact that the size can be the same.
/*
* Various states we could be in...
@@ -276,8 +331,8 @@
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// if we get there we're pretty screwed. the only reasonable
// thing to do is to pretend we should do the resize since
// backbufferChanged is set (this also will give a chance to
@@ -299,8 +354,8 @@
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
if (state & eLocked) {
// if the buffer is locked, we can't resize anything because
@@ -314,10 +369,11 @@
status_t err =
resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
if (err == NO_ERROR) {
- const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ const uint32_t mask = clientBackBufferIndex ?
+ eResizeBuffer1 : eResizeBuffer0;
android_atomic_and(~mask, &(lcblk->swapState));
// since a buffer became available, we can let the client go...
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
mResizeTransactionDone = true;
// we're being resized and there is a freeze display request,
@@ -353,14 +409,15 @@
{
/*
* handle resize (backbuffer and frontbuffer reallocation)
+ * this is called from post() or from doTransaction()
*/
const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
// if the new (transaction) size is != from the the backbuffer
// then we need to reallocate the backbuffer
- bool backbufferChanged = (clientBackBuffer.width() != width) ||
- (clientBackBuffer.height() != height);
+ bool backbufferChanged = (clientBackBuffer.getWidth() != width) ||
+ (clientBackBuffer.getHeight() != height);
LOGD_IF(!backbufferChanged,
"(%s) eResizeRequested (layer=%p), but size not changed: "
@@ -372,18 +429,28 @@
int(currentState().w), int(currentState().h),
long(lcblk->swapState),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// this can happen when changing the size back and forth quickly
status_t err = NO_ERROR;
if (backbufferChanged) {
- err = reallocateBuffer(clientBackBufferIndex, width, height);
- }
- if (UNLIKELY(err != NO_ERROR)) {
- // couldn't reallocate the surface
- android_atomic_write(eInvalidSurface, &lcblk->swapState);
- memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), requested (%dx%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, int(width), int(height), int(clientBackBufferIndex),
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
+
+ err = mBuffers[clientBackBufferIndex].setSize(width, height);
+ if (UNLIKELY(err != NO_ERROR)) {
+ // This really should never happen
+ LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+ clientBackBufferIndex, width, height, err, strerror(err));
+ // couldn't reallocate the surface
+ android_atomic_write(eInvalidSurface, &lcblk->swapState);
+ }
}
return err;
}
@@ -415,7 +482,7 @@
if (UNLIKELY(state & eInvalidSurface)) {
// if eInvalidSurface is set, this means the surface
// became invalid during a transaction (NO_MEMORY for instance)
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
return;
}
@@ -457,15 +524,21 @@
} while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
*previousSate = oldValue;
-
+
const int32_t index = (newValue & eIndex) ^ 1;
mFrontBufferIndex = index;
+ /* NOTE: it's safe to set this flag here because this is only touched
+ * from LayerBitmap::allocate(), which by construction cannot happen
+ * while we're in post().
+ */
+ lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty;
+
// ... post the new front-buffer
Region dirty(lcblk->region + index);
- dirty.andSelf(frontBuffer().bounds());
+ dirty.andSelf(frontBuffer().getBounds());
- //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+ //LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
// oldValue, newValue, mFrontBufferIndex);
//dirty.dump("dirty");
@@ -476,8 +549,8 @@
"index=%d, (%dx%d), (%dx%d)",
this, newValue,
int(1-index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// here, we just posted the surface and we have resolved
// the front/back buffer indices. The client is blocked, so
@@ -522,8 +595,13 @@
Point Layer::getPhysicalSize() const
{
- const LayerBitmap& front(frontBuffer());
- return Point(front.width(), front.height());
+ sp<const Buffer> front(frontBuffer().getBuffer());
+ Point size(front->getWidth(), front->getHeight());
+ if ((size.x | size.y) == 0) {
+ // if we don't have a buffer yet, just use the state's size.
+ size = LayerBase::getPhysicalSize();
+ }
+ return size;
}
void Layer::unlockPageFlip(
@@ -547,7 +625,7 @@
// client could be blocked, so signal them so they get a
// chance to reevaluate their condition.
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
}
}
@@ -558,9 +636,30 @@
"layer %p wasn't locked!", this);
android_atomic_and(~eBusy, &(lcblk->swapState));
}
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
}
+// ---------------------------------------------------------------------------
+
+Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner)
+ : Surface(flinger, id, owner->getIdentity(), owner)
+{
+}
+
+Layer::SurfaceLayer::~SurfaceLayer()
+{
+}
+
+sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage)
+{
+ sp<SurfaceBuffer> buffer = 0;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ buffer = owner->peekBuffer(usage);
+ }
+ return buffer;
+}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 2867f2b..add5d50 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -27,6 +27,11 @@
#include <pixelflinger/pixelflinger.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "LayerBitmap.h"
#include "LayerBase.h"
#include "Transform.h"
@@ -37,11 +42,12 @@
class Client;
class LayerBitmap;
-class MemoryDealer;
class FreezeLock;
// ---------------------------------------------------------------------------
+const int NUM_BUFFERS = 2;
+
class Layer : public LayerBaseClient
{
public:
@@ -51,16 +57,15 @@
virtual uint32_t getTypeInfo() const { return typeInfo; }
Layer(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~Layer();
inline PixelFormat pixelFormat() const {
- return frontBuffer().pixelFormat();
+ return frontBuffer().getPixelFormat();
}
- status_t setBuffers( Client* client,
- uint32_t w, uint32_t h,
+ status_t setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
virtual void onDraw(const Region& clip) const;
@@ -73,8 +78,8 @@
virtual void finishPageFlip();
virtual bool needsBlending() const { return mNeedsBlending; }
virtual bool isSecure() const { return mSecure; }
- virtual GLuint getTextureName() const { return mTextureName; }
- virtual sp<Surface> getSurface() const;
+ virtual sp<Surface> createSurface() const;
+ virtual status_t ditch();
const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
@@ -96,21 +101,37 @@
status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
- status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
+ sp<SurfaceBuffer> peekBuffer(int usage);
+ void destroy();
+ void scheduleBroadcast();
+
+ class SurfaceLayer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner);
+ ~SurfaceLayer();
+
+ private:
+ virtual sp<SurfaceBuffer> getBuffer(int usage);
+
+ sp<Layer> getOwner() const {
+ return static_cast<Layer*>(Surface::getOwner().get());
+ }
+ };
+ friend class SurfaceLayer;
+
sp<Surface> mSurface;
bool mSecure;
- LayerBitmap mBuffers[2];
+ LayerBitmap mBuffers[NUM_BUFFERS];
+ Texture mTextures[NUM_BUFFERS];
int32_t mFrontBufferIndex;
bool mNeedsBlending;
bool mResizeTransactionDone;
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
-
- GLuint mTextureName;
- GLuint mTextureWidth;
- GLuint mTextureHeight;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 0cf53f7..419574c 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -53,19 +53,13 @@
// ---------------------------------------------------------------------------
-Vector<GLuint> LayerBase::deletedTextures;
-
-int32_t LayerBase::sIdentity = 0;
-
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
mFlinger(flinger),
mTransformed(false),
mOrientation(0),
- mCanUseCopyBit(false),
mTransactionFlags(0),
mPremultipliedAlpha(true),
- mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
mInvalidate(0)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
@@ -265,43 +259,6 @@
mTransformed = transformed;
mLeft = tr.tx();
mTop = tr.ty();
-
- // see if we can/should use 2D h/w with the new configuration
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
- const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
- mCanUseCopyBit = true;
- if ((mOrientation < 0) && (step > 1)) {
- // arbitrary orientations not supported
- mCanUseCopyBit = false;
- } else if ((mOrientation > 0) && (step > 90)) {
- // 90 deg rotations not supported
- mCanUseCopyBit = false;
- } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
- // arbitrary scaling not supported
- mCanUseCopyBit = false;
- }
-#if HONOR_PREMULTIPLIED_ALPHA
- else if (needsBlending() && mPremultipliedAlpha) {
- // pre-multiplied alpha not supported
- mCanUseCopyBit = false;
- }
-#endif
- else {
- // here, we determined we can use copybit
- if (tr.getType() & SkMatrix::kScale_Mask) {
- // and we have scaling
- if (!transparentRegionScreen.isRect()) {
- // we punt because blending is cheap (h/w) and the region is
- // complex, which may causes artifacts when copying
- // scaled content
- transparentRegionScreen.clear();
- }
- }
- }
- }
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
@@ -329,8 +286,9 @@
void LayerBase::drawRegion(const Region& reg) const
{
- Region::iterator iterator(reg);
- if (iterator) {
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ if (it != end) {
Rect r;
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const int32_t fbWidth = hw.getWidth();
@@ -338,7 +296,8 @@
const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
{ fbWidth, fbHeight }, { 0, fbHeight } };
glVertexPointer(2, GL_SHORT, 0, vertices);
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -403,12 +362,14 @@
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
- Rect r;
- Region::iterator iterator(clip);
- if (iterator) {
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_SCISSOR_TEST);
glVertexPointer(2, GL_FIXED, 0, mVertices);
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -416,15 +377,17 @@
}
}
-void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t, int transform) const
+void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
-
+
// bind our texture
- validateTexture(textureName);
+ validateTexture(texture.name);
+ uint32_t width = texture.width;
+ uint32_t height = texture.height;
+
glEnable(GL_TEXTURE_2D);
// Dithering...
@@ -472,8 +435,9 @@
|| !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
{
//StopWatch watch("GL transformed");
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
// always use high-quality filtering with fast configurations
bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
@@ -490,21 +454,24 @@
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
- if (transform == HAL_TRANSFORM_ROT_90) {
+ // the texture's source is rotated
+ if (texture.transform == HAL_TRANSFORM_ROT_90) {
+ // TODO: handle the other orientations
glTranslatef(0, 1, 0);
glRotatef(-90, 0, 0, 1);
}
- if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+ if (!(mFlags & (DisplayHardware::NPOT_EXTENSION |
+ DisplayHardware::DIRECT_TEXTURE))) {
// find the smallest power-of-two that will accommodate our surface
- GLuint tw = 1 << (31 - clz(t.width));
- GLuint th = 1 << (31 - clz(t.height));
- if (tw < t.width) tw <<= 1;
- if (th < t.height) th <<= 1;
+ GLuint tw = 1 << (31 - clz(width));
+ GLuint th = 1 << (31 - clz(height));
+ if (tw < width) tw <<= 1;
+ if (th < height) th <<= 1;
// this divide should be relatively fast because it's
// a power-of-two (optimized path in libgcc)
- GLfloat ws = GLfloat(t.width) /tw;
- GLfloat hs = GLfloat(t.height)/th;
+ GLfloat ws = GLfloat(width) /tw;
+ GLfloat hs = GLfloat(height)/th;
glScalef(ws, hs, 1.0f);
}
@@ -512,8 +479,8 @@
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
- Rect r;
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -526,18 +493,19 @@
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- Rect r;
- GLint crop[4] = { 0, t.height, t.width, -t.height };
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
+ GLint crop[4] = { 0, height, width, -height };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
int x = tx();
int y = ty();
- y = fbHeight - (y + t.height);
- while (iterator.iterate(&r)) {
+ y = fbHeight - (y + height);
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, t.width, t.height);
+ glDrawTexiOES(x, y, 0, width, height);
}
}
}
@@ -550,13 +518,16 @@
// this is currently done in loadTexture() below
}
-void LayerBase::loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const
+void LayerBase::loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const
{
// TODO: defer the actual texture reload until LayerBase::validateTexture
// is called.
+ texture->name = textureName;
+ GLuint& textureWidth(texture->width);
+ GLuint& textureHeight(texture->height);
+
uint32_t flags = mFlags;
glBindTexture(GL_TEXTURE_2D, textureName);
@@ -565,8 +536,7 @@
/*
* In OpenGL ES we can't specify a stride with glTexImage2D (however,
- * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
- * stride).
+ * GL_UNPACK_ALIGNMENT is a limited form of stride).
* So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
* need to do something reasonable (here creating a bigger texture).
*
@@ -579,9 +549,11 @@
*
* This should never be a problem with POT textures
*/
-
- tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
-
+
+ int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
+ unpack = 1 << ((unpack > 3) ? 3 : unpack);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
+
/*
* round to POT if needed
*/
@@ -594,119 +566,98 @@
texture_h = 1 << (31 - clz(t.height));
if (texture_w < t.width) texture_w <<= 1;
if (texture_h < t.height) texture_h <<= 1;
- if (texture_w != tw || texture_h != th) {
- // we can't use DIRECT_TEXTURE since we changed the size
- // of the texture
- flags &= ~DisplayHardware::DIRECT_TEXTURE;
- }
}
-
- if (flags & DisplayHardware::DIRECT_TEXTURE) {
- // here we're guaranteed that texture_{w|h} == t{w|h}
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGB, tw, th, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
- // TODO: add GL_BGRA extension
- } else {
- // oops, we don't handle this format, try the regular path
- goto regular;
- }
- textureWidth = tw;
- textureHeight = th;
- } else {
+
regular:
- Rect bounds(dirty.bounds());
- GLvoid* data = 0;
- if (texture_w!=textureWidth || texture_h!=textureHeight) {
- // texture size changed, we need to create a new one
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture_w!=textureWidth || texture_h!=textureHeight) {
+ // texture size changed, we need to create a new one
- if (!textureWidth || !textureHeight) {
- // this is the first time, load the whole texture
- if (texture_w==tw && texture_h==th) {
- // we can do it one pass
- data = t.data;
- } else {
- // we have to create the texture first because it
- // doesn't match the size of the buffer
- bounds.set(Rect(tw, th));
- }
- }
-
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGB, texture_w, texture_h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, data);
- } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
- t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
- // just show the Y plane of YUV buffers
+ if (!textureWidth || !textureHeight) {
+ // this is the first time, load the whole texture
+ if (texture_w==tw && texture_h==th) {
+ // we can do it one pass
data = t.data;
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_LUMINANCE, texture_w, texture_h, 0,
- GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
} else {
- // oops, we don't handle this format!
- LOGE("layer %p, texture=%d, using format %d, which is not "
- "supported by the GL", this, textureName, t.format);
- textureName = -1;
+ // we have to create the texture first because it
+ // doesn't match the size of the buffer
+ bounds.set(Rect(tw, th));
}
- textureWidth = texture_w;
- textureHeight = texture_h;
}
- if (!data && textureName>=0) {
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
- t.data + bounds.top*t.width*2);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
- t.data + bounds.top*t.width*2);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGBA, GL_UNSIGNED_BYTE,
- t.data + bounds.top*t.width*4);
- }
+
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture_w, texture_h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, texture_w, texture_h, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ } else {
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, textureName, t.format);
+ textureName = -1;
+ }
+ textureWidth = texture_w;
+ textureHeight = texture_h;
+ }
+ if (!data && textureName>=0) {
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride*4);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride);
}
}
}
-bool LayerBase::canUseCopybit() const
-{
- return mCanUseCopyBit;
-}
-
// ---------------------------------------------------------------------------
-LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i)
- : LayerBase(flinger, display), client(c),
- lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
- mIndex(i)
-{
- if (client) {
- client->bindLayer(this, i);
+int32_t LayerBaseClient::sIdentity = 0;
+LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
+ const sp<Client>& client, int32_t i)
+ : LayerBase(flinger, display), client(client),
+ lcblk( client!=0 ? &(client->ctrlblk->layers[i]) : 0 ),
+ mIndex(i),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
+{
+}
+
+void LayerBaseClient::onFirstRef()
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
+ client->bindLayer(this, mIndex);
// Initialize this layer's control block
memset(this->lcblk, 0, sizeof(layer_cblk_t));
this->lcblk->identity = mIdentity;
@@ -717,23 +668,121 @@
LayerBaseClient::~LayerBaseClient()
{
- if (client) {
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
client->free(mIndex);
}
}
-int32_t LayerBaseClient::serverIndex() const {
- if (client) {
+int32_t LayerBaseClient::serverIndex() const
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
return (client->cid<<16)|mIndex;
}
return 0xFFFF0000 | mIndex;
}
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
{
- return new Surface(clientIndex(), mIdentity);
+ sp<Surface> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = createSurface();
+ mClientSurface = s;
+ }
+ return s;
}
+sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
+{
+ return new Surface(mFlinger, clientIndex(), mIdentity,
+ const_cast<LayerBaseClient *>(this));
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::Surface::Surface(
+ const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner)
+ : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner)
+{
+}
+
+
+LayerBaseClient::Surface::~Surface()
+{
+ /*
+ * This is a good place to clean-up all client resources
+ */
+
+ // destroy client resources
+ sp<LayerBaseClient> layer = getOwner();
+ if (layer != 0) {
+ mFlinger->destroySurface(layer);
+ }
+}
+
+sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
+ sp<LayerBaseClient> owner(mOwner.promote());
+ 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)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ return BnSurface::onTransact(code, data, reply, flags);
+}
+
+sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int)
+{
+ return NULL;
+}
+
+status_t LayerBaseClient::Surface::registerBuffers(
+ const ISurface::BufferHeap& buffers)
+{
+ return INVALID_OPERATION;
+}
+
+void LayerBaseClient::Surface::postBuffer(ssize_t offset)
+{
+}
+
+void LayerBaseClient::Surface::unregisterBuffers()
+{
+}
+
+sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
+ uint32_t w, uint32_t h, int32_t format)
+{
+ return NULL;
+};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index a020f44..65bf55b 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -20,8 +20,13 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include <private/ui/LayerState.h>
+#include <utils/RefBase.h>
+
#include <ui/Region.h>
#include <ui/Overlay.h>
@@ -37,10 +42,12 @@
class DisplayHardware;
class GraphicPlane;
class Client;
+class SurfaceBuffer;
+class Buffer;
// ---------------------------------------------------------------------------
-class LayerBase
+class LayerBase : public RefBase
{
// poor man's dynamic_cast below
template<typename T>
@@ -69,10 +76,7 @@
}
- static Vector<GLuint> deletedTextures;
-
LayerBase(SurfaceFlinger* flinger, DisplayID display);
- virtual ~LayerBase();
DisplayID dpy;
mutable bool contentDirty;
@@ -201,21 +205,29 @@
/**
* isSecure - true if this surface is secure, that is if it prevents
- * screenshots or vns servers.
+ * screenshots or VNC servers.
*/
virtual bool isSecure() const { return false; }
- enum { // flags for doTransaction()
- eVisibleRegion = 0x00000002,
- eRestartTransaction = 0x00000008
- };
+ /** signal this layer that it's not needed any longer. called from the
+ * main thread */
+ virtual status_t ditch() { return NO_ERROR; }
+
+
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ eRestartTransaction = 0x00000008
+ };
inline const State& drawingState() const { return mDrawingState; }
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
- static int compareCurrentStateZ(LayerBase*const* layerA, LayerBase*const* layerB) {
+ static int compareCurrentStateZ(
+ sp<LayerBase> const * layerA,
+ sp<LayerBase> const * layerB) {
return layerA[0]->currentState().z - layerB[0]->currentState().z;
}
@@ -229,20 +241,24 @@
GLuint createTexture() const;
- void drawWithOpenGL(const Region& clip,
- GLint textureName,
- const GGLSurface& surface,
- int transform = 0) const;
-
- void clearWithOpenGL(const Region& clip) const;
-
- void loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const;
-
- bool canUseCopybit() const;
+ struct Texture {
+ Texture() : name(-1U), width(0), height(0),
+ image(EGL_NO_IMAGE_KHR), transform(0), dirty(true) { }
+ GLuint name;
+ GLuint width;
+ GLuint height;
+ EGLImageKHR image;
+ uint32_t transform;
+ bool dirty;
+ };
- SurfaceFlinger* mFlinger;
+ void clearWithOpenGL(const Region& clip) const;
+ void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ void loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const;
+
+
+ sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
// cached during validateVisibility()
@@ -250,7 +266,6 @@
int32_t mOrientation;
GLfixed mVertices[4][2];
Rect mTransformedBounds;
- bool mCanUseCopyBit;
int mLeft;
int mTop;
@@ -262,16 +277,16 @@
// don't change, don't need a lock
bool mPremultipliedAlpha;
- // only read
- const uint32_t mIdentity;
-
// atomic
volatile int32_t mInvalidate;
+protected:
+ virtual ~LayerBase();
+
private:
- void validateTexture(GLint textureName) const;
- static int32_t sIdentity;
+ LayerBase(const LayerBase& rhs);
+ void validateTexture(GLint textureName) const;
};
@@ -287,66 +302,63 @@
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBaseClient();
+ virtual void onFirstRef();
-
- Client* const client;
+ wp<Client> client;
layer_cblk_t* const lcblk;
+ inline uint32_t getIdentity() const { return mIdentity; }
inline int32_t clientIndex() const { return mIndex; }
int32_t serverIndex() const;
- virtual sp<Surface> getSurface() const;
- uint32_t getIdentity() const { return mIdentity; }
+ sp<Surface> getSurface();
+ virtual sp<Surface> createSurface() const;
+
class Surface : public BnSurface
{
public:
- Surface(SurfaceID id, int identity) {
- mParams.token = id;
- mParams.identity = identity;
- }
- Surface(SurfaceID id,
- const sp<IMemoryHeap>& heap0,
- const sp<IMemoryHeap>& heap1,
- int identity)
- {
- mParams.token = id;
- mParams.identity = identity;
- mParams.heap[0] = heap0;
- mParams.heap[1] = heap1;
- }
- virtual ~Surface() {
- // TODO: We now have a point here were we can clean-up the
- // client's mess.
- // This is also where surface id should be recycled.
- //LOGD("Surface %d, heaps={%p, %p} destroyed",
- // mId, mHeap[0].get(), mHeap[1].get());
- }
-
+
virtual void getSurfaceData(
- ISurfaceFlingerClient::surface_data_t* params) const {
- *params = mParams;
- }
+ ISurfaceFlingerClient::surface_data_t* params) const;
- virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
- { return INVALID_OPERATION; }
- virtual void postBuffer(ssize_t offset) { }
- virtual void unregisterBuffers() { };
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format) {
- return NULL;
- };
+ protected:
+ Surface(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner);
+ virtual ~Surface();
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ sp<LayerBaseClient> getOwner() const;
private:
- ISurfaceFlingerClient::surface_data_t mParams;
+ virtual sp<SurfaceBuffer> getBuffer(int usage);
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
+ int32_t format);
+
+ protected:
+ friend class LayerBaseClient;
+ sp<SurfaceFlinger> mFlinger;
+ int32_t mToken;
+ int32_t mIdentity;
+ wp<LayerBaseClient> mOwner;
};
-private:
- int32_t mIndex;
+ friend class Surface;
+private:
+ int32_t mIndex;
+ mutable Mutex mLock;
+ mutable wp<Surface> mClientSurface;
+ // only read
+ const uint32_t mIdentity;
+ static int32_t sIdentity;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 397ddc8..5e74451 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -14,173 +14,186 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/memory.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/IMemory.h>
+
#include <ui/PixelFormat.h>
+#include <ui/Surface.h>
#include <pixelflinger/pixelflinger.h>
+#include "BufferAllocator.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
namespace android {
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
+
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage, uint32_t flags)
+ : SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags),
+ mVStride(0)
+{
+ this->format = format;
+ if (w>0 && h>0) {
+ mInitCheck = initSize(w, h, reqUsage);
+ }
+}
+
+Buffer::~Buffer()
+{
+ if (handle) {
+ BufferAllocator& allocator(BufferAllocator::get());
+ allocator.free(handle);
+ }
+}
+
+status_t Buffer::initCheck() const {
+ return mInitCheck;
+}
+
+android_native_buffer_t* Buffer::getNativeBuffer() const
+{
+ return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
+}
+
+status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
+{
+ status_t err = NO_ERROR;
+
+ BufferAllocator& allocator = BufferAllocator::get();
+
+ /*
+ * buffers used for software rendering, but h/w composition
+ * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
+ *
+ * buffers used for h/w rendering and h/w composition
+ * are allocated with HW_RENDER | HW_TEXTURE
+ *
+ * buffers used with h/w rendering and either NPOT or no egl_image_ext
+ * are allocated with SW_READ_RARELY | HW_RENDER
+ *
+ */
+
+ if (mFlags & Buffer::SECURE) {
+ // secure buffer, don't store it into the GPU
+ usage = BufferAllocator::USAGE_SW_READ_OFTEN |
+ BufferAllocator::USAGE_SW_WRITE_OFTEN;
+ } else {
+ // it's allowed to modify the usage flags here, but generally
+ // the requested flags should be honored.
+ usage = reqUsage | BufferAllocator::USAGE_HW_TEXTURE;
+ }
+
+ err = allocator.alloc(w, h, format, usage, &handle, &stride);
+
+ if (err == NO_ERROR) {
+ if (err == NO_ERROR) {
+ width = w;
+ height = h;
+ mVStride = 0;
+ }
+ }
+
+ return err;
+}
+
+status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
+{
+ void* vaddr;
+ status_t res = SurfaceBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->vstride = mVStride;
+ sur->data = static_cast<GGLubyte*>(vaddr);
+ }
+ return res;
+}
+
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
LayerBitmap::LayerBitmap()
- : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+ : mInfo(0), mWidth(0), mHeight(0)
{
- memset(&mSurface, 0, sizeof(mSurface));
}
LayerBitmap::~LayerBitmap()
{
- mSurface.data = 0;
}
-status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
+status_t LayerBitmap::init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
{
- if (mAllocator != NULL)
+ if (info == NULL)
return BAD_VALUE;
- mAllocator = allocator;
+
+ mFormat = format;
+ mFlags = flags;
+ mWidth = w;
+ mHeight = h;
+
+ mInfo = info;
+ memset(info, 0, sizeof(surface_info_t));
+ info->flags = surface_info_t::eNeedNewBuffer;
+
+ // init the buffer, but don't trigger an allocation
+ mBuffer = new Buffer(0, 0, format, flags);
return NO_ERROR;
}
-status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags)
+status_t LayerBitmap::setSize(uint32_t w, uint32_t h)
{
- const sp<MemoryDealer>& allocator(mAllocator);
- if (allocator == NULL)
- return NO_INIT;
-
- if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
- format == mSurface.format))
- { // same format and size, do nothing.
- return NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ if ((w != mWidth) || (h != mHeight)) {
+ mWidth = w;
+ mHeight = h;
+ // this will signal the client that it needs to asks us for a new buffer
+ mInfo->flags = surface_info_t::eNeedNewBuffer;
}
+ return NO_ERROR;
+}
- PixelFormatInfo info;
- getPixelFormatInfo(format, &info);
-
- uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
- const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
- const uint32_t Bpp = info.bytesPerPixel;
- uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
- stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
- size_t size = info.getScanlineSize(stride) * h;
- if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
- size_t pagesize = getpagesize();
- size = (size + (pagesize-1)) & ~(pagesize-1);
- }
-
- /* FIXME: we should be able to have a h/v stride because the user of the
- * surface might have stride limitation (for instance h/w codecs often do)
- */
- int32_t vstride = 0;
-
- mAlignment = alignment;
- mAllocFlags = allocFlags;
- mOffset = 0;
- if (mSize != size) {
- // would be nice to have a reallocate() api
- mBitsMemory.clear(); // free-memory
- mBitsMemory = allocator->allocate(size, allocFlags);
- mSize = size;
+sp<Buffer> LayerBitmap::allocate(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mLock);
+ surface_info_t* info = mInfo;
+ mBuffer.clear(); // free buffer before allocating a new one
+ sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, reqUsage, mFlags);
+ status_t err = buffer->initCheck();
+ if (LIKELY(err == NO_ERROR)) {
+ info->flags = surface_info_t::eBufferDirty;
+ info->status = NO_ERROR;
} else {
- // don't erase memory if we didn't have to reallocate
- flags &= ~SECURE_BITS;
- }
- if (mBitsMemory != 0) {
- mOffset = mBitsMemory->offset();
- mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
- mSurface.version = sizeof(GGLSurface);
- mSurface.width = w;
- mSurface.height = h;
- mSurface.stride = stride;
- mSurface.vstride = vstride;
- mSurface.format = format;
- if (flags & SECURE_BITS)
- clear();
- }
-
- if (mBitsMemory==0 || mSurface.data==0) {
- LOGE("not enough memory for layer bitmap "
- "size=%u (w=%d, h=%d, stride=%d, format=%d)",
- size, int(w), int(h), int(stride), int(format));
- allocator->dump("LayerBitmap");
- mSurface.data = 0;
- mSize = -1U;
- return NO_MEMORY;
- }
- return NO_ERROR;
-}
-
-void LayerBitmap::clear()
-{
- // NOTE: this memset should not be necessary, at least for
- // opaque surface. However, for security reasons it's better to keep it
- // (in the case of pmem, it's possible that the memory contains old
- // data)
- if (mSurface.data) {
- memset(mSurface.data, 0, mSize);
- //if (bytesPerPixel(mSurface.format) == 4) {
- // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
- //} else {
- // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
- //}
- }
-}
-
-status_t LayerBitmap::getInfo(surface_info_t* info) const
-{
- if (mSurface.data == 0) {
memset(info, 0, sizeof(surface_info_t));
- info->bits_offset = NO_MEMORY;
- return NO_MEMORY;
+ info->status = NO_MEMORY;
}
- info->w = uint16_t(width());
- info->h = uint16_t(height());
- info->stride= uint16_t(stride());
- info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat()));
- info->format= uint8_t(pixelFormat());
- info->flags = surface_info_t::eBufferDirty;
- info->bits_offset = ssize_t(mOffset);
+ mBuffer = buffer;
+ return buffer;
+}
+
+status_t LayerBitmap::free()
+{
+ mBuffer.clear();
+ mWidth = 0;
+ mHeight = 0;
return NO_ERROR;
}
-status_t LayerBitmap::resize(uint32_t w, uint32_t h)
-{
- int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
- return err;
-}
-
-size_t LayerBitmap::size() const
-{
- return mSize;
-}
-
-void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
-{
- const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
- void* sbase = mh->base();
- const GGLSurface& t(surface());
- img->w = t.stride ?: t.width;
- img->h = t.vstride ?: t.height;
- img->format = t.format;
- img->offset = intptr_t(t.data) - intptr_t(sbase);
- img->base = sbase;
- img->fd = mh->heapID();
-}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 9ad64c4..87e8f42 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -20,63 +20,113 @@
#include <stdint.h>
#include <sys/types.h>
+#include <hardware/gralloc.h>
+
#include <utils/Atomic.h>
+
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
+#include <ui/Surface.h>
+
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/SharedState.h>
+#include <private/ui/SurfaceBuffer.h>
+
class copybit_image_t;
+struct android_native_buffer_t;
namespace android {
// ---------------------------------------------------------------------------
-
class IMemory;
-class MemoryDealer;
class LayerBitmap;
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer
+// ===========================================================================
+
+class NativeBuffer;
+
+class Buffer : public SurfaceBuffer
+{
+public:
+ enum {
+ DONT_CLEAR = 0x00000001,
+ SECURE = 0x00000004
+ };
+
+ // creates w * h buffer
+ Buffer(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage, uint32_t flags = 0);
+
+ // return status
+ status_t initCheck() const;
+
+ uint32_t getWidth() const { return width; }
+ uint32_t getHeight() const { return height; }
+ uint32_t getStride() const { return stride; }
+ uint32_t getUsage() const { return usage; }
+ PixelFormat getPixelFormat() const { return format; }
+ Rect getBounds() const { return Rect(width, height); }
+
+ status_t lock(GGLSurface* surface, uint32_t usage);
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+private:
+ friend class LightRefBase<Buffer>;
+ Buffer(const Buffer& rhs);
+ virtual ~Buffer();
+ Buffer& operator = (const Buffer& rhs);
+ const Buffer& operator = (const Buffer& rhs) const;
+
+ status_t initSize(uint32_t w, uint32_t h, uint32_t reqUsage);
+
+ ssize_t mInitCheck;
+ uint32_t mFlags;
+ uint32_t mVStride;
+};
+
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
class LayerBitmap
{
public:
-
enum {
- // erase memory to ensure security when necessary
- SECURE_BITS = 0x00000001
+ DONT_CLEAR = Buffer::DONT_CLEAR,
+ SECURE = Buffer::SECURE
};
+ LayerBitmap();
+ ~LayerBitmap();
- LayerBitmap();
- ~LayerBitmap();
- status_t init(const sp<MemoryDealer>& allocator);
+ status_t init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
- status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags = 0);
- void clear();
+ status_t setSize(uint32_t w, uint32_t h);
- status_t getInfo(surface_info_t* info) const;
- status_t resize(uint32_t w, uint32_t h);
-
- const GGLSurface& surface() const { return mSurface; }
- Rect bounds() const { return Rect(width(), height()); }
- uint32_t width() const { return surface().width; }
- uint32_t height() const { return surface().height; }
- uint32_t stride() const { return surface().stride; }
- PixelFormat pixelFormat() const { return surface().format; }
- void* serverBits() const { return surface().data; }
- size_t size() const;
- const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
- void getBitmapSurface(copybit_image_t* img) const;
-
+ sp<Buffer> allocate(uint32_t reqUsage);
+ status_t free();
+
+ sp<const Buffer> getBuffer() const { return mBuffer; }
+ sp<Buffer> getBuffer() { return mBuffer; }
+
+ uint32_t getWidth() const { return mWidth; }
+ uint32_t getHeight() const { return mHeight; }
+ PixelFormat getPixelFormat() const { return mBuffer->getPixelFormat(); }
+ Rect getBounds() const { return mBuffer->getBounds(); }
+
private:
- sp<MemoryDealer> mAllocator;
- sp<IMemory> mBitsMemory;
- uint32_t mAllocFlags;
- ssize_t mOffset;
- GGLSurface mSurface;
- size_t mSize;
- uint32_t mAlignment;
+ surface_info_t* mInfo;
+ sp<Buffer> mBuffer;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ // protects setSize() and allocate()
+ mutable Mutex mLock;
};
}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index d3e456f..00abd5a 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -40,7 +38,7 @@
// ---------------------------------------------------------------------------
LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
{
@@ -49,8 +47,7 @@
LayerBlur::~LayerBlur()
{
if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ glDeleteTextures(1, &mTextureName);
}
}
@@ -139,8 +136,9 @@
glGenTextures(1, &mTextureName);
}
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
@@ -201,27 +199,25 @@
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- // NOTE: this is marginally faster with the software gl, because
- // glReadPixels() reads the fb bottom-to-top, however we'll
- // skip all the jaccobian computations.
- Rect r;
- GLint crop[4] = { 0, 0, w, h };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- y = fbHeight - (y + h);
- while (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, w, h);
- }
+ // NOTE: this is marginally faster with the software gl, because
+ // glReadPixels() reads the fb bottom-to-top, however we'll
+ // skip all the jaccobian computations.
+ Rect r;
+ GLint crop[4] = { 0, 0, w, h };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ y = fbHeight - (y + h);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, w, h);
}
}
}
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 24b1156..0c3e6eb 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -39,7 +39,7 @@
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBlur();
virtual void onDraw(const Region& clip) const;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 00fab70..bd6d472f 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
@@ -25,17 +23,17 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <hardware/copybit.h>
+
+#include "BufferAllocator.h"
#include "LayerBuffer.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "gralloc_priv.h" // needed for msm / copybit
namespace android {
@@ -47,7 +45,7 @@
// ---------------------------------------------------------------------------
LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i),
mNeedsBlending(false)
{
@@ -55,30 +53,24 @@
LayerBuffer::~LayerBuffer()
{
- sp<SurfaceBuffer> s(getClientSurface());
- if (s != 0) {
- s->disown();
- mClientSurface.clear();
- }
}
-sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+void LayerBuffer::onFirstRef()
{
- Mutex::Autolock _l(mLock);
- return mClientSurface.promote();
+ LayerBaseClient::onFirstRef();
+ mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
+ const_cast<LayerBuffer *>(this));
}
-sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
{
- sp<SurfaceBuffer> s;
- Mutex::Autolock _l(mLock);
- s = mClientSurface.promote();
- if (s == 0) {
- s = new SurfaceBuffer(clientIndex(),
- const_cast<LayerBuffer *>(this));
- mClientSurface = s;
- }
- return s;
+ return mSurface;
+}
+
+status_t LayerBuffer::ditch()
+{
+ mSurface.clear();
+ return NO_ERROR;
}
bool LayerBuffer::needsBlending() const {
@@ -192,82 +184,49 @@
// LayerBuffer::SurfaceBuffer
// ============================================================================
-LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
-: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner)
+ : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
{
}
LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
{
unregisterBuffers();
- mOwner = 0;
}
-status_t LayerBuffer::SurfaceBuffer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(
+ const ISurface::BufferHeap& buffers)
{
- switch (code) {
- case REGISTER_BUFFERS:
- case UNREGISTER_BUFFERS:
- case CREATE_OVERLAY:
- {
- // codes that require permission check
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int self_pid = getpid();
- if (LIKELY(pid != self_pid)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- const int uid = ipc->getCallingUid();
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- }
- }
- return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
-}
-
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
-{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
return owner->registerBuffers(buffers);
return NO_INIT;
}
void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->postBuffer(offset);
}
void LayerBuffer::SurfaceBuffer::unregisterBuffers()
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->unregisterBuffers();
}
sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
uint32_t w, uint32_t h, int32_t format) {
sp<OverlayRef> result;
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
result = owner->createOverlay(w, h, format);
return result;
}
-void LayerBuffer::SurfaceBuffer::disown()
-{
- Mutex::Autolock _l(mLock);
- mOwner = 0;
-}
-
// ============================================================================
// LayerBuffer::Buffer
// ============================================================================
@@ -276,20 +235,30 @@
: mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
+
src.crop.l = 0;
src.crop.t = 0;
src.crop.r = buffers.w;
src.crop.b = buffers.h;
- src.img.w = buffers.hor_stride ?: buffers.w;
- src.img.h = buffers.ver_stride ?: buffers.h;
- src.img.format = buffers.format;
- src.img.offset = offset;
- src.img.base = buffers.heap->base();
- src.img.fd = buffers.heap->heapID();
+
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
+ src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
+
+ // FIXME: gross hack, we should never access private_handle_t from here,
+ // but this is needed by msm drivers
+ private_handle_t* hnd = new private_handle_t(
+ buffers.heap->heapID(), buffers.heap->getSize(), 0);
+ hnd->offset = offset;
+ src.img.handle = hnd;
}
LayerBuffer::Buffer::~Buffer()
{
+ NativeBuffer& src(mNativeBuffer);
+ if (src.img.handle)
+ delete (private_handle_t*)src.img.handle;
}
// ============================================================================
@@ -323,8 +292,7 @@
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
const ISurface::BufferHeap& buffers)
- : Source(layer), mStatus(NO_ERROR),
- mBufferSize(0), mTextureName(-1U)
+ : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
{
if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
@@ -363,13 +331,21 @@
mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
mLayer.forceVisibilityTransaction();
-
+
+ hw_module_t const* module;
+ mBlitEngine = NULL;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
}
LayerBuffer::BufferSource::~BufferSource()
{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
+ if (mTexture.name != -1U) {
+ glDeleteTextures(1, &mTexture.name);
+ }
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
}
}
@@ -427,19 +403,19 @@
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
- sp<Buffer> buffer(getBuffer());
- if (UNLIKELY(buffer == 0)) {
+ sp<Buffer> ourBuffer(getBuffer());
+ if (UNLIKELY(ourBuffer == 0)) {
// nothing to do, we don't have a buffer
mLayer.clearWithOpenGL(clip);
return;
}
status_t err = NO_ERROR;
- NativeBuffer src(buffer->getBuffer());
+ NativeBuffer src(ourBuffer->getBuffer());
const Rect& transformedBounds = mLayer.getTransformedBounds();
- const int can_use_copybit = mLayer.canUseCopybit();
+ copybit_device_t* copybit = mBlitEngine;
- if (can_use_copybit) {
+ if (copybit) {
const int src_width = src.crop.r - src.crop.l;
const int src_height = src.crop.b - src.crop.t;
int W = transformedBounds.width();
@@ -448,89 +424,110 @@
int t(W); W=H; H=t;
}
- /* With LayerBuffer, it is likely that we'll have to rescale the
- * surface, because this is often used for video playback or
- * camera-preview. Since we want these operation as fast as possible
- * we make sure we can use the 2D H/W even if it doesn't support
- * the requested scale factor, in which case we perform the scaling
- * in several passes. */
+#ifdef EGL_ANDROID_get_render_buffer
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLSurface draw = eglGetCurrentSurface(EGL_DRAW);
+ EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
+ android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
+ if (nb == 0) {
+ err = BAD_VALUE;
+ } else {
+ copybit_image_t dst;
+ dst.w = nb->width;
+ dst.h = nb->height;
+ dst.format = nb->format;
+ dst.base = NULL; // unused by copybit on msm7k
+ dst.handle = (native_handle_t *)nb->handle;
- copybit_device_t* copybit = mLayer.mFlinger->getBlitEngine();
- const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
- const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+ /* With LayerBuffer, it is likely that we'll have to rescale the
+ * surface, because this is often used for video playback or
+ * camera-preview. Since we want these operation as fast as possible
+ * we make sure we can use the 2D H/W even if it doesn't support
+ * the requested scale factor, in which case we perform the scaling
+ * in several passes. */
- float xscale = 1.0f;
- if (src_width > W*min) xscale = 1.0f / min;
- else if (src_width*mag < W) xscale = mag;
+ const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
- float yscale = 1.0f;
- if (src_height > H*min) yscale = 1.0f / min;
- else if (src_height*mag < H) yscale = mag;
+ float xscale = 1.0f;
+ if (src_width > W*min) xscale = 1.0f / min;
+ else if (src_width*mag < W) xscale = mag;
- if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
- if (UNLIKELY(mTemporaryDealer == 0)) {
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- mTempBitmap.init(mTemporaryDealer);
+ float yscale = 1.0f;
+ if (src_height > H*min) yscale = 1.0f / min;
+ else if (src_height*mag < H) yscale = mag;
+
+ if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+ const int tmp_w = floorf(src_width * xscale);
+ const int tmp_h = floorf(src_height * yscale);
+
+ if (mTempBitmap==0 ||
+ mTempBitmap->getWidth() < tmp_w ||
+ mTempBitmap->getHeight() < tmp_h) {
+ mTempBitmap.clear();
+ mTempBitmap = new android::Buffer(
+ tmp_w, tmp_h, src.img.format,
+ BufferAllocator::USAGE_HW_2D);
+ err = mTempBitmap->initCheck();
+ }
+
+ if (LIKELY(err == NO_ERROR)) {
+ NativeBuffer tmp;
+ tmp.img.w = tmp_w;
+ tmp.img.h = tmp_h;
+ tmp.img.format = src.img.format;
+ tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
+ tmp.crop.l = 0;
+ tmp.crop.t = 0;
+ tmp.crop.r = tmp.img.w;
+ tmp.crop.b = tmp.img.h;
+
+ region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+ src = tmp;
+ }
}
- const int tmp_w = floorf(src_width * xscale);
- const int tmp_h = floorf(src_height * yscale);
- err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
+ const Rect& transformedBounds = mLayer.getTransformedBounds();
+ const copybit_rect_t& drect =
+ reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ const State& s(mLayer.drawingState());
+ region_iterator it(clip);
- if (LIKELY(err == NO_ERROR)) {
- NativeBuffer tmp;
- mTempBitmap.getBitmapSurface(&tmp.img);
- tmp.crop.l = 0;
- tmp.crop.t = 0;
- tmp.crop.r = tmp.img.w;
- tmp.crop.b = tmp.img.h;
-
- region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- err = copybit->stretch(copybit,
- &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
- src = tmp;
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
}
- }
- const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
- const State& s(mLayer.drawingState());
- region_iterator it(clip);
-
- // pick the right orientation for this buffer
- int orientation = mLayer.getOrientation();
- if (UNLIKELY(mBufferHeap.transform)) {
- Transform rot90;
- GraphicPlane::orientationToTransfrom(
- ISurfaceComposer::eOrientation90, 0, 0, &rot90);
- const Transform& planeTransform(mLayer.graphicPlane(0).transform());
- const Layer::State& s(mLayer.drawingState());
- Transform tr(planeTransform * s.transform * rot90);
- orientation = tr.getOrientation();
- }
-
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
- err = copybit->stretch(copybit,
- &dst, &src.img, &drect, &src.crop, &it);
- if (err != NO_ERROR) {
- LOGE("copybit failed (%s)", strerror(err));
+ err = copybit->stretch(copybit,
+ &dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
}
}
-
- if (!can_use_copybit || err) {
- if (UNLIKELY(mTextureName == -1LU)) {
- mTextureName = mLayer.createTexture();
+#endif
+
+ if (!copybit || err)
+ {
+ // OpenGL fall-back
+ if (UNLIKELY(mTexture.name == -1LU)) {
+ mTexture.name = mLayer.createTexture();
}
GLuint w = 0;
GLuint h = 0;
@@ -541,10 +538,11 @@
t.stride = src.img.w;
t.vstride= src.img.h;
t.format = src.img.format;
- t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
+ t.data = (GGLubyte*)src.img.base;
const Region dirty(Rect(t.width, t.height));
- mLayer.loadTexture(dirty, mTextureName, t, w, h);
- mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
+ mLayer.loadTexture(&mTexture, mTexture.name, dirty, t);
+ mTexture.transform = mBufferHeap.transform;
+ mLayer.drawWithOpenGL(clip, mTexture);
}
}
@@ -580,6 +578,7 @@
mFormat = overlay->format;
mWidthStride = overlay->w_stride;
mHeightStride = overlay->h_stride;
+ mInitialized = false;
mOverlayHandle = overlay->getHandleRef(overlay);
@@ -599,6 +598,11 @@
}
}
+void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
+{
+ mLayer.clearWithOpenGL(clip);
+}
+
void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
{
const Layer::State& front(mLayer.drawingState());
@@ -614,8 +618,9 @@
// this code-path must be as tight as possible, it's called each time
// the screen is composited.
if (UNLIKELY(mOverlay != 0)) {
- if (mVisibilityChanged) {
+ if (mVisibilityChanged || !mInitialized) {
mVisibilityChanged = false;
+ mInitialized = true;
const Rect& bounds = mLayer.getTransformedBounds();
int x = bounds.left;
int y = bounds.top;
@@ -627,8 +632,9 @@
if (mOverlay) {
overlay_control_device_t* overlay_dev = mOverlayDevice;
overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
- overlay_dev->setParameter(overlay_dev, mOverlay,
+ overlay_dev->setParameter(overlay_dev, mOverlay,
OVERLAY_TRANSFORM, mLayer.getOrientation());
+ overlay_dev->commit(overlay_dev, mOverlay);
}
}
}
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2dc77f1..8057219 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -20,18 +20,18 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <private/ui/LayerState.h>
-#include <EGL/eglnatives.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
+struct copybit_device_t;
+
namespace android {
// ---------------------------------------------------------------------------
-class MemoryDealer;
class Region;
class OverlayRef;
@@ -51,7 +51,6 @@
LayerBuffer& mLayer;
};
-
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -59,12 +58,14 @@
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBuffer();
+ virtual void onFirstRef();
virtual bool needsBlending() const;
- virtual sp<LayerBaseClient::Surface> getSurface() const;
+ virtual sp<LayerBaseClient::Surface> createSurface() const;
+ virtual status_t ditch();
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t flags);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
@@ -121,14 +122,14 @@
virtual void unregisterBuffers();
virtual bool transformed() const;
private:
- mutable Mutex mLock;
- sp<Buffer> mBuffer;
- status_t mStatus;
- ISurface::BufferHeap mBufferHeap;
- size_t mBufferSize;
- mutable sp<MemoryDealer> mTemporaryDealer;
- mutable LayerBitmap mTempBitmap;
- mutable GLuint mTextureName;
+ mutable Mutex mLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable sp<android::Buffer> mTempBitmap;
+ mutable LayerBase::Texture mTexture;
+ copybit_device_t* mBlitEngine;
};
class OverlaySource : public Source {
@@ -137,6 +138,7 @@
sp<OverlayRef>* overlayRef,
uint32_t w, uint32_t h, int32_t format);
virtual ~OverlaySource();
+ virtual void onDraw(const Region& clip) const;
virtual void onTransaction(uint32_t flags);
virtual void onVisibilityResolved(const Transform& planeTransform);
private:
@@ -173,40 +175,34 @@
int32_t mWidthStride;
int32_t mHeightStride;
mutable Mutex mLock;
+ bool mInitialized;
};
class SurfaceBuffer : public LayerBaseClient::Surface
{
public:
- SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+ SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner);
virtual ~SurfaceBuffer();
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+
virtual sp<OverlayRef> createOverlay(
uint32_t w, uint32_t h, int32_t format);
- void disown();
private:
- LayerBuffer* getOwner() const {
- Mutex::Autolock _l(mLock);
- return mOwner;
+ sp<LayerBuffer> getOwner() const {
+ return static_cast<LayerBuffer*>(Surface::getOwner().get());
}
- mutable Mutex mLock;
- LayerBuffer* mOwner;
};
-
- friend class SurfaceFlinger;
- sp<SurfaceBuffer> getClientSurface() const;
-
+
mutable Mutex mLock;
sp<Source> mSource;
-
+ sp<Surface> mSurface;
bool mInvalidate;
bool mNeedsBlending;
- mutable wp<SurfaceBuffer> mClientSurface;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 0c347cc..f613767 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -23,9 +21,9 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include "BufferAllocator.h"
#include "LayerDim.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
@@ -33,27 +31,77 @@
const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
const char* const LayerDim::typeID = "LayerDim";
-sp<MemoryDealer> LayerDim::mDimmerDealer;
-LayerBitmap LayerDim::mDimmerBitmap;
+
+bool LayerDim::sUseTexture;
+GLuint LayerDim::sTexId;
+EGLImageKHR LayerDim::sImage;
+int32_t LayerDim::sWidth;
+int32_t LayerDim::sHeight;
// ---------------------------------------------------------------------------
LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
- : LayerBaseClient(flinger, display, client, i)
+ const sp<Client>& client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i)
{
}
void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
{
- // must only be called once.
- mDimmerDealer = flinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- if (mDimmerDealer != 0) {
- mDimmerBitmap.init(mDimmerDealer);
- mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
- mDimmerBitmap.clear();
+ sTexId = -1;
+ sImage = EGL_NO_IMAGE_KHR;
+ sWidth = w;
+ sHeight = h;
+ sUseTexture = false;
+
+#ifdef DIM_WITH_TEXTURE
+
+#warning "using a texture to implement LayerDim"
+
+ /* On some h/w like msm7K, it is faster to use a texture because the
+ * software renderer will defer to copybit, for this to work we need to
+ * use an EGLImage texture so copybit can actually make use of it.
+ * This burns a full-screen worth of graphic memory.
+ */
+
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ uint32_t flags = hw.getFlags();
+
+ if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
+ // TODO: api to pass the usage flags
+ sp<Buffer> buffer = new Buffer(w, h, PIXEL_FORMAT_RGB_565,
+ BufferAllocator::USAGE_SW_WRITE_OFTEN |
+ BufferAllocator::USAGE_HW_TEXTURE);
+
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ glGenTextures(1, &sTexId);
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
+ if (sImage == EGL_NO_IMAGE_KHR) {
+ LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+ return;
+ }
+
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
+ GLint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ eglDestroyImageKHR(dpy, sImage);
+ LOGE("glEGLImageTargetTexture2DOES() failed. err=0x%4x", error);
+ return;
+ }
+
+ // initialize the texture with zeros
+ GGLSurface t;
+ buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ memset(t.data, 0, t.stride * t.height * 2);
+ buffer->unlock();
+ sUseTexture = true;
}
+#endif
}
LayerDim::~LayerDim()
@@ -63,49 +111,56 @@
void LayerDim::onDraw(const Region& clip) const
{
const State& s(drawingState());
-
- Region::iterator iterator(clip);
- if (s.alpha>0 && iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (s.alpha>0 && (it != end)) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- mDimmerBitmap.getBitmapSurface(&src);
- const copybit_rect_t& srect(drect);
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0, 0, alpha);
+
+#ifdef DIM_WITH_TEXTURE
+ if (sUseTexture) {
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ const GLshort texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_SHORT, 0, texCoords);
+ } else
+#endif
+ {
+ glDisable(GL_TEXTURE_2D);
}
- if (!can_use_copybit || err) {
- const GGLfixed alpha = (s.alpha << 16)/255;
- const uint32_t fbHeight = hw.getHeight();
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_DITHER);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glColor4x(0, 0, 0, alpha);
- glVertexPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
+ GLshort w = sWidth;
+ GLshort h = sHeight;
+ const GLshort vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
index 3e37a47..33bd49d 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -20,6 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -29,6 +32,11 @@
class LayerDim : public LayerBaseClient
{
+ static bool sUseTexture;
+ static GLuint sTexId;
+ static EGLImageKHR sImage;
+ static int32_t sWidth;
+ static int32_t sHeight;
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -36,7 +44,7 @@
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerDim();
virtual void onDraw(const Region& clip) const;
@@ -44,10 +52,6 @@
virtual bool isSecure() const { return false; }
static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
-
-private:
- static sp<MemoryDealer> mDimmerDealer;
- static LayerBitmap mDimmerBitmap;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
deleted file mode 100644
index 79e5328..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/StopWatch.h>
-
-#include <core/SkBitmap.h>
-
-#include <ui/EGLDisplaySurface.h>
-
-#include "BlurFilter.h"
-#include "LayerBase.h"
-#include "LayerOrientationAnim.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "OrientationAnimation.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
-const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
-
-// ---------------------------------------------------------------------------
-
-// Animation...
-const float DURATION = ms2ns(200);
-const float BOUNCES_PER_SECOND = 0.5f;
-const float DIM_TARGET = 0.40f;
-#define INTERPOLATED_TIME(_t) (_t)
-
-// ---------------------------------------------------------------------------
-
-LayerOrientationAnim::LayerOrientationAnim(
- SurfaceFlinger* flinger, DisplayID display,
- OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut)
- : LayerOrientationAnimBase(flinger, display), mAnim(anim),
- mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
- mTextureName(-1), mTextureNameIn(-1)
-{
- // blur that texture.
- mOrientationCompleted = false;
- mNeedsBlending = false;
-}
-
-LayerOrientationAnim::~LayerOrientationAnim()
-{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
- }
- if (mTextureNameIn != -1U) {
- LayerBase::deletedTextures.add(mTextureNameIn);
- }
-}
-
-bool LayerOrientationAnim::needsBlending() const
-{
- return mNeedsBlending;
-}
-
-Point LayerOrientationAnim::getPhysicalSize() const
-{
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- return Point(hw.getWidth(), hw.getHeight());
-}
-
-void LayerOrientationAnim::validateVisibility(const Transform&)
-{
- const Layer::State& s(drawingState());
- const Transform tr(s.transform);
- const Point size(getPhysicalSize());
- uint32_t w = size.x;
- uint32_t h = size.y;
- mTransformedBounds = tr.makeBounds(w, h);
- mLeft = tr.tx();
- mTop = tr.ty();
- transparentRegionScreen.clear();
- mTransformed = true;
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- mCanUseCopyBit = true;
- }
-}
-
-void LayerOrientationAnim::onOrientationCompleted()
-{
- mAnim->onAnimationFinished();
-}
-
-void LayerOrientationAnim::onDraw(const Region& clip) const
-{
- float alphaIn = DIM_TARGET;
-
- // clear screen
- // TODO: with update on demand, we may be able
- // to not erase the screen at all during the animation
- if (!mOrientationCompleted) {
- glDisable(GL_BLEND);
- glDisable(GL_DITHER);
- glDisable(GL_SCISSOR_TEST);
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-
- copybit_image_t dst;
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- hw.getDisplaySurface(&dst);
-
- copybit_image_t src;
- mBitmapIn.getBitmapSurface(&src);
-
- copybit_image_t srcOut;
- mBitmapOut.getBitmapSurface(&srcOut);
-
- const int w = dst.w;
- const int h = dst.h;
- const int xc = uint32_t(dst.w-w)/2;
- const int yc = uint32_t(dst.h-h)/2;
- const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
- const copybit_rect_t srect = { 0, 0, src.w, src.h };
- const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
-
- int err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
- if (alphaIn > 0) {
- region_iterator it(reg);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_ENABLE);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alphaIn*255));
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_DISABLE);
- }
- LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
- }
- if (!can_use_copybit || err) {
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = src.w;
- t.height = src.h;
- t.stride = src.w;
- t.vstride= src.h;
- t.format = src.format;
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
-
- Transform tr;
- tr.set(xc, yc);
-
- // FIXME: we should not access mVertices and mDrawingState like that,
- // but since we control the animation, we know it's going to work okay.
- // eventually we'd need a more formal way of doing things like this.
- LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
- tr.transform(self.mVertices[0], 0, 0);
- tr.transform(self.mVertices[1], 0, src.h);
- tr.transform(self.mVertices[2], src.w, src.h);
- tr.transform(self.mVertices[3], src.w, 0);
- if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
- // Too slow to do this in software
- self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
- }
-
- if (alphaIn > 0.0f) {
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
- if (UNLIKELY(mTextureNameIn == -1LU)) {
- mTextureNameIn = createTexture();
- GLuint w=0, h=0;
- const Region dirty(Rect(t.width, t.height));
- loadTexture(dirty, mTextureNameIn, t, w, h);
- }
- self.mDrawingState.alpha = int(alphaIn*255);
- drawWithOpenGL(reg, mTextureNameIn, t);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
deleted file mode 100644
index 12b6f1c..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
-#define ANDROID_LAYER_ORIENTATION_ANIM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Parcel.h>
-
-#include "LayerBase.h"
-#include "LayerBitmap.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-class OrientationAnimation;
-
-
-class LayerOrientationAnimBase : public LayerBase
-{
-public:
- LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
- : LayerBase(flinger, display) {
- }
- virtual void onOrientationCompleted() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class LayerOrientationAnim : public LayerOrientationAnimBase
-{
-public:
- static const uint32_t typeInfo;
- static const char* const typeID;
- virtual char const* getTypeID() const { return typeID; }
- virtual uint32_t getTypeInfo() const { return typeInfo; }
-
- LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
- OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut);
- virtual ~LayerOrientationAnim();
-
- void onOrientationCompleted();
-
- virtual void onDraw(const Region& clip) const;
- virtual Point getPhysicalSize() const;
- virtual void validateVisibility(const Transform& globalTransform);
- virtual bool needsBlending() const;
- virtual bool isSecure() const { return false; }
-private:
- OrientationAnimation* mAnim;
- LayerBitmap mBitmapIn;
- LayerBitmap mBitmapOut;
- bool mOrientationCompleted;
- mutable GLuint mTextureName;
- mutable GLuint mTextureNameIn;
- mutable bool mNeedsBlending;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp
new file mode 100644
index 0000000..b43d801
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void MessageList::insert(const sp<MessageBase>& node)
+{
+ LIST::iterator cur(mList.begin());
+ LIST::iterator end(mList.end());
+ while (cur != end) {
+ if (*node < **cur) {
+ mList.insert(cur, node);
+ return;
+ }
+ ++cur;
+ }
+ mList.insert(++end, node);
+}
+
+void MessageList::remove(MessageList::LIST::iterator pos)
+{
+ mList.erase(pos);
+}
+
+// ---------------------------------------------------------------------------
+
+MessageQueue::MessageQueue()
+ : mInvalidate(false)
+{
+ mInvalidateMessage = new MessageBase(INVALIDATE);
+}
+
+MessageQueue::~MessageQueue()
+{
+}
+
+MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
+{
+ MessageList::value_type result;
+
+ bool again;
+ do {
+ const nsecs_t timeoutTime = systemTime() + timeout;
+ while (true) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime();
+ nsecs_t nextEventTime = -1;
+
+ // invalidate messages are always handled first
+ if (mInvalidate) {
+ mInvalidate = false;
+ mInvalidateMessage->when = now;
+ result = mInvalidateMessage;
+ break;
+ }
+
+ LIST::iterator cur(mMessages.begin());
+ if (cur != mMessages.end()) {
+ result = *cur;
+ }
+
+ if (result != 0) {
+ if (result->when <= now) {
+ // there is a message to deliver
+ mMessages.remove(cur);
+ break;
+ }
+ if (timeout>=0 && timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ nextEventTime = result->when;
+ result = 0;
+ }
+
+ if (timeout >= 0 && nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ }
+
+ if (nextEventTime >= 0) {
+ //LOGD("nextEventTime = %lld ms", nextEventTime);
+ if (nextEventTime > 0) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ const nsecs_t reltime = nextEventTime - systemTime();
+ if (reltime > 0) {
+ mCondition.waitRelative(mLock, reltime);
+ }
+ }
+ } else {
+ //LOGD("going to wait");
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mCondition.wait(mLock);
+ }
+ }
+ // here we're not holding the lock anymore
+
+ if (result == 0)
+ break;
+
+ again = result->handler();
+ if (again) {
+ // the message has been processed. release our reference to it
+ // without holding the lock.
+ result = 0;
+ }
+
+ } while (again);
+
+ return result;
+}
+
+status_t MessageQueue::postMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ return queueMessage(message, relTime, flags);
+}
+
+status_t MessageQueue::invalidate() {
+ Mutex::Autolock _l(mLock);
+ mInvalidate = true;
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t MessageQueue::queueMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ message->when = systemTime() + relTime;
+ mMessages.insert(message);
+
+ //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
+ //dumpLocked(message);
+
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+void MessageQueue::dump(const MessageList::value_type& message)
+{
+ Mutex::Autolock _l(mLock);
+ dumpLocked(message);
+}
+
+void MessageQueue::dumpLocked(const MessageList::value_type& message)
+{
+ LIST::const_iterator cur(mMessages.begin());
+ LIST::const_iterator end(mMessages.end());
+ int c = 0;
+ while (cur != end) {
+ const char tick = (*cur == message) ? '>' : ' ';
+ LOGD("%c %d: msg{.what=%08x, when=%lld}",
+ tick, c, (*cur)->what, (*cur)->when);
+ ++cur;
+ c++;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h
new file mode 100644
index 0000000..dc8138d
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.h
@@ -0,0 +1,127 @@
+/*
+ * 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 ANDROID_MESSAGE_QUEUE_H
+#define ANDROID_MESSAGE_QUEUE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MessageBase;
+
+class MessageList
+{
+ List< sp<MessageBase> > mList;
+ typedef List< sp<MessageBase> > LIST;
+public:
+ typedef sp<MessageBase> value_type;
+ inline LIST::iterator begin() { return mList.begin(); }
+ inline LIST::const_iterator begin() const { return mList.begin(); }
+ inline LIST::iterator end() { return mList.end(); }
+ inline LIST::const_iterator end() const { return mList.end(); }
+ inline bool isEmpty() const { return mList.empty(); }
+ void insert(const sp<MessageBase>& node);
+ void remove(LIST::iterator pos);
+};
+
+// ============================================================================
+
+class MessageBase :
+ public LightRefBase<MessageBase>
+{
+public:
+ nsecs_t when;
+ uint32_t what;
+ int32_t arg0;
+
+ MessageBase() : when(0), what(0), arg0(0) { }
+ MessageBase(uint32_t what, int32_t arg0=0)
+ : when(0), what(what), arg0(arg0) { }
+
+ // return true if message has a handler
+ virtual bool handler() { return false; }
+
+protected:
+ virtual ~MessageBase() { }
+
+private:
+ friend class LightRefBase<MessageBase>;
+};
+
+inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
+ return lhs.when < rhs.when;
+}
+
+// ---------------------------------------------------------------------------
+
+class MessageQueue
+{
+ typedef List< sp<MessageBase> > LIST;
+public:
+
+ // this is a work-around the multichar constant warning. A macro would
+ // work too, but would pollute the namespace.
+ template <int a, int b, int c, int d>
+ struct WHAT {
+ static const uint32_t Value =
+ (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)|
+ (uint32_t(c&0xff)<<8)|uint32_t(d&0xff);
+ };
+
+ MessageQueue();
+ ~MessageQueue();
+
+ // pre-defined messages
+ enum {
+ INVALIDATE = WHAT<'_','p','d','t'>::Value
+ };
+
+ MessageList::value_type waitMessage(nsecs_t timeout = -1);
+
+ status_t postMessage(const MessageList::value_type& message,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ status_t invalidate();
+
+ void dump(const MessageList::value_type& message);
+
+private:
+ status_t queueMessage(const MessageList::value_type& message,
+ nsecs_t reltime, uint32_t flags);
+ void dumpLocked(const MessageList::value_type& message);
+
+ Mutex mLock;
+ Condition mCondition;
+ MessageList mMessages;
+ bool mInvalidate;
+ MessageList::value_type mInvalidateMessage;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
deleted file mode 100644
index 12c0eef..0000000
--- a/libs/surfaceflinger/OrientationAnimation.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#include "DisplayHardware/DisplayHardware.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
-{
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
- ISurfaceComposer::eHardware);
-}
-
-OrientationAnimation::~OrientationAnimation()
-{
-}
-
-void OrientationAnimation::onOrientationChanged(uint32_t type)
-{
- if (mState == DONE) {
- mType = type;
- if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
- mState = PREPARE;
- }
- }
-}
-
-void OrientationAnimation::onAnimationFinished()
-{
- if (mState != DONE)
- mState = FINISH;
-}
-
-bool OrientationAnimation::run_impl()
-{
- bool skip_frame;
- switch (mState) {
- default:
- case DONE:
- skip_frame = done();
- break;
- case PREPARE:
- skip_frame = prepare();
- break;
- case PHASE1:
- skip_frame = phase1();
- break;
- case PHASE2:
- skip_frame = phase2();
- break;
- case FINISH:
- skip_frame = finished();
- break;
- }
- return skip_frame;
-}
-
-bool OrientationAnimation::done()
-{
- return done_impl();
-}
-
-bool OrientationAnimation::prepare()
-{
- mState = PHASE1;
-
- const GraphicPlane& plane(mFlinger->graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- const uint32_t w = hw.getWidth();
- const uint32_t h = hw.getHeight();
-
- LayerBitmap bitmap;
- bitmap.init(mTemporaryDealer);
- bitmap.setBits(w, h, 1, hw.getFormat());
-
- LayerBitmap bitmapIn;
- bitmapIn.init(mTemporaryDealer);
- bitmapIn.setBits(w, h, 1, hw.getFormat());
-
- copybit_image_t front;
- bitmap.getBitmapSurface(&front);
- hw.copyFrontToImage(front);
-
- LayerOrientationAnimBase* l;
-
- l = new LayerOrientationAnim(
- mFlinger.get(), 0, this, bitmap, bitmapIn);
-
- l->initStates(w, h, 0);
- l->setLayer(INT_MAX-1);
- mFlinger->addLayer(l);
- mLayerOrientationAnim = l;
- return true;
-}
-
-bool OrientationAnimation::phase1()
-{
- if (mFlinger->isFrozen() == false) {
- // start phase 2
- mState = PHASE2;
- mLayerOrientationAnim->onOrientationCompleted();
- mLayerOrientationAnim->invalidate();
- return true;
-
- }
- //mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::phase2()
-{
- // do the 2nd phase of the animation
- mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::finished()
-{
- mState = DONE;
- mFlinger->removeLayer(mLayerOrientationAnim);
- mLayerOrientationAnim = NULL;
- return true;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
deleted file mode 100644
index cafa38d..0000000
--- a/libs/surfaceflinger/OrientationAnimation.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_ORIENTATION_ANIMATION_H
-#define ANDROID_ORIENTATION_ANIMATION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class SurfaceFlinger;
-class MemoryDealer;
-class LayerOrientationAnim;
-
-class OrientationAnimation
-{
-public:
- OrientationAnimation(const sp<SurfaceFlinger>& flinger);
- virtual ~OrientationAnimation();
-
- void onOrientationChanged(uint32_t type);
- void onAnimationFinished();
- inline bool run() {
- if (LIKELY(mState == DONE))
- return done_impl();
- return run_impl();
- }
-
-private:
- enum {
- DONE = 0,
- PREPARE,
- PHASE1,
- PHASE2,
- FINISH
- };
-
- bool run_impl();
- inline bool done_impl() {
- if (mFlinger->isFrozen()) {
- // we are not allowed to draw, but pause a bit to make sure
- // apps don't end up using the whole CPU, if they depend on
- // surfaceflinger for synchronization.
- usleep(8333); // 8.3ms ~ 120fps
- return true;
- }
- return false;
- }
-
- bool done();
- bool prepare();
- bool phase1();
- bool phase2();
- bool finished();
-
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mTemporaryDealer;
- LayerOrientationAnimBase* mLayerOrientationAnim;
- int mState;
- uint32_t mType;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 97dfecc..102899c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
@@ -23,6 +21,7 @@
#include <fcntl.h>
#include <errno.h>
#include <math.h>
+#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -30,36 +29,30 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
#include <ui/DisplayInfo.h>
-#include <ui/EGLDisplaySurface.h>
#include <pixelflinger/pixelflinger.h>
#include <GLES/gl.h>
#include "clz.h"
-#include "CPUGauge.h"
+#include "BufferAllocator.h"
#include "Layer.h"
#include "LayerBlur.h"
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
-#include "GPUHardware/GPUHardware.h"
-
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -93,30 +86,30 @@
}
ssize_t SurfaceFlinger::LayerVector::indexOf(
- LayerBase* key, size_t guess) const
+ const sp<LayerBase>& key, size_t guess) const
{
if (guess<size() && lookup.keyAt(guess) == key)
return guess;
const ssize_t i = lookup.indexOfKey(key);
if (i>=0) {
const size_t idx = lookup.valueAt(i);
- LOG_ASSERT(layers[idx]==key,
+ LOGE_IF(layers[idx]!=key,
"LayerVector[%p]: layers[%d]=%p, key=%p",
- this, int(idx), layers[idx], key);
+ this, int(idx), layers[idx].get(), key.get());
return idx;
}
return i;
}
ssize_t SurfaceFlinger::LayerVector::add(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
size_t count = layers.size();
ssize_t l = 0;
ssize_t h = count-1;
ssize_t mid;
- LayerBase* const* a = layers.array();
+ sp<LayerBase> const* a = layers.array();
while (l <= h) {
mid = l + (h - l)/2;
const int c = cmp(a+mid, &layer);
@@ -139,14 +132,14 @@
return order;
}
-ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
+ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
{
const ssize_t keyIndex = lookup.indexOfKey(layer);
if (keyIndex >= 0) {
const size_t index = lookup.valueAt(keyIndex);
- LOG_ASSERT(layers[index]==layer,
+ LOGE_IF(layers[index]!=layer,
"LayerVector[%p]: layers[%u]=%p, layer=%p",
- this, int(index), layers[index], layer);
+ this, int(index), layers[index].get(), layer.get());
layers.removeItemsAt(index);
lookup.removeItemsAt(keyIndex);
const size_t count = lookup.size();
@@ -161,8 +154,8 @@
}
ssize_t SurfaceFlinger::LayerVector::reorder(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
// XXX: it's a little lame. but oh well...
ssize_t err = remove(layer);
@@ -180,7 +173,11 @@
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
mTransactionCount(0),
+ mLayersRemoved(false),
mBootTime(systemTime()),
+ mHardwareTest("android.permission.HARDWARE_TEST"),
+ mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
+ mDump("android.permission.DUMP"),
mLastScheduledBroadcast(NULL),
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
@@ -188,11 +185,7 @@
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
- mDebugCpu(0),
- mDebugFps(0),
mDebugBackground(0),
- mSyncObject(),
- mDeplayedTransactionPending(0),
mConsoleSignals(0),
mSecureFrameBuffer(0)
{
@@ -207,28 +200,16 @@
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
- property_get("debug.sf.showcpu", value, "0");
- mDebugCpu = atoi(value);
property_get("debug.sf.showbackground", value, "0");
mDebugBackground = atoi(value);
- property_get("debug.sf.showfps", value, "0");
- mDebugFps = atoi(value);
LOGI_IF(mDebugRegion, "showupdates enabled");
- LOGI_IF(mDebugCpu, "showcpu enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
- LOGI_IF(mDebugFps, "showfps enabled");
}
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
- delete mOrientationAnimation;
-}
-
-copybit_device_t* SurfaceFlinger::getBlitEngine() const
-{
- return graphicPlane(0).displayHardware().getBlitEngine();
}
overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
@@ -236,29 +217,9 @@
return graphicPlane(0).displayHardware().getOverlayEngine();
}
-sp<IMemory> SurfaceFlinger::getCblk() const
+sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
- return mServerCblkMemory;
-}
-
-status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu)
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- status_t err = mGPU->request(pid, callback, gpu);
- return err;
-}
-
-status_t SurfaceFlinger::revokeGPU()
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- return mGPU->friendlyRevoke();
+ return mServerHeap;
}
sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
@@ -266,33 +227,34 @@
Mutex::Autolock _l(mStateLock);
uint32_t token = mTokens.acquire();
- Client* client = new Client(token, this);
- if ((client == 0) || (client->ctrlblk == 0)) {
+ sp<Client> client = new Client(token, this);
+ if (client->ctrlblk == 0) {
mTokens.release(token);
return 0;
}
status_t err = mClientsMap.add(token, client);
if (err < 0) {
- delete client;
mTokens.release(token);
return 0;
}
sp<BClient> bclient =
- new BClient(this, token, client->controlBlockMemory());
+ new BClient(this, token, client->getControlBlockMemory());
return bclient;
}
void SurfaceFlinger::destroyConnection(ClientID cid)
{
Mutex::Autolock _l(mStateLock);
- Client* const client = mClientsMap.valueFor(cid);
- if (client) {
+ sp<Client> client = mClientsMap.valueFor(cid);
+ if (client != 0) {
// free all the layers this client owns
- const Vector<LayerBaseClient*>& layers = client->getLayers();
+ Vector< wp<LayerBaseClient> > layers(client->getLayers());
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- LayerBaseClient* const layer = layers[i];
- removeLayer_l(layer);
+ sp<LayerBaseClient> layer(layers[i].promote());
+ if (layer != 0) {
+ purgatorizeLayer_l(layer);
+ }
}
// the resources associated with this client will be freed
@@ -339,41 +301,15 @@
mReadyToRunBarrier.wait();
}
-
static inline uint16_t pack565(int r, int g, int b) {
return (r<<11)|(g<<5)|b;
}
-// this is defined in libGLES_CM.so
-extern ISurfaceComposer* GLES_localSurfaceManager;
-
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- // create the shared control-block
- mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
- LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
- mServerCblkMemory = mServerHeap->allocate(4096);
- LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
-
- mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
- LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
- new(mServerCblk) surface_flinger_cblk_t;
-
- // get a reference to the GPU if we have one
- mGPU = GPUFactory::getGPU();
-
- // create the surface Heap manager, which manages the heaps
- // (be it in RAM or VRAM) where surfaces are allocated
- // We give 8 MB per client.
- mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
-
-
- GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
-
// we only support one display currently
int dpy = 0;
@@ -384,6 +320,16 @@
plane.setDisplayHardware(hw);
}
+ // create the shared control-block
+ mServerHeap = new MemoryHeapBase(4096,
+ MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+
+ new(mServerCblk) surface_flinger_cblk_t;
+
// initialize primary screen
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
@@ -450,13 +396,6 @@
* We're now ready to accept clients...
*/
- mOrientationAnimation = new OrientationAnimation(this);
-
- // start CPU gauge display
- if (mDebugCpu)
- mCpuGauge = new CPUGauge(this, ms2ns(500));
-
-
// start boot animation
property_set("ctl.start", "bootanim");
@@ -471,45 +410,53 @@
void SurfaceFlinger::waitForEvent()
{
- // wait for something to do
- if (UNLIKELY(isFrozen())) {
- // wait 5 seconds
- const nsecs_t freezeDisplayTimeout = ms2ns(5000);
- const nsecs_t now = systemTime();
- if (mFreezeDisplayTime == 0) {
- mFreezeDisplayTime = now;
+ while (true) {
+ nsecs_t timeout = -1;
+ if (UNLIKELY(isFrozen())) {
+ // wait 5 seconds
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ timeout = waitTime>0 ? waitTime : 0;
}
- nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
- int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
- if (err != NO_ERROR) {
+
+ MessageList::value_type msg = mEventQueue.waitMessage(timeout);
+ if (msg != 0) {
+ mFreezeDisplayTime = 0;
+ switch (msg->what) {
+ case MessageQueue::INVALIDATE:
+ // invalidate message, just return to the main loop
+ return;
+ }
+ } else {
+ // we timed out
if (isFrozen()) {
// we timed out and are still frozen
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
mFreezeDisplay, mFreezeCount);
mFreezeCount = 0;
mFreezeDisplay = false;
+ return;
}
}
- } else {
- mFreezeDisplayTime = 0;
- mSyncObject.wait();
}
}
void SurfaceFlinger::signalEvent() {
- mSyncObject.open();
+ mEventQueue.invalidate();
}
void SurfaceFlinger::signal() const {
- mSyncObject.open();
+ // this is the IPC call
+ const_cast<SurfaceFlinger*>(this)->signalEvent();
}
void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
{
- if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
- sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
- delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
- }
+ mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay);
}
// ----------------------------------------------------------------------------
@@ -548,11 +495,6 @@
unlockClients();
executeScheduledBroadcasts();
- // sample the cpu gauge
- if (UNLIKELY(mDebugCpu)) {
- handleDebugCpu();
- }
-
postFramebuffer();
} else {
// pretend we did the post
@@ -565,28 +507,18 @@
void SurfaceFlinger::postFramebuffer()
{
- const bool skip = mOrientationAnimation->run();
- if (UNLIKELY(skip)) {
+ if (isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
return;
}
if (!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
hw.flip(mInvalidRegion);
-
mInvalidRegion.clear();
-
- if (Layer::deletedTextures.size()) {
- glDeleteTextures(
- Layer::deletedTextures.size(),
- Layer::deletedTextures.array());
- Layer::deletedTextures.clear();
- }
}
}
@@ -601,15 +533,13 @@
}
if (mDeferReleaseConsole && hw.canDraw()) {
- // We got the release signal before the aquire signal
+ // We got the release signal before the acquire signal
mDeferReleaseConsole = false;
- revokeGPU();
hw.releaseScreen();
}
if (what & eConsoleReleased) {
if (hw.canDraw()) {
- revokeGPU();
hw.releaseScreen();
} else {
mDeferReleaseConsole = true;
@@ -621,9 +551,25 @@
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
- Mutex::Autolock _l(mStateLock);
+ Vector< sp<LayerBase> > ditchedLayers;
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ }
+
+ // do this without lock held
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+}
+
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
/*
@@ -634,7 +580,7 @@
const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
if (layersNeedTransaction) {
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@@ -681,7 +627,6 @@
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
mFreezeDisplayTime = 0;
- mOrientationAnimation->onOrientationChanged(type);
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
@@ -689,24 +634,27 @@
mFreezeDisplay = mCurrentState.freezeDisplay;
}
- // some layers might have been removed, so
- // we need to update the regions they're exposing.
- const SortedVector<LayerBase*>& removedLayers(mRemovedLayers);
- size_t c = removedLayers.size();
- if (c) {
- mVisibleRegionsDirty = true;
- while (c--) {
- mDirtyRegionRemovedLayer.orSelf(
- removedLayers[c]->visibleRegionScreen);
- }
- }
-
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
// layers have been added
mVisibleRegionsDirty = true;
}
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ if (mLayersRemoved) {
+ mVisibleRegionsDirty = true;
+ const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+ const size_t count = previousLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(previousLayers[i]);
+ if (currentLayers.indexOf( layer ) < 0) {
+ // this layer is not visible anymore
+ ditchedLayers.add(layer);
+ mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
+ }
+ }
+ }
+
// get rid of all resources we don't need anymore
// (layers and clients)
free_resources_l();
@@ -734,7 +682,7 @@
size_t i = currentLayers.size();
while (i--) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
layer->validateVisibility(planeTransform);
// start with the whole surface at its current location
@@ -785,7 +733,7 @@
// accumulate to the screen dirty region
dirtyRegion.orSelf(dirty);
- // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+ // Update aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
aboveCoveredLayers.orSelf(visibleRegion);
@@ -837,9 +785,9 @@
{
bool recomputeVisibleRegions = false;
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->lockPageFlip(recomputeVisibleRegions);
}
return recomputeVisibleRegions;
@@ -850,37 +798,58 @@
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
+
void SurfaceFlinger::handleRepaint()
{
- // set the frame buffer
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+ if (mInvalidRegion.isEmpty()) {
+ // nothing to do
+ return;
+ }
if (UNLIKELY(mDebugRegion)) {
debugFlashRegions();
}
- // compute the invalid region
- mInvalidRegion.orSelf(mDirtyRegion);
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
uint32_t flags = hw.getFlags();
- if (flags & DisplayHardware::BUFFER_PRESERVED) {
- // here we assume DisplayHardware::flip()'s implementation
- // performs the copy-back optimization.
- } else {
- if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
- // we need to fully redraw the part that will be updated
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
+ {
+ // we can redraw only what's dirty, but since SWAP_RECTANGLE only
+ // takes a rectangle, we must make sure to update that whole
+ // rectangle in that case
+ if (flags & DisplayHardware::SWAP_RECTANGLE) {
+ // FIXME: we really should be able to pass a region to
+ // SWAP_RECTANGLE so that we don't have to redraw all this.
mDirtyRegion.set(mInvalidRegion.bounds());
} else {
- // we need to redraw everything
+ // in the BUFFER_PRESERVED case, obviously, we can update only
+ // what's needed and nothing more.
+ // NOTE: this is NOT a common case, as preserving the backbuffer
+ // is costly and usually involves copying the whole update back.
+ }
+ } else {
+ if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because UPDATE_ON_DEMAND only takes one
+ // rectangle instead of a region (see DisplayHardware::flip())
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // we need to redraw everything (the whole screen)
mDirtyRegion.set(hw.bounds());
mInvalidRegion = mDirtyRegion;
}
@@ -903,9 +872,9 @@
const SurfaceFlinger& flinger(*this);
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase const* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase const * const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
const Region& visibleRegion(layer->visibleRegionScreen);
if (!visibleRegion.isEmpty()) {
const Region clip(dirty.intersect(visibleRegion));
@@ -920,14 +889,14 @@
{
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->finishPageFlip();
}
}
-void SurfaceFlinger::scheduleBroadcast(Client* client)
+void SurfaceFlinger::scheduleBroadcast(const sp<Client>& client)
{
if (mLastScheduledBroadcast != client) {
mLastScheduledBroadcast = client;
@@ -937,50 +906,56 @@
void SurfaceFlinger::executeScheduledBroadcasts()
{
- SortedVector<Client*>& list = mScheduledBroadcasts;
+ SortedVector< wp<Client> >& list(mScheduledBroadcasts);
size_t count = list.size();
while (count--) {
- per_client_cblk_t* const cblk = list[count]->ctrlblk;
- if (cblk->lock.tryLock() == NO_ERROR) {
- cblk->cv.broadcast();
- list.removeAt(count);
- cblk->lock.unlock();
- } else {
- // schedule another round
- LOGW("executeScheduledBroadcasts() skipped, "
- "contention on the client. We'll try again later...");
- signalDelayedEvent(ms2ns(4));
+ sp<Client> client = list[count].promote();
+ if (client != 0) {
+ per_client_cblk_t* const cblk = client->ctrlblk;
+ if (cblk->lock.tryLock() == NO_ERROR) {
+ cblk->cv.broadcast();
+ list.removeAt(count);
+ cblk->lock.unlock();
+ } else {
+ // schedule another round
+ LOGW("executeScheduledBroadcasts() skipped, "
+ "contention on the client. We'll try again later...");
+ signalDelayedEvent(ms2ns(4));
+ }
}
}
mLastScheduledBroadcast = 0;
}
-void SurfaceFlinger::handleDebugCpu()
-{
- Mutex::Autolock _l(mDebugLock);
- if (mCpuGauge != 0)
- mCpuGauge->sample();
-}
-
void SurfaceFlinger::debugFlashRegions()
{
- if (UNLIKELY(!mDirtyRegion.isRect())) {
- // TODO: do this only if we don't have preserving
- // swapBuffer. If we don't have update-on-demand,
- // redraw everything.
- composeSurfaces(Region(mDirtyRegion.bounds()));
- }
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t flags = hw.getFlags();
+ if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))) {
+ const Region repaint((flags & DisplayHardware::UPDATE_ON_DEMAND) ?
+ mDirtyRegion.bounds() : hw.bounds());
+ composeSurfaces(repaint);
+ }
+
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
- glColor4x(0x10000, 0, 0x10000, 0x10000);
+ static int toggle = 0;
+ toggle = 1 - toggle;
+ if (toggle) {
+ glColor4x(0x10000, 0, 0x10000, 0x10000);
+ } else {
+ glColor4x(0x10000, 0x10000, 0, 0x10000);
+ }
- Rect r;
- Region::iterator iterator(mDirtyRegion);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = mDirtyRegion.begin();
+ Region::const_iterator const end = mDirtyRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
GLfloat vertices[][2] = {
{ r.left, r.top },
{ r.left, r.bottom },
@@ -990,10 +965,12 @@
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- hw.flip(mDirtyRegion.merge(mInvalidRegion));
- mInvalidRegion.clear();
+
+ if (mInvalidRegion.isEmpty()) {
+ mDirtyRegion.dump("mDirtyRegion");
+ mInvalidRegion.dump("mInvalidRegion");
+ }
+ hw.flip(mInvalidRegion);
if (mDebugRegion > 1)
usleep(mDebugRegion * 1000);
@@ -1017,9 +994,10 @@
if (LIKELY(!mDebugBackground)) {
glClearColorx(0,0,0,0);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
@@ -1037,9 +1015,10 @@
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -1065,7 +1044,7 @@
// XXX: mFPS has the value we want
}
-status_t SurfaceFlinger::addLayer(LayerBase* layer)
+status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
addLayer_l(layer);
@@ -1073,62 +1052,72 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
- removeLayer_l(layer);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR)
+ setTransactionFlags(eTransactionNeeded);
+ return err;
}
-status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
{
layer->forceVisibilityTransaction();
setTransactionFlags(eTraversalNeeded);
return NO_ERROR;
}
-status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(
layer, &LayerBase::compareCurrentStateZ);
- LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
mLayerMap.add(lbc->serverIndex(), lbc);
}
- mRemovedLayers.remove(layer);
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
{
ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
if (index >= 0) {
- mRemovedLayers.add(layerBase);
- LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
- if (layer) {
+ mLayersRemoved = true;
+ sp<LayerBaseClient> layer =
+ LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get());
+ if (layer != 0) {
mLayerMap.removeItem(layer->serverIndex());
}
return NO_ERROR;
}
+ return status_t(index);
+}
+
+status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
+{
+ // remove the layer from the main list (through a transaction).
+ ssize_t err = removeLayer_l(layerBase);
+
// it's possible that we don't find a layer, because it might
// have been destroyed already -- this is not technically an error
- // from the user because there is a race between destroySurface,
- // destroyclient and destroySurface-from-a-transaction.
- return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+ // from the user because there is a race between BClient::destroySurface(),
+ // ~BClient() and ~ISurface().
+ return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
}
+
void SurfaceFlinger::free_resources_l()
{
// Destroy layers that were removed
- destroy_all_removed_layers_l();
-
+ mLayersRemoved = false;
+
// free resources associated with disconnected clients
- SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
- Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts);
+ Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
const size_t count = disconnectedClients.size();
for (size_t i=0 ; i<count ; i++) {
- Client* client = disconnectedClients[i];
+ sp<Client> client = disconnectedClients[i];
// if this client is the scheduled broadcast list,
// remove it from there (and we don't need to signal it
// since it is dead).
@@ -1137,27 +1126,10 @@
scheduledBroadcasts.removeItemsAt(index);
}
mTokens.release(client->cid);
- delete client;
}
disconnectedClients.clear();
}
-void SurfaceFlinger::destroy_all_removed_layers_l()
-{
- size_t c = mRemovedLayers.size();
- while (c--) {
- LayerBase* const removed_layer = mRemovedLayers[c];
-
- LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
- "layer %p removed but still in the current state list",
- removed_layer);
-
- delete removed_layer;
- }
- mRemovedLayers.clear();
-}
-
-
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -1198,7 +1170,7 @@
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1212,7 +1184,7 @@
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1241,7 +1213,7 @@
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
- LayerBaseClient* layer = 0;
+ sp<LayerBaseClient> layer;
sp<LayerBaseClient::Surface> surfaceHandle;
if (int32_t(w|h) < 0) {
@@ -1251,14 +1223,14 @@
}
Mutex::Autolock _l(mStateLock);
- Client* const c = mClientsMap.valueFor(clientId);
- if (UNLIKELY(!c)) {
+ sp<Client> client = mClientsMap.valueFor(clientId);
+ if (UNLIKELY(client == 0)) {
LOGE("createSurface() failed, client not found (id=%d)", clientId);
return surfaceHandle;
}
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
- int32_t id = c->generateId(pid);
+ int32_t id = client->generateId(pid);
if (uint32_t(id) >= NUM_LAYERS_MAX) {
LOGE("createSurface() failed, generateId = %d", id);
return surfaceHandle;
@@ -1267,20 +1239,20 @@
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+ layer = createPushBuffersSurfaceLocked(client, d, id, w, h, flags);
} else {
- layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+ layer = createNormalSurfaceLocked(client, d, id, w, h, format, flags);
}
break;
case eFXSurfaceBlur:
- layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+ layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
break;
case eFXSurfaceDim:
- layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+ layer = createDimSurfaceLocked(client, d, id, w, h, flags);
break;
}
- if (layer) {
+ if (layer != 0) {
setTransactionFlags(eTransactionNeeded);
surfaceHandle = layer->getSurface();
if (surfaceHandle != 0)
@@ -1290,8 +1262,8 @@
return surfaceHandle;
}
-LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
{
// initialize the surfaces
@@ -1305,57 +1277,99 @@
break;
}
- Layer* layer = new Layer(this, display, client, id);
- status_t err = layer->setBuffers(client, w, h, format, flags);
+ sp<Layer> layer = new Layer(this, display, client, id);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (LIKELY(err == NO_ERROR)) {
layer->initStates(w, h, flags);
addLayer_l(layer);
} else {
LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
- delete layer;
- return 0;
+ layer.clear();
}
return layer;
}
-LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBlur* layer = new LayerBlur(this, display, client, id);
+ sp<LayerBlur> layer = new LayerBlur(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerDim* layer = new LayerDim(this, display, client, id);
+ sp<LayerDim> layer = new LayerDim(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+ sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-status_t SurfaceFlinger::destroySurface(SurfaceID index)
+status_t SurfaceFlinger::removeSurface(SurfaceID index)
{
+ /*
+ * called by the window manager, when a surface should be marked for
+ * destruction.
+ *
+ * The surface is removed from the current and drawing lists, but placed
+ * in the purgatory queue, so it's not destroyed right-away (we need
+ * to wait for all client's references to go away first).
+ */
+
Mutex::Autolock _l(mStateLock);
- LayerBaseClient* const layer = getLayerUser_l(index);
- status_t err = removeLayer_l(layer);
- if (err < 0)
- return err;
- setTransactionFlags(eTransactionNeeded);
+ sp<LayerBaseClient> layer = getLayerUser_l(index);
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR) {
+ setTransactionFlags(eTransactionNeeded);
+ }
+ return err;
+}
+
+status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
+{
+ // called by ~ISurface() when all references are gone
+
+ class MessageDestroySurface : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<LayerBaseClient> layer;
+ public:
+ MessageDestroySurface(
+ SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
+ : flinger(flinger), layer(layer) { }
+ virtual bool handler() {
+ sp<LayerBaseClient> l(layer);
+ layer.clear(); // clear it outside of the lock;
+ Mutex::Autolock _l(flinger->mStateLock);
+ /*
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
+ * However, a buggy client could have not done that.
+ * Since we know we don't have any more clients, we don't need
+ * to use the purgatory.
+ */
+ status_t err = flinger->removeLayer_l(l);
+ LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ return true;
+ }
+ };
+
+ mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
return NO_ERROR;
}
@@ -1369,18 +1383,9 @@
cid <<= 16;
for (int i=0 ; i<count ; i++) {
const layer_state_t& s = states[i];
- LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
- if (layer) {
+ sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid));
+ if (layer != 0) {
const uint32_t what = s.what;
- // check if it has been destroyed first
- if (what & eDestroyed) {
- if (removeLayer_l(layer) == NO_ERROR) {
- flags |= eTransactionNeeded;
- // we skip everything else... well, no, not really
- // we skip ONLY that transaction.
- continue;
- }
- }
if (what & ePositionChanged) {
if (layer->setPosition(s.x, s.y))
flags |= eTraversalNeeded;
@@ -1422,9 +1427,10 @@
return NO_ERROR;
}
-LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+sp<LayerBaseClient> SurfaceFlinger::getLayerUser_l(SurfaceID s) const
{
- return mLayerMap.valueFor(s);
+ sp<LayerBaseClient> layer = mLayerMap.valueFor(s);
+ return layer;
}
void SurfaceFlinger::screenReleased(int dpy)
@@ -1446,9 +1452,7 @@
const size_t SIZE = 1024;
char buffer[SIZE];
String8 result;
- if (checkCallingPermission(
- String16("android.permission.DUMP")) == false)
- { // not allowed
+ if (!mDump.checkCalling()) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump SurfaceFlinger from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
@@ -1459,7 +1463,7 @@
size_t s = mClientsMap.size();
char name[64];
for (size_t i=0 ; i<s ; i++) {
- Client* client = mClientsMap.valueAt(i);
+ sp<Client> client = mClientsMap.valueAt(i);
sprintf(name, " Client (id=0x%08x)", client->cid);
client->dump(name);
}
@@ -1467,7 +1471,7 @@
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
/*** LayerBase ***/
- LayerBase const * const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
const Layer::State& s = layer->drawingState();
snprintf(buffer, SIZE,
"+ %s %p\n"
@@ -1475,7 +1479,7 @@
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
"needsBlending=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- layer->getTypeID(), layer,
+ layer->getTypeID(), layer.get(),
s.z, layer->tx(), layer->ty(), s.w, s.h,
layer->needsBlending(), layer->contentDirty,
s.alpha, s.flags,
@@ -1484,30 +1488,33 @@
result.append(buffer);
buffer[0] = 0;
/*** LayerBaseClient ***/
- LayerBaseClient* const lbc =
- LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc =
+ LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
+ sp<Client> client(lbc->client.promote());
snprintf(buffer, SIZE,
" "
"id=0x%08x, client=0x%08x, identity=%u\n",
- lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+ lbc->clientIndex(), client.get() ? client->cid : 0,
lbc->getIdentity());
}
result.append(buffer);
buffer[0] = 0;
/*** Layer ***/
- Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
- if (l) {
+ sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
+ if (l != 0) {
const LayerBitmap& buf0(l->getBuffer(0));
const LayerBitmap& buf1(l->getBuffer(1));
snprintf(buffer, SIZE,
" "
- "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
" freezeLock=%p, swapState=0x%08x\n",
l->pixelFormat(),
- buf0.width(), buf0.height(), buf0.stride(),
- buf1.width(), buf1.height(), buf1.stride(),
- l->getTextureName(), l->getFreezeLock().get(),
+ buf0.getWidth(), buf0.getHeight(),
+ buf0.getBuffer()->getStride(),
+ buf1.getWidth(), buf1.getHeight(),
+ buf1.getBuffer()->getStride(),
+ l->getFreezeLock().get(),
l->lcblk->swapState);
}
result.append(buffer);
@@ -1523,20 +1530,10 @@
mFreezeDisplay?"yes":"no", mFreezeCount,
mCurrentState.orientation, hw.canDraw());
result.append(buffer);
-
- sp<AllocatorInterface> allocator;
- if (mGPU != 0) {
- snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
- result.append(buffer);
- allocator = mGPU->getAllocator();
- if (allocator != 0) {
- allocator->dump(result, "GPU Allocator");
- }
- }
- allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
- if (allocator != 0) {
- allocator->dump(result, "PMEM Allocator");
- }
+ snprintf(buffer, SIZE, " client count: %d\n", mClientsMap.size());
+ result.append(buffer);
+ const BufferAllocator& alloc(BufferAllocator::get());
+ alloc.dump(result);
}
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -1553,57 +1550,34 @@
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
- case REVOKE_GPU:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
+ if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
}
}
}
-
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ if (UNLIKELY(!mHardwareTest.checkCalling())) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
int n;
switch (code) {
- case 1000: // SHOW_CPU
- n = data.readInt32();
- mDebugCpu = n ? 1 : 0;
- if (mDebugCpu) {
- if (mCpuGauge == 0) {
- mCpuGauge = new CPUGauge(this, ms2ns(500));
- }
- } else {
- if (mCpuGauge != 0) {
- mCpuGauge->requestExitAndWait();
- Mutex::Autolock _l(mDebugLock);
- mCpuGauge.clear();
- }
- }
+ case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
return NO_ERROR;
- case 1001: // SHOW_FPS
- n = data.readInt32();
- mDebugFps = n ? 1 : 0;
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
return NO_ERROR;
case 1002: // SHOW_UPDATES
n = data.readInt32();
@@ -1620,21 +1594,11 @@
signalEvent();
}
return NO_ERROR;
- case 1005: // ask GPU revoke
- if (mGPU != 0) {
- mGPU->friendlyRevoke();
- }
- return NO_ERROR;
- case 1006: // revoke GPU
- if (mGPU != 0) {
- mGPU->unconditionalRevoke();
- }
- return NO_ERROR;
case 1007: // set mFreezeCount
mFreezeCount = data.readInt32();
return NO_ERROR;
case 1010: // interrogate.
- reply->writeInt32(mDebugCpu);
+ reply->writeInt32(0);
reply->writeInt32(0);
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
@@ -1658,16 +1622,15 @@
Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
{
- mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
const int pgsize = getpagesize();
- const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
- mCblkHeap = new MemoryDealer(cblksize);
- mCblkMemory = mCblkHeap->allocate(cblksize);
- if (mCblkMemory != 0) {
- ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
- if (ctrlblk) { // construct the shared structure in-place.
- new(ctrlblk) per_client_cblk_t;
- }
+ const int cblksize = ((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+
+ mCblkHeap = new MemoryHeapBase(cblksize, 0,
+ "SurfaceFlinger Client control-block");
+
+ ctrlblk = static_cast<per_client_cblk_t *>(mCblkHeap->getBase());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) per_client_cblk_t;
}
}
@@ -1678,10 +1641,6 @@
}
}
-const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
- return mFlinger->getSurfaceHeapManager();
-}
-
int32_t Client::generateId(int pid)
{
const uint32_t i = clz( ~mBitmap );
@@ -1693,13 +1652,15 @@
mBitmap |= 1<<(31-i);
return i;
}
-status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+
+status_t Client::bindLayer(const sp<LayerBaseClient>& layer, int32_t id)
{
ssize_t idx = mInUse.indexOf(id);
if (idx < 0)
return NAME_NOT_FOUND;
return mLayers.insertAt(layer, idx);
}
+
void Client::free(int32_t id)
{
ssize_t idx = mInUse.remove(uint8_t(id));
@@ -1709,27 +1670,18 @@
}
}
-sp<MemoryDealer> Client::createAllocator(uint32_t flags)
-{
- sp<MemoryDealer> allocator;
- allocator = getSurfaceHeapManager()->createHeap(
- flags, getClientPid(), mSharedHeapAllocator);
- return allocator;
-}
-
bool Client::isValid(int32_t i) const {
return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
}
-const uint8_t* Client::inUseArray() const {
- return mInUse.array();
-}
-size_t Client::numActiveLayers() const {
- return mInUse.size();
-}
-LayerBaseClient* Client::getLayerUser(int32_t i) const {
+
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+ sp<LayerBaseClient> lbc;
ssize_t idx = mInUse.indexOf(uint8_t(i));
- if (idx<0) return 0;
- return mLayers[idx];
+ if (idx >= 0) {
+ lbc = mLayers[idx].promote();
+ LOGE_IF(lbc==0, "getLayerUser(i=%d), idx=%d is dead", int(i), int(idx));
+ }
+ return lbc;
}
void Client::dump(const char* what)
@@ -1741,7 +1693,7 @@
#pragma mark -
#endif
-BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk)
: mId(cid), mFlinger(flinger), mCblk(cblk)
{
}
@@ -1751,8 +1703,8 @@
mFlinger->destroyConnection(mId);
}
-void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
- *ctrl = mCblk;
+sp<IMemoryHeap> BClient::getControlBlock() const {
+ return mCblk;
}
sp<ISurface> BClient::createSurface(
@@ -1766,7 +1718,7 @@
status_t BClient::destroySurface(SurfaceID sid)
{
sid |= (mId << 16); // add the client-part to id
- return mFlinger->destroySurface(sid);
+ return mFlinger->removeSurface(sid);
}
status_t BClient::setState(int32_t count, const layer_state_t* states)
@@ -1866,6 +1818,10 @@
return mGlobalTransform;
}
+EGLDisplay GraphicPlane::getEGLDisplay() const {
+ return mHw->getEGLDisplay();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 0d63e1d..2569a0f 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -25,7 +25,10 @@
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
-#include <utils/MemoryDealer.h>
+#include <utils/RefBase.h>
+
+#include <binder/IMemory.h>
+#include <binder/Permission.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceComposer.h>
@@ -33,13 +36,13 @@
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
-#include <private/ui/SurfaceFlingerSynchro.h>
#include "Barrier.h"
-#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
+#include "MessageQueue.h"
+
struct copybit_device_t;
struct overlay_device_t;
@@ -51,13 +54,8 @@
class BClient;
class DisplayHardware;
class FreezeLock;
-class GPUHardwareInterface;
-class IGPUCallback;
class Layer;
class LayerBuffer;
-class LayerOrientationAnim;
-class OrientationAnimation;
-class SurfaceHeapManager;
typedef int32_t ClientID;
@@ -66,7 +64,7 @@
// ---------------------------------------------------------------------------
-class Client
+class Client : public RefBase
{
public:
Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
@@ -74,17 +72,19 @@
int32_t generateId(int pid);
void free(int32_t id);
- status_t bindLayer(LayerBaseClient* layer, int32_t id);
- sp<MemoryDealer> createAllocator(uint32_t memory_type);
+ status_t bindLayer(const sp<LayerBaseClient>& layer, int32_t id);
inline bool isValid(int32_t i) const;
- inline const uint8_t* inUseArray() const;
- inline size_t numActiveLayers() const;
- LayerBaseClient* getLayerUser(int32_t i) const;
- const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
- const sp<IMemory>& controlBlockMemory() const { return mCblkMemory; }
+ sp<LayerBaseClient> getLayerUser(int32_t i) const;
void dump(const char* what);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const;
+
+ const Vector< wp<LayerBaseClient> >& getLayers() const {
+ return mLayers;
+ }
+
+ const sp<IMemoryHeap>& getControlBlockMemory() const {
+ return mCblkHeap;
+ }
// pointer to this client's control block
per_client_cblk_t* ctrlblk;
@@ -92,17 +92,14 @@
private:
- int getClientPid() const { return mPid; }
+ int getClientPid() const { return mPid; }
- int mPid;
- uint32_t mBitmap;
- SortedVector<uint8_t> mInUse;
- Vector<LayerBaseClient*> mLayers;
- sp<MemoryDealer> mCblkHeap;
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mSharedHeapAllocator;
- sp<MemoryDealer> mPMemAllocator;
- sp<IMemory> mCblkMemory;
+ int mPid;
+ uint32_t mBitmap;
+ SortedVector<uint8_t> mInUse;
+ Vector< wp<LayerBaseClient> > mLayers;
+ sp<IMemoryHeap> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
};
// ---------------------------------------------------------------------------
@@ -125,6 +122,8 @@
const DisplayHardware& displayHardware() const;
const Transform& transform() const;
+ EGLDisplay getEGLDisplay() const;
+
private:
GraphicPlane(const GraphicPlane&);
GraphicPlane operator = (const GraphicPlane&);
@@ -160,7 +159,7 @@
// ISurfaceComposer interface
virtual sp<ISurfaceFlingerClient> createConnection();
- virtual sp<IMemory> getCblk() const;
+ virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
virtual void openGlobalTransaction();
virtual void closeGlobalTransaction();
@@ -168,56 +167,52 @@
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
- virtual status_t requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu);
- virtual status_t revokeGPU();
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const {
- return mSurfaceHeapManager;
- }
-
- const sp<GPUHardwareInterface>& getGPU() const {
- return mGPU;
- }
-
- copybit_device_t* getBlitEngine() const;
overlay_control_device_t* getOverlayEngine() const;
- status_t removeLayer(LayerBase* layer);
- status_t addLayer(LayerBase* layer);
- status_t invalidateLayerVisibility(LayerBase* layer);
+ status_t removeLayer(const sp<LayerBase>& layer);
+ status_t addLayer(const sp<LayerBase>& layer);
+ status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
private:
friend class BClient;
friend class LayerBase;
friend class LayerBuffer;
friend class LayerBaseClient;
+ friend class LayerBaseClient::Surface;
friend class Layer;
friend class LayerBlur;
+ friend class LayerDim;
sp<ISurface> createSurface(ClientID client, int pid,
ISurfaceFlingerClient::surface_data_t* params,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags);
- LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ sp<LayerBaseClient> createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags);
- LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- status_t destroySurface(SurfaceID surface_id);
- status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+ status_t removeSurface(SurfaceID surface_id);
+ status_t destroySurface(const sp<LayerBaseClient>& layer);
+ status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
class LayerVector {
@@ -225,15 +220,15 @@
inline LayerVector() { }
LayerVector(const LayerVector&);
inline size_t size() const { return layers.size(); }
- inline LayerBase*const* array() const { return layers.array(); }
- ssize_t add(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t remove(LayerBase*);
- ssize_t reorder(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t indexOf(LayerBase* key, size_t guess=0) const;
- inline LayerBase* operator [] (size_t i) const { return layers[i]; }
+ inline sp<LayerBase> const* array() const { return layers.array(); }
+ ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t remove(const sp<LayerBase>&);
+ ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const;
+ inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
private:
- KeyedVector<LayerBase*, size_t> lookup;
- Vector<LayerBase*> layers;
+ KeyedVector< sp<LayerBase> , size_t> lookup;
+ Vector< sp<LayerBase> > layers;
};
struct State {
@@ -247,25 +242,6 @@
uint8_t freezeDisplay;
};
- class DelayedTransaction : public Thread
- {
- friend class SurfaceFlinger;
- sp<SurfaceFlinger> mFlinger;
- nsecs_t mDelay;
- public:
- DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
- : Thread(false), mFlinger(flinger), mDelay(delay) {
- }
- virtual bool threadLoop() {
- usleep(mDelay / 1000);
- if (android_atomic_and(~1,
- &mFlinger->mDeplayedTransactionPending) == 1) {
- mFlinger->signalEvent();
- }
- return false;
- }
- };
-
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
@@ -279,6 +255,9 @@
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(
+ uint32_t transactionFlags,
+ Vector< sp<LayerBase> >& ditchedLayers);
void computeVisibleRegions(
LayerVector& currentLayers,
@@ -289,8 +268,7 @@
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRepaint();
- void handleDebugCpu();
- void scheduleBroadcast(Client* client);
+ void scheduleBroadcast(const sp<Client>& client);
void executeScheduledBroadcasts();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
@@ -298,10 +276,10 @@
void destroyConnection(ClientID cid);
- LayerBaseClient* getLayerUser_l(SurfaceID index) const;
- status_t addLayer_l(LayerBase* layer);
- status_t removeLayer_l(LayerBase* layer);
- void destroy_all_removed_layers_l();
+ sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const;
+ status_t addLayer_l(const sp<LayerBase>& layer);
+ status_t removeLayer_l(const sp<LayerBase>& layer);
+ status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
void free_resources_l();
uint32_t getTransactionFlags(uint32_t flags);
@@ -323,6 +301,11 @@
void debugShowFPS() const;
void drawWormhole() const;
+
+ mutable MessageQueue mEventQueue;
+
+
+
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState;
@@ -330,23 +313,23 @@
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
-
+
// protected by mStateLock (but we could use another lock)
Tokenizer mTokens;
- DefaultKeyedVector<ClientID, Client*> mClientsMap;
- DefaultKeyedVector<SurfaceID, LayerBaseClient*> mLayerMap;
+ DefaultKeyedVector<ClientID, sp<Client> > mClientsMap;
+ DefaultKeyedVector<SurfaceID, sp<LayerBaseClient> > mLayerMap;
GraphicPlane mGraphicPlanes[1];
- SortedVector<LayerBase*> mRemovedLayers;
- Vector<Client*> mDisconnectedClients;
+ bool mLayersRemoved;
+ Vector< sp<Client> > mDisconnectedClients;
// constant members (no synchronization needed for access)
- sp<MemoryDealer> mServerHeap;
- sp<IMemory> mServerCblkMemory;
+ sp<IMemoryHeap> mServerHeap;
surface_flinger_cblk_t* mServerCblk;
- sp<SurfaceHeapManager> mSurfaceHeapManager;
- sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
nsecs_t mBootTime;
+ Permission mHardwareTest;
+ Permission mAccessSurfaceFlinger;
+ Permission mDump;
// Can only accessed from the main thread, these members
// don't need synchronization
@@ -354,30 +337,20 @@
Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
Region mWormholeRegion;
- Client* mLastScheduledBroadcast;
- SortedVector<Client*> mScheduledBroadcasts;
+ wp<Client> mLastScheduledBroadcast;
+ SortedVector< wp<Client> > mScheduledBroadcasts;
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
- friend class OrientationAnimation;
- OrientationAnimation* mOrientationAnimation;
-
- // access protected by mDebugLock
- mutable Mutex mDebugLock;
- sp<CPUGauge> mCpuGauge;
// don't use a lock for these, we don't care
int mDebugRegion;
- int mDebugCpu;
- int mDebugFps;
int mDebugBackground;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
- mutable SurfaceFlingerSynchro mSyncObject;
- volatile int32_t mDeplayedTransactionPending;
// atomic variables
enum {
@@ -410,11 +383,11 @@
{
public:
BClient(SurfaceFlinger *flinger, ClientID cid,
- const sp<IMemory>& cblk);
+ const sp<IMemoryHeap>& cblk);
~BClient();
// ISurfaceFlingerClient interface
- virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+ virtual sp<IMemoryHeap> getControlBlock() const;
virtual sp<ISurface> createSurface(
surface_data_t* params, int pid,
@@ -427,7 +400,7 @@
private:
ClientID mId;
SurfaceFlinger* mFlinger;
- sp<IMemory> mCblk;
+ sp<IMemoryHeap> mCblk;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
index ef51d6a..be3a239 100644
--- a/libs/surfaceflinger/Tokenizer.cpp
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -162,9 +162,10 @@
{
const run_t* ranges = mRanges.array();
const size_t c = mRanges.size();
- printf("Tokenizer (%p, size = %lu)\n", this, c);
+ printf("Tokenizer (%p, size = %d)\n", this, int(c));
for (size_t i=0 ; i<c ; i++) {
- printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ printf("%u: (%u, %u)\n", i,
+ uint32_t(ranges[i].first), uint32_t(ranges[i].length));
}
}
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index e8b0f45..1501536 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -177,10 +177,10 @@
Region out;
if (UNLIKELY(transformed())) {
if (LIKELY(preserveRects())) {
- Rect r;
- Region::iterator iterator(reg);
- while (iterator.iterate(&r)) {
- out.orSelf(transform(r));
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ while (it != end) {
+ out.orSelf(transform(*it++));
}
} else {
out.set(transform(reg.bounds()));
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
deleted file mode 100644
index 5f633bd..0000000
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ /dev/null
@@ -1,178 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-
-#include <EGL/eglnatives.h>
-
-#include "GPUHardware/GPUHardware.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-/*
- * Amount of memory we reserve for surface, per client in PMEM
- * (PMEM is used for 2D acceleration)
- * 8 MB of address space per client should be enough.
- */
-static const int PMEM_SIZE = int(8 * 1024 * 1024);
-
-int SurfaceHeapManager::global_pmem_heap = 0;
-
-// ---------------------------------------------------------------------------
-
-SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
- size_t clientHeapSize)
- : mFlinger(flinger), mClientHeapSize(clientHeapSize)
-{
- SurfaceHeapManager::global_pmem_heap = 1;
-}
-
-SurfaceHeapManager::~SurfaceHeapManager()
-{
-}
-
-void SurfaceHeapManager::onFirstRef()
-{
- if (global_pmem_heap) {
- const char* device = "/dev/pmem";
- mPMemHeap = new PMemHeap(device, PMEM_SIZE);
- if (mPMemHeap->base() == MAP_FAILED) {
- mPMemHeap.clear();
- global_pmem_heap = 0;
- }
- }
-}
-
-sp<MemoryDealer> SurfaceHeapManager::createHeap(
- uint32_t flags,
- pid_t client_pid,
- const sp<MemoryDealer>& defaultAllocator)
-{
- sp<MemoryDealer> dealer;
-
- if (flags & ISurfaceComposer::eGPU) {
- // don't grant GPU memory if GPU is disabled
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) == 0) {
- flags &= ~ISurfaceComposer::eGPU;
- }
- }
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
- if (!(flags & ISurfaceComposer::eSecure)) {
- // if GPU doesn't work, we try eHardware
- flags |= ISurfaceComposer::eHardware;
- // asked for GPU memory, try that first
- dealer = mFlinger->getGPU()->request(client_pid);
- }
- }
-
- if (dealer == NULL) {
- if (defaultAllocator != NULL)
- // if a default allocator is given, use that
- dealer = defaultAllocator;
- }
-
- if (dealer == NULL) {
- // always try h/w accelerated memory first
- if (global_pmem_heap) {
- const sp<PMemHeap>& heap(mPMemHeap);
- if (dealer == NULL && heap != NULL) {
- dealer = new MemoryDealer(
- heap->createClientHeap(),
- heap->getAllocator());
- }
- }
- }
-
- if (dealer == NULL) {
- // return the ashmem allocator (software rendering)
- dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
- }
- return dealer;
-}
-
-sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
-{
- Mutex::Autolock _l(mLock);
- sp<SimpleBestFitAllocator> allocator;
-
- // this is only used for debugging
- switch (type) {
- case NATIVE_MEMORY_TYPE_PMEM:
- if (mPMemHeap != 0) {
- allocator = mPMemHeap->getAllocator();
- }
- break;
- }
- return allocator;
-}
-
-// ---------------------------------------------------------------------------
-
-PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
- : MemoryHeapBase(device, size)
-{
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
- if (base() != MAP_FAILED) {
- //LOGD("%s, %u bytes", device, virtualSize());
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
-}
-
-PMemHeap::~PMemHeap() {
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
-}
-
-sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapPmem(parentHeap);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
new file mode 100644
index 0000000..2de628b
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
@@ -0,0 +1,585 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <binder/IBinder.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IPCThreadState.h>
+#include <utils/StopWatch.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include "VRamHeap.h"
+#include "GPUHardware.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include "GPUHardware/GPUHardware.h"
+
+
+/*
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here.
+ *
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
+ *
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
+ *
+ */
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+ static const int GPU_RESERVED_SIZE;
+ static const int GPUR_SIZE;
+
+ GPUHardware();
+ virtual ~GPUHardware();
+
+ virtual void revoke(int pid);
+ virtual sp<MemoryDealer> request(int pid);
+ virtual status_t request(int pid,
+ const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu);
+
+ virtual status_t friendlyRevoke();
+ virtual void unconditionalRevoke();
+
+ virtual pid_t getOwner() const { return mOwner; }
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+
+
+ enum {
+ NO_OWNER = -1,
+ };
+
+ struct GPUArea {
+ sp<GPUAreaHeap> heap;
+ sp<MemoryHeapPmem> clientHeap;
+ sp<IMemory> map();
+ };
+
+ struct Client {
+ pid_t pid;
+ GPUArea smi;
+ GPUArea ebi;
+ GPUArea reg;
+ void createClientHeaps();
+ void revokeAllHeaps();
+ };
+
+ Client& getClientLocked(pid_t pid);
+ status_t requestLocked(int pid);
+ void releaseLocked();
+ void takeBackGPULocked();
+ void registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client);
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ mutable Mutex mLock;
+ sp<GPUAreaHeap> mSMIHeap;
+ sp<GPUAreaHeap> mEBIHeap;
+ sp<GPUAreaHeap> mREGHeap;
+
+ KeyedVector<pid_t, Client> mClients;
+ DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+
+ pid_t mOwner;
+
+ sp<MemoryDealer> mCurrentAllocator;
+ sp<IGPUCallback> mCallback;
+
+ sp<SimpleBestFitAllocator> mAllocator;
+
+ Condition mCondition;
+};
+
+// size reserved for GPU surfaces
+// 1200 KB fits exactly:
+// - two 320*480 16-bits double-buffered surfaces
+// - one 320*480 32-bits double-buffered surface
+// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
+
+// ---------------------------------------------------------------------------
+
+/*
+ * GPUHandle is a special IMemory given to the client. It represents their
+ * handle to the GPU. Once they give it up, they loose GPU access, or if
+ * they explicitly revoke their access through the binder code 1000.
+ * In both cases, this triggers a callback to revoke()
+ * first, and then actually powers down the chip.
+ *
+ * In the case of a misbehaving app, GPUHardware can ask for an immediate
+ * release of the GPU to the target process which should answer by calling
+ * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
+ * be revoked from under their feet.
+ *
+ * We should never hold a strong reference on GPUHandle. In practice this
+ * shouldn't be a big issue though because clients should use code 1000 and
+ * not rely on the dtor being called.
+ *
+ */
+
+class GPUClientHeap : public MemoryHeapPmem
+{
+public:
+ GPUClientHeap(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+ GPUAreaHeap(const wp<GPUHardware>& gpu,
+ const char* const vram, size_t size=0, size_t reserved=0)
+ : MemoryHeapBase(vram, size), mGPU(gpu) {
+ if (base() != MAP_FAILED) {
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new GPUClientHeap(mGPU, parentHeap);
+ }
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
+private:
+ sp<SimpleBestFitAllocator> mAllocator;
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+ GPURegisterHeap(const sp<GPUHardware>& gpu)
+ : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapRegs(mGPU, parentHeap);
+ }
+private:
+ class MemoryHeapRegs : public GPUClientHeap {
+ public:
+ MemoryHeapRegs(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : GPUClientHeap(gpu, heap) { }
+ sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+ virtual void revoke();
+ private:
+ class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+ public:
+ GPUHandle(const sp<GPUHardware>& gpu,
+ const sp<MemoryHeapPmem>& heap)
+ : MemoryHeapPmem::MemoryPmem(heap),
+ mGPU(gpu), mOwner(gpu->getOwner()) { }
+ virtual ~GPUHandle();
+ virtual sp<IMemoryHeap> getMemory(
+ ssize_t* offset, size_t* size) const;
+ virtual void revoke() { };
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ private:
+ void revokeNotification();
+ wp<GPUHardware> mGPU;
+ pid_t mOwner;
+ };
+ };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
+ //LOGD("GPUHandle %p released, revoking GPU", this);
+ revokeNotification();
+}
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
+ sp<GPUHardware> hw(mGPU.promote());
+ if (hw != 0) {
+ hw->revoke(mOwner);
+ }
+}
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ sp<MemoryHeapPmem> heap = getHeap();
+ if (offset) *offset = 0;
+ if (size) *size = heap !=0 ? heap->virtualSize() : 0;
+ return heap;
+}
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ status_t err = BnMemory::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION && code == 1000) {
+ int callingPid = IPCThreadState::self()->getCallingPid();
+ //LOGD("pid %d voluntarily revoking gpu", callingPid);
+ if (callingPid == mOwner) {
+ revokeNotification();
+ // we've revoked the GPU, don't do it again later when we
+ // are destroyed.
+ mGPU.clear();
+ } else {
+ LOGW("%d revoking someone else's gpu? (owner=%d)",
+ callingPid, mOwner);
+ }
+ err = NO_ERROR;
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+ size_t offset, size_t size)
+{
+ sp<GPUHandle> memory;
+ sp<GPUHardware> gpu = mGPU.promote();
+ if (heapID()>0 && gpu!=0) {
+#if HAVE_ANDROID_OS
+ /* this is where the GPU is powered on and the registers are mapped
+ * in the client */
+ //LOGD("ioctl(HW3D_GRANT_GPU)");
+ int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
+ if (err) {
+ // it can happen if the master heap has been closed already
+ // in which case the GPU already is revoked (app crash for
+ // instance).
+ LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+ memory = new GPUHandle(gpu, this);
+#endif
+ }
+ return memory;
+}
+
+void GPURegisterHeap::MemoryHeapRegs::revoke()
+{
+ MemoryHeapPmem::revoke();
+#if HAVE_ANDROID_OS
+ if (heapID() > 0) {
+ //LOGD("ioctl(HW3D_REVOKE_GPU)");
+ int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
+ LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+#endif
+}
+
+/*****************************************************************************/
+
+GPUHardware::GPUHardware()
+ : mOwner(NO_OWNER)
+{
+}
+
+GPUHardware::~GPUHardware()
+{
+}
+
+status_t GPUHardware::requestLocked(int pid)
+{
+ const int self_pid = getpid();
+ if (pid == self_pid) {
+ // can't use GPU from surfaceflinger's process
+ return PERMISSION_DENIED;
+ }
+
+ if (mOwner != pid) {
+ if (mREGHeap != 0) {
+ if (mOwner != NO_OWNER) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+ releaseLocked();
+ }
+ } else {
+ // first time, initialize the stuff.
+ if (mSMIHeap == 0)
+ mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+ if (mEBIHeap == 0)
+ mEBIHeap = new GPUAreaHeap(this,
+ "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+ mREGHeap = new GPURegisterHeap(this);
+ mAllocator = mEBIHeap->getAllocator();
+ if (mAllocator == NULL) {
+ // something went terribly wrong.
+ mSMIHeap.clear();
+ mEBIHeap.clear();
+ mREGHeap.clear();
+ return INVALID_OPERATION;
+ }
+ }
+ Client& client = getClientLocked(pid);
+ mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+ mOwner = pid;
+ }
+ return NO_ERROR;
+}
+
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+ sp<MemoryDealer> dealer;
+ Mutex::Autolock _l(mLock);
+ Client* client;
+ LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+ if (requestLocked(pid) == NO_ERROR) {
+ dealer = mCurrentAllocator;
+ LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+ }
+ return dealer;
+}
+
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu)
+{
+ if (callback == 0)
+ return BAD_VALUE;
+
+ sp<IMemory> gpuHandle;
+ LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+ Mutex::Autolock _l(mLock);
+ status_t err = requestLocked(pid);
+ if (err == NO_ERROR) {
+ // it's guaranteed to be there, be construction
+ Client& client = mClients.editValueFor(pid);
+ registerCallbackLocked(callback, client);
+ gpu->count = 2;
+ gpu->regions[0].region = client.smi.map();
+ gpu->regions[1].region = client.ebi.map();
+ gpu->regs = client.reg.map();
+ gpu->regions[0].reserved = 0;
+ gpu->regions[1].reserved = GPU_RESERVED_SIZE;
+ if (gpu->regs != 0) {
+ //LOGD("gpu core granted to pid %d, handle base=%p",
+ // mOwner, gpu->regs->pointer());
+ }
+ mCallback = callback;
+ } else {
+ LOGW("couldn't grant gpu core to pid %d", pid);
+ }
+ return err;
+}
+
+void GPUHardware::revoke(int pid)
+{
+ Mutex::Autolock _l(mLock);
+ if (mOwner > 0) {
+ if (pid != mOwner) {
+ LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
+ return;
+ }
+ //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
+ // mOwner could be <0 if the same process acquired the GPU
+ // several times without releasing it first.
+ mCondition.signal();
+ releaseLocked();
+ }
+}
+
+status_t GPUHardware::friendlyRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ //LOGD("friendlyRevoke owner=%d", mOwner);
+ takeBackGPULocked();
+ releaseLocked();
+ return NO_ERROR;
+}
+
+void GPUHardware::takeBackGPULocked()
+{
+ sp<IGPUCallback> callback = mCallback;
+ mCallback.clear();
+ if (callback != 0) {
+ callback->gpuLost(); // one-way
+ mCondition.waitRelative(mLock, ms2ns(250));
+ }
+}
+
+void GPUHardware::releaseLocked()
+{
+ //LOGD("revoking gpu from pid %d", mOwner);
+ if (mOwner != NO_OWNER) {
+ // this may fail because the client might have died, and have
+ // been removed from the list.
+ ssize_t index = mClients.indexOfKey(mOwner);
+ if (index >= 0) {
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps();
+ }
+ mOwner = NO_OWNER;
+ mCurrentAllocator.clear();
+ mCallback.clear();
+ }
+}
+
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
+{
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index < 0) {
+ Client client;
+ client.pid = pid;
+ client.smi.heap = mSMIHeap;
+ client.ebi.heap = mEBIHeap;
+ client.reg.heap = mREGHeap;
+ index = mClients.add(pid, client);
+ }
+ Client& client(mClients.editValueAt(index));
+ client.createClientHeaps();
+ return client;
+}
+
+// ----------------------------------------------------------------------------
+// for debugging / testing ...
+
+sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
+ Mutex::Autolock _l(mLock);
+ return mAllocator;
+}
+
+void GPUHardware::unconditionalRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ releaseLocked();
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IMemory> GPUHardware::GPUArea::map() {
+ sp<IMemory> memory;
+ if (clientHeap != 0 && heap != 0) {
+ memory = clientHeap->mapMemory(0, heap->virtualSize());
+ }
+ return memory;
+}
+
+void GPUHardware::Client::createClientHeaps()
+{
+ if (smi.clientHeap == 0)
+ smi.clientHeap = smi.heap->createClientHeap();
+ if (ebi.clientHeap == 0)
+ ebi.clientHeap = ebi.heap->createClientHeap();
+ if (reg.clientHeap == 0)
+ reg.clientHeap = reg.heap->createClientHeap();
+}
+
+void GPUHardware::Client::revokeAllHeaps()
+{
+ if (smi.clientHeap != 0)
+ smi.clientHeap->revoke();
+ if (ebi.clientHeap != 0)
+ ebi.clientHeap->revoke();
+ if (reg.clientHeap != 0)
+ reg.clientHeap->revoke();
+}
+
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client)
+{
+ sp<IBinder> binder = callback->asBinder();
+ if (mRegisteredClients.add(binder, client.pid) >= 0) {
+ binder->linkToDeath(this);
+ }
+}
+
+void GPUHardware::binderDied(const wp<IBinder>& who)
+{
+ Mutex::Autolock _l(mLock);
+ pid_t pid = mRegisteredClients.valueFor(who);
+ if (pid != 0) {
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index >= 0) {
+ //LOGD("*** removing client at %d", index);
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps(); // not really needed in theory
+ mClients.removeItemsAt(index);
+ if (mClients.size() == 0) {
+ //LOGD("*** was last client closing everything");
+ mCallback.clear();
+ mAllocator.clear();
+ mCurrentAllocator.clear();
+ mSMIHeap.clear();
+ mREGHeap.clear();
+
+ // NOTE: we cannot clear the EBI heap because surfaceflinger
+ // itself may be using it, since this is where surfaces
+ // are allocated. if we're in the middle of compositing
+ // a surface (even if its process just died), we cannot
+ // rip the heap under our feet.
+
+ mOwner = NO_OWNER;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
+{
+ sp<GPUHardwareInterface> gpu;
+ if (access("/dev/hw3d", F_OK) == 0) {
+ gpu = new GPUHardware();
+ }
+ return gpu;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
similarity index 100%
rename from libs/surfaceflinger/GPUHardware/GPUHardware.h
rename to libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..41c42d1
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/StopWatch.h>
+
+#include "BlurFilter.h"
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+// Animation...
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.5f;
+//const float BOUNCES_AMPLITUDE = 1.0f/16.0f;
+const float BOUNCES_AMPLITUDE = 0;
+const float DIM_TARGET = 0.40f;
+//#define INTERPOLATED_TIME(_t) ((_t)*(_t))
+#define INTERPOLATED_TIME(_t) (_t)
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ // blur that texture.
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mNeedsBlending = false;
+ mAlphaInLerp.set(1.0f, DIM_TARGET);
+ mAlphaOutLerp.set(0.5f, 1.0f);
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ const nsecs_t now = systemTime();
+ float alphaIn, alphaOut;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapOut->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp(interpolatedTime);
+ } else {
+ mAnim->onAnimationFinished();
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp.getOut();
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp(interpolatedTime);
+ alphaOut = 0.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ alphaIn = mAlphaInLerp.getOut();
+ if (BOUNCES_AMPLITUDE > 0.0f) {
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ if (alphaIn > 1.0f) alphaIn = 1.0f;
+ else if (alphaIn < 0.0f) alphaIn = 0.0f;
+ alphaIn += BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ }
+ alphaOut = 0.0f;
+ }
+ mAlphaOutLerp.setIn(alphaIn);
+ }
+ drawScaled(1.0f, alphaIn, alphaOut);
+}
+
+void LayerOrientationAnim::drawScaled(float scale, float alphaIn, float alphaOut) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ if (scale==1.0f && (alphaIn>=1.0f || alphaOut>=1.0f)) {
+ // we don't need to erase the screen in that case
+ } else {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+
+ copybit_image_t srcOut;
+ mBitmapOut->getBitmapSurface(&srcOut);
+
+ const int w = dst.w*scale;
+ const int h = dst.h*scale;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+ const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(scale,0,0,scale);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alphaIn > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaIn*255);
+ drawWithOpenGL(reg, mTextureNameIn, t);
+ }
+
+ if (alphaOut > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(srcOut.base) + srcOut.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaOut*255);
+ drawWithOpenGL(reg, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.h b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
new file mode 100644
index 0000000..a1a2654
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <binder/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+
+class LayerOrientationAnimBase : public LayerBase
+{
+public:
+ LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
+ : LayerBase(flinger, display) {
+ }
+ virtual void onOrientationCompleted() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class LayerOrientationAnim : public LayerOrientationAnimBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float scale, float alphaIn, float alphaOut) const;
+
+ class Lerp {
+ float in;
+ float outMinusIn;
+ public:
+ Lerp() : in(0), outMinusIn(0) { }
+ Lerp(float in, float out) : in(in), outMinusIn(out-in) { }
+ float getIn() const { return in; };
+ float getOut() const { return in + outMinusIn; }
+ void set(float in, float out) {
+ this->in = in;
+ this->outMinusIn = out-in;
+ }
+ void setIn(float in) {
+ this->in = in;
+ }
+ void setOut(float out) {
+ this->outMinusIn = out - this->in;
+ }
+ float operator()(float t) const {
+ return outMinusIn*t + in;
+ }
+ };
+
+ OrientationAnimation* mAnim;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+
+ mutable Lerp mAlphaInLerp;
+ mutable Lerp mAlphaOutLerp;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
new file mode 100644
index 0000000..dc6b632
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
+const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
+
+// ---------------------------------------------------------------------------
+
+const float ROTATION = M_PI * 0.5f;
+const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.8;
+const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
+
+LayerOrientationAnimRotate::LayerOrientationAnimRotate(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastAngle = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+ const GraphicPlane& plane(graphicPlane(0));
+ mOriginalTargetOrientation = plane.getOrientation();
+}
+
+LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnimRotate::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnimRotate::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnimRotate::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnimRotate::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnimRotate::onDraw(const Region& clip) const
+{
+ // Animation...
+
+ const nsecs_t now = systemTime();
+ float angle, scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // FIXME: code below is gross
+ mFirstRedraw = false;
+ mNeedsBlending = false;
+ LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = normalizedTime;
+ } else {
+ mAnim->onAnimationFinished();
+ angle = ROTATION;
+ alpha = 1.0f;
+ scale = 1.0f;
+ }
+ } else {
+ // FIXME: works only for portrait framebuffers
+ const Point size(getPhysicalSize());
+ const float TARGET_SCALE = size.x * (1.0f / size.y);
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = ROTATION * squaredTime;
+ scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
+ alpha = 0;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ angle = ROTATION;
+ if (BOUNCES_AMPLITUDE) {
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ angle += BOUNCES_AMPLITUDE * sinf(phi);
+ }
+ scale = TARGET_SCALE;
+ alpha = 0;
+ }
+ mLastAngle = angle;
+ mLastScale = scale;
+ }
+ drawScaled(angle, scale, alpha);
+}
+
+void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ const int w = dst.w;
+ const int h = dst.h;
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ if (!mOriginalTargetOrientation) {
+ f = -f;
+ }
+
+ Transform tr;
+ tr.set(f, w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = 255; //-int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+
+ if (alpha > 0) {
+ const float sign = (!mOriginalTargetOrientation) ? 1.0f : -1.0f;
+ tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureNameIn, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
new file mode 100644
index 0000000..a88eec0
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <binder/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnimRotate : public LayerOrientationAnimBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnimRotate(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnimRotate();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float angle, float scale, float alpha) const;
+
+ OrientationAnimation* mAnim;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ int mOriginalTargetOrientation;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastAngle;
+ mutable float mLastScale;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
diff --git a/libs/surfaceflinger/purgatory/OrientationAnimation.cpp b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
new file mode 100644
index 0000000..a6c9c28
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged(uint32_t type)
+{
+ if (mState == DONE) {
+ mType = type;
+ if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
+ mState = PREPARE;
+ }
+ }
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+ if (mState != DONE)
+ mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+ bool skip_frame;
+ switch (mState) {
+ default:
+ case DONE:
+ skip_frame = done();
+ break;
+ case PREPARE:
+ skip_frame = prepare();
+ break;
+ case PHASE1:
+ skip_frame = phase1();
+ break;
+ case PHASE2:
+ skip_frame = phase2();
+ break;
+ case FINISH:
+ skip_frame = finished();
+ break;
+ }
+ return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+ return done_impl();
+}
+
+bool OrientationAnimation::prepare()
+{
+ mState = PHASE1;
+
+ const GraphicPlane& plane(mFlinger->graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+
+ sp<Buffer> bitmap = new Buffer(w, h, hw.getFormat());
+ sp<Buffer> bitmapIn = new Buffer(w, h, hw.getFormat());
+
+ copybit_image_t front;
+ bitmap->getBitmapSurface(&front);
+ hw.copyFrontToImage(front); // FIXME: we need an extension to do this
+
+ sp<LayerOrientationAnimBase> l;
+
+ if (mType & 0x80) {
+ l = new LayerOrientationAnimRotate(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ } else {
+ l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ }
+
+ l->initStates(w, h, 0);
+ l->setLayer(INT_MAX-1);
+ mFlinger->addLayer(l);
+ mLayerOrientationAnim = l;
+ return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+ if (mFlinger->isFrozen() == false) {
+ // start phase 2
+ mState = PHASE2;
+ mLayerOrientationAnim->onOrientationCompleted();
+ mLayerOrientationAnim->invalidate();
+ return true;
+
+ }
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+ // do the 2nd phase of the animation
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::finished()
+{
+ mState = DONE;
+ mFlinger->removeLayer(mLayerOrientationAnim);
+ mLayerOrientationAnim.clear();
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/OrientationAnimation.h b/libs/surfaceflinger/purgatory/OrientationAnimation.h
new file mode 100644
index 0000000..8ba6621
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:
+ OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+ virtual ~OrientationAnimation();
+
+ void onOrientationChanged(uint32_t type);
+ void onAnimationFinished();
+ inline bool run() {
+ if (LIKELY(mState == DONE))
+ return done_impl();
+ return run_impl();
+ }
+
+private:
+ enum {
+ DONE = 0,
+ PREPARE,
+ PHASE1,
+ PHASE2,
+ FINISH
+ };
+
+ bool run_impl();
+ inline bool done_impl() {
+ if (mFlinger->isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return true;
+ }
+ return false;
+ }
+
+ bool done();
+ bool prepare();
+ bool phase1();
+ bool phase2();
+ bool finished();
+
+ sp<SurfaceFlinger> mFlinger;
+ sp< LayerOrientationAnimBase > mLayerOrientationAnim;
+ int mState;
+ uint32_t mType;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/purgatory/VRamHeap.cpp b/libs/surfaceflinger/purgatory/VRamHeap.cpp
new file mode 100644
index 0000000..f3ed790
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/VRamHeap.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/MemoryDealer.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#include "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Amount of memory we reserve for surface, per client in PMEM
+ * (PMEM is used for 2D acceleration)
+ * 8 MB of address space per client should be enough.
+ */
+static const int PMEM_SIZE = int(8 * 1024 * 1024);
+
+int SurfaceHeapManager::global_pmem_heap = 0;
+
+// ---------------------------------------------------------------------------
+
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
+ size_t clientHeapSize)
+ : mFlinger(flinger), mClientHeapSize(clientHeapSize)
+{
+ SurfaceHeapManager::global_pmem_heap = 1;
+}
+
+SurfaceHeapManager::~SurfaceHeapManager()
+{
+}
+
+void SurfaceHeapManager::onFirstRef()
+{
+ if (global_pmem_heap) {
+ const char* device = "/dev/pmem";
+ mPMemHeap = new PMemHeap(device, PMEM_SIZE);
+ if (mPMemHeap->base() == MAP_FAILED) {
+ mPMemHeap.clear();
+ global_pmem_heap = 0;
+ }
+ }
+}
+
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+ uint32_t flags,
+ pid_t client_pid,
+ const sp<MemoryDealer>& defaultAllocator)
+{
+ sp<MemoryDealer> dealer;
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // don't grant GPU memory if GPU is disabled
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) == 0) {
+ flags &= ~ISurfaceComposer::eGPU;
+ }
+ }
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+ if (!(flags & ISurfaceComposer::eSecure)) {
+ // if GPU doesn't work, we try eHardware
+ flags |= ISurfaceComposer::eHardware;
+ // asked for GPU memory, try that first
+ dealer = mFlinger->getGPU()->request(client_pid);
+ }
+ }
+
+ if (dealer == NULL) {
+ if (defaultAllocator != NULL)
+ // if a default allocator is given, use that
+ dealer = defaultAllocator;
+ }
+
+ if (dealer == NULL) {
+ // always try h/w accelerated memory first
+ if (global_pmem_heap) {
+ const sp<PMemHeap>& heap(mPMemHeap);
+ if (dealer == NULL && heap != NULL) {
+ dealer = new MemoryDealer(
+ heap->createClientHeap(),
+ heap->getAllocator());
+ }
+ }
+ }
+
+ if (dealer == NULL) {
+ // return the ashmem allocator (software rendering)
+ dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
+ }
+ return dealer;
+}
+
+sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
+{
+ Mutex::Autolock _l(mLock);
+ sp<SimpleBestFitAllocator> allocator;
+
+ // this is only used for debugging
+ switch (type) {
+ case NATIVE_MEMORY_TYPE_PMEM:
+ if (mPMemHeap != 0) {
+ allocator = mPMemHeap->getAllocator();
+ }
+ break;
+ }
+ return allocator;
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
+ : MemoryHeapBase(device, size)
+{
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+ if (base() != MAP_FAILED) {
+ //LOGD("%s, %u bytes", device, virtualSize());
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+}
+
+PMemHeap::~PMemHeap() {
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+}
+
+sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapPmem(parentHeap);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/purgatory/VRamHeap.h
similarity index 100%
rename from libs/surfaceflinger/VRamHeap.h
rename to libs/surfaceflinger/purgatory/VRamHeap.h
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp
index f3c046f..0b9322e 100644
--- a/libs/surfaceflinger/tests/overlays/overlays.cpp
+++ b/libs/surfaceflinger/tests/overlays/overlays.cpp
@@ -1,6 +1,6 @@
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <ui/Surface.h>
diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/libs/surfaceflinger/tests/resize/Android.mk
new file mode 100644
index 0000000..ef1532f
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ resize.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-resize
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/libs/surfaceflinger/tests/resize/resize.cpp
new file mode 100644
index 0000000..21c6ab6
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/resize.cpp
@@ -0,0 +1,60 @@
+#include <cutils/memory.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Surface.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+#include <ui/SurfaceComposerClient.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+ static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+ return s->getISurface();
+ }
+};
+};
+
+int main(int argc, char** argv)
+{
+ // set up the thread-pool
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ // create a client to surfaceflinger
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+
+ // create pushbuffer surface
+ sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240,
+ PIXEL_FORMAT_RGB_565);
+
+
+ client->openTransaction();
+ surface->setLayer(100000);
+ client->closeTransaction();
+
+ Surface::SurfaceInfo info;
+ surface->lock(&info);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ android_memset16((uint16_t*)info.bits, 0xF800, bpr*info.h);
+ surface->unlockAndPost();
+
+ surface->lock(&info);
+ android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
+ surface->unlockAndPost();
+
+ client->openTransaction();
+ surface->setSize(320, 240);
+ client->closeTransaction();
+
+
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 7bbe38b..93c7263 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -2,12 +2,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ BufferMapper.cpp \
Camera.cpp \
CameraParameters.cpp \
- EGLDisplaySurface.cpp \
- EGLNativeWindowSurface.cpp \
+ EGLUtils.cpp \
EventHub.cpp \
EventRecurrence.cpp \
+ FramebufferNativeWindow.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
ICamera.cpp \
@@ -27,9 +28,10 @@
SurfaceFlingerSynchro.cpp
LOCAL_SHARED_LIBRARIES := \
- libcorecg \
libcutils \
libutils \
+ libEGL \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
diff --git a/libs/ui/BufferMapper.cpp b/libs/ui/BufferMapper.cpp
new file mode 100644
index 0000000..4add8f9
--- /dev/null
+++ b/libs/ui/BufferMapper.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "BufferMapper"
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/BufferMapper.h>
+#include <ui/Rect.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferMapper )
+
+BufferMapper::BufferMapper()
+ : mAllocMod(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ mAllocMod = (gralloc_module_t const *)module;
+ }
+}
+
+status_t BufferMapper::registerBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->registerBuffer(mAllocMod, handle);
+ LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unregisterBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr)
+{
+ status_t err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr);
+ LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unlock(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unlock(mAllocMod, handle);
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 5015379..12a7725 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -19,9 +19,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <ui/Camera.h>
#include <ui/ICameraService.h>
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
deleted file mode 100644
index d06c98b..0000000
--- a/libs/ui/EGLDisplaySurface.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- **
- ** 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.
- */
-
-#define LOG_TAG "EGLDisplaySurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <hardware/copybit.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/EGLDisplaySurface.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/msm_mdp.h>
-#endif
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-
-// ----------------------------------------------------------------------------
-
-egl_native_window_t* android_createDisplaySurface()
-{
- egl_native_window_t* s = new android::EGLDisplaySurface();
- s->memory_type = NATIVE_MEMORY_TYPE_GPU;
- return s;
-}
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLDisplaySurface::EGLDisplaySurface()
- : EGLNativeSurface<EGLDisplaySurface>()
-{
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
- egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::connect = 0;
- egl_native_window_t::disconnect = 0;
-
- mFb[0].data = 0;
- mFb[1].data = 0;
- mBlitEngine = 0;
- egl_native_window_t::fd = mapFrameBuffer();
- if (egl_native_window_t::fd >= 0) {
-
- hw_module_t const* module;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- const float in2mm = 25.4f;
- float refreshRate = 1000000000000000LLU / (
- float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
- * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
- * mInfo.pixclock);
-
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::width = buffer.width;
- egl_native_window_t::height = buffer.height;
- egl_native_window_t::stride = buffer.stride;
- egl_native_window_t::format = buffer.format;
- egl_native_window_t::base = intptr_t(mFb[0].data);
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- egl_native_window_t::flags = 0;
- egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
- egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
- egl_native_window_t::fps = refreshRate;
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
- // no error, set the magic word
- egl_native_window_t::magic = 0x600913;
- }
- mSwapCount = -1;
- mPageFlipCount = 0;
-}
-
-EGLDisplaySurface::~EGLDisplaySurface()
-{
- magic = 0;
- copybit_close(mBlitEngine);
- mBlitEngine = 0;
- close(egl_native_window_t::fd);
- munmap(mFb[0].data, mSize);
- if (!(mFlags & PAGE_FLIP))
- free((void*)mFb[1].data);
-}
-
-void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->incStrong(that);
-}
-void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->decStrong(that);
-}
-uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mInfo.reserved[0] = 0x54445055; // "UPDT";
- mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
- mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-}
-
-uint32_t EGLDisplaySurface::swapBuffers()
-{
-#define SHOW_FPS 0
-#if SHOW_FPS
- nsecs_t now = systemTime();
- if (mSwapCount == -1) {
- mTime = now;
- mSwapCount = 0;
- mSleep = 0;
- } else {
- nsecs_t d = now-mTime;
- if (d >= seconds(1)) {
- double fps = (mSwapCount * double(seconds(1))) / double(d);
- LOGD("%f fps, sleep=%d / frame",
- fps, (int)ns2us(mSleep / mSwapCount));
- mSwapCount = 0;
- mTime = now;
- mSleep = 0;
- } else {
- mSwapCount++;
- }
- }
-#endif
- /* If we can't do the page_flip, just copy the back buffer to the front */
- if (!(mFlags & PAGE_FLIP)) {
- memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
- return 0;
- }
-
- // do the actual flip
- mIndex = 1 - mIndex;
- mInfo.activate = FB_ACTIVATE_VBL;
- mInfo.yoffset = mIndex ? mInfo.yres : 0;
- if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
- LOGE("FBIOPUT_VSCREENINFO failed");
- return 0;
- }
-
- /*
- * this is a monstrous hack: Because the h/w accelerator is not able
- * to render directly into the framebuffer, we need to copy its
- * internal framebuffer out to the fb.
- * oem[0] is used to access the fd of internal fb.
- * All this is needed only in standalone mode, in SurfaceFlinger mode
- * we control where the GPU renders.
- * We do this only if we have copybit, since this hack is needed only
- * with msm7k.
- */
- if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
- copybit_device_t *copybit = mBlitEngine;
- copybit_rect_t sdrect = { 0, 0,
- egl_native_window_t::width, egl_native_window_t::height };
- copybit_image_t dst = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format,
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base,
- egl_native_window_t::fd
- };
- copybit_image_t src = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format, // XXX: use proper format
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base, // XXX: use proper base
- egl_native_window_t::oem[0]
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
- }
-
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
-
-#if SHOW_FPS
- mSleep += systemTime()-now;
-#endif
-
- mPageFlipCount++;
-
- // We don't support screen-size changes for now
- return 0;
-}
-
-int32_t EGLDisplaySurface::getPageFlipCount() const
-{
- return mPageFlipCount;
-}
-
-void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t dst = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(copyback);
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- /* no extra copy needed since we copied back to front instead of
- * flipping */
- if (!(mFlags & PAGE_FLIP)) {
- return;
- }
-
- Region::iterator iterator(copyback);
- if (iterator) {
- Rect r;
- uint8_t* const screen_src = mFb[ mIndex].data;
- uint8_t* const screen_dst = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
- uint8_t* s = screen_src + o;
- uint8_t* d = screen_dst + o;
- if (size == bpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += bpr;
- s += bpr;
- } while (--h > 0);
- }
- }
- }
- }
-}
-
-void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[ mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-
-status_t EGLDisplaySurface::mapFrameBuffer()
-{
- char const * const device_template[] = {
- "/dev/graphics/fb%u",
- "/dev/fb%u",
- 0 };
- int fd = -1;
- int i=0;
- char name[64];
- while ((fd==-1) && device_template[i]) {
- snprintf(name, 64, device_template[i], 0);
- fd = open(name, O_RDWR, 0);
- i++;
- }
- if (fd < 0)
- return -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.yres_virtual = info.yres * 2;
- info.bits_per_pixel = 16;
- /* Explicitly request 5/6/5 */
- info.red.offset = 11;
- info.red.length = 5;
- info.green.offset = 5;
- info.green.length = 6;
- info.blue.offset = 0;
- info.blue.length = 5;
- info.transp.offset = 0;
- info.transp.length = 0;
- info.activate = FB_ACTIVATE_NOW;
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
- if (int(info.width) <= 0 || int(info.height) <= 0) {
- // the driver doesn't return that information
- // default to 160 dpi
- info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
- info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
- }
-
- float xdpi = (info.xres * 25.4f) / info.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "using (fd=%d)\n"
- "id = %s\n"
- "xres = %d px\n"
- "yres = %d px\n"
- "xres_virtual = %d px\n"
- "yres_virtual = %d px\n"
- "bpp = %d\n"
- "r = %2u:%u\n"
- "g = %2u:%u\n"
- "b = %2u:%u\n",
- fd,
- finfo.id,
- info.xres,
- info.yres,
- info.xres_virtual,
- info.yres_virtual,
- info.bits_per_pixel,
- info.red.offset, info.red.length,
- info.green.offset, info.green.length,
- info.blue.offset, info.blue.length
- );
-
- LOGI( "width = %d mm (%f dpi)\n"
- "height = %d mm (%f dpi)\n"
- "refresh rate = %.2f Hz\n",
- info.width, xdpi,
- info.height, ydpi,
- fps
- );
-
-
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- /*
- * Open and map the display.
- */
-
- void* buffer = (uint16_t*) mmap(
- 0, finfo.smem_len,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, 0);
-
- if (buffer == MAP_FAILED)
- return -errno;
-
- // at least for now, always clear the fb
- memset(buffer, 0, finfo.smem_len);
-
- uint8_t* offscreen[2];
- offscreen[0] = (uint8_t*)buffer;
- if (flags & PAGE_FLIP) {
- offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
- } else {
- offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
- if (offscreen[1] == 0) {
- munmap(buffer, finfo.smem_len);
- return NO_MEMORY;
- }
- }
-
- mFlags = flags;
- mInfo = info;
- mFinfo = finfo;
- mSize = finfo.smem_len;
- mIndex = 0;
- for (int i=0 ; i<2 ; i++) {
- mFb[i].version = sizeof(GGLSurface);
- mFb[i].width = info.xres;
- mFb[i].height = info.yres;
- mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
- mFb[i].data = (GGLubyte*)(offscreen[i]);
- mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
- }
- return fd;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
deleted file mode 100644
index f1071cf..0000000
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-**
-** 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.
-*/
-
-#define LOG_TAG "EGLNativeWindowSurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-#include <ui/EGLNativeWindowSurface.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
- : EGLNativeSurface<EGLNativeWindowSurface>(),
- mSurface(surface), mConnected(false)
-{
- egl_native_window_t::magic = 0x600913;
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
- egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
- egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
-
- DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
- egl_native_window_t::xdpi = dinfo.xdpi;
- egl_native_window_t::ydpi = dinfo.ydpi;
- egl_native_window_t::fps = dinfo.fps;
- egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
-}
-
-EGLNativeWindowSurface::~EGLNativeWindowSurface()
-{
- disconnect();
- mSurface.clear();
- magic = 0;
-}
-
-void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->incStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->decStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->connect();
-}
-
-void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->disconnect();
-}
-
-uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
-}
-
-uint32_t EGLNativeWindowSurface::swapBuffers()
-{
- const int w = egl_native_window_t::width;
- const int h = egl_native_window_t::height;
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->unlockAndPost();
- surface->lock(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-
- // update size if it changed
- if (w != int(info.w) || h != int(info.h)) {
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- return EGL_NATIVES_FLAG_SIZE_CHANGED;
- }
- return 0;
-}
-
-void EGLNativeWindowSurface::connect()
-{
- if (!mConnected) {
- Surface::SurfaceInfo info;
- mSurface->lock(&info);
- mSurface->setSwapRectangle(Rect(info.w, info.h));
- mConnected = true;
-
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- // FIXME: egl_native_window_t::memory_type used to be set from
- // mSurface, but we wanted to break this dependency. We set it to
- // GPU because the software rendered doesn't care, but the h/w
- // accelerator needs it. Eventually, this value should go away
- // completely, since memory will be managed by OpenGL.
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
- egl_native_window_t::fd = 0;
- }
-}
-
-void EGLNativeWindowSurface::disconnect()
-{
- if (mConnected) {
- mSurface->unlock();
- mConnected = false;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
new file mode 100644
index 0000000..1663313
--- /dev/null
+++ b/libs/ui/EGLUtils.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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_TAG "EGLUtils"
+
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+#include <ui/EGLUtils.h>
+
+#include <EGL/egl.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const char *EGLUtils::strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+status_t EGLUtils::selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig)
+{
+ EGLint numConfigs = -1, n=0;
+
+ if (!attrs)
+ return BAD_VALUE;
+
+ if (outConfig == NULL)
+ return BAD_VALUE;
+
+ int err;
+ PixelFormatInfo fbFormatInfo;
+ if ((err = getPixelFormatInfo(PixelFormat(format), &fbFormatInfo)) < 0) {
+ return err;
+ }
+
+ // Get all the "potential match" configs...
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ return BAD_VALUE;
+
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+ const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+ const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+ const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint r,g,b,a;
+ EGLConfig curr = configs[i];
+ eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);
+ if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) {
+ config = curr;
+ break;
+ }
+ }
+
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+status_t EGLUtils::selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig)
+{
+ int err;
+ int format;
+
+ if (!window)
+ return BAD_VALUE;
+
+ if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
+ return err;
+ }
+
+ return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..df713cb 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -16,13 +16,14 @@
//#define LOG_NDEBUG 0
#include <ui/EventHub.h>
+#include <ui/KeycodeLabels.h>
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
-#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <utils.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
@@ -58,6 +59,18 @@
#define SEQ_SHIFT 16
#define id_to_index(id) ((id&ID_MASK)+1)
+#ifndef ABS_MT_TOUCH_MAJOR
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#endif
+
+#ifndef ABS_MT_POSITION_X
+#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
+#endif
+
+#ifndef ABS_MT_POSITION_Y
+#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
+#endif
+
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
@@ -69,8 +82,8 @@
return (v1 > v2) ? v1 : v2;
}
-EventHub::device_t::device_t(int32_t _id, const char* _path)
- : id(_id), path(_path), classes(0)
+EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
+ : id(_id), path(_path), name(name), classes(0)
, keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
@@ -83,7 +96,7 @@
: mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
, mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0)
+ , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
{
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
@@ -100,11 +113,6 @@
// we should free stuff here...
}
-void EventHub::onFirstRef()
-{
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
-}
-
status_t EventHub::errorCheck() const
{
return mError;
@@ -239,6 +247,41 @@
return 0;
}
+status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+
+ if (mHaveFirstKeyboard) {
+ device = getDevice(mFirstKeyboardId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ }
+
+ *outKeycode = 0;
+ *outFlags = 0;
+ return NAME_NOT_FOUND;
+}
+
+void EventHub::addExcludedDevice(const char* deviceName)
+{
+ String8 name(deviceName);
+ mExcludedDevices.push_back(name);
+}
+
EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
@@ -276,7 +319,12 @@
// Note that we only allow one caller to getEvent(), so don't need
// to do locking here... only when adding/removing devices.
-
+
+ if (!mOpened) {
+ mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+ mOpened = true;
+ }
+
while(1) {
// First, report any devices that had last been added/removed.
@@ -474,6 +522,20 @@
//fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
name[0] = '\0';
}
+
+ // check to see if the device is on our excluded list
+ List<String8>::iterator iter = mExcludedDevices.begin();
+ List<String8>::iterator end = mExcludedDevices.end();
+ for ( ; iter != end; iter++) {
+ const char* test = *iter;
+ if (strcmp(name, test) == 0) {
+ LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ }
+
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
location[0] = '\0';
@@ -531,7 +593,7 @@
version >> 16, (version >> 8) & 0xff, version & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+ device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
if (device == NULL) {
LOGE("out of memory");
return -1;
@@ -541,6 +603,8 @@
mFDs[mFDCount].events = POLLIN;
// figure out the kinds of events the device reports
+
+ // See if this is a keyboard, and classify it.
uint8_t key_bitmask[(KEY_MAX+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
@@ -552,15 +616,11 @@
for (int i=0; i<((BTN_MISC+7)/8); i++) {
if (key_bitmask[i] != 0) {
device->classes |= CLASS_KEYBOARD;
- // 'Q' key support = cheap test of whether this is an alpha-capable kbd
- if (test_bit(KEY_Q, key_bitmask)) {
- device->classes |= CLASS_ALPHAKEY;
- }
break;
}
}
if ((device->classes & CLASS_KEYBOARD) != 0) {
- device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
if (device->keyBitmask != NULL) {
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
} else {
@@ -570,6 +630,8 @@
}
}
}
+
+ // See if this is a trackball.
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
memset(rel_bitmask, 0, sizeof(rel_bitmask));
@@ -581,16 +643,22 @@
}
}
}
- if (test_bit(BTN_TOUCH, key_bitmask)) {
- uint8_t abs_bitmask[(ABS_MAX+1)/8];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
- {
- if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
- device->classes |= CLASS_TOUCHSCREEN;
- }
- }
+
+ uint8_t abs_bitmask[(ABS_MAX+1)/8];
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ LOGV("Getting absolute controllers...");
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+
+ // Is this a new modern multi-touch driver?
+ if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
+
+ // Is this an old style single-touch driver?
+ } else if (test_bit(BTN_TOUCH, key_bitmask)
+ && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN;
}
#ifdef EV_SW
@@ -609,21 +677,15 @@
}
#endif
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
if ((device->classes&CLASS_KEYBOARD) != 0) {
- char devname[101];
- char tmpfn[101];
+ char tmpfn[sizeof(name)];
char keylayoutFilename[300];
// a more descriptive name
- ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
- devname[sizeof(devname)-1] = 0;
- device->name = devname;
+ device->name = name;
// replace all the spaces with underscores
- strcpy(tmpfn, devname);
+ strcpy(tmpfn, name);
for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
*p = '_';
@@ -656,12 +718,29 @@
}
char propName[100];
sprintf(propName, "hw.keyboards.%u.devname", publicID);
- property_set(propName, devname);
+ property_set(propName, name);
- LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
- publicID, device->id, devname, propName, keylayoutFilename);
+ // 'Q' key support = cheap test of whether this is an alpha-capable kbd
+ if (hasKeycode(device, kKeyCodeQ)) {
+ device->classes |= CLASS_ALPHAKEY;
+ }
+
+ // See if this has a DPAD.
+ if (hasKeycode(device, kKeyCodeDpadUp) &&
+ hasKeycode(device, kKeyCodeDpadDown) &&
+ hasKeycode(device, kKeyCodeDpadLeft) &&
+ hasKeycode(device, kKeyCodeDpadRight) &&
+ hasKeycode(device, kKeyCodeDpadCenter)) {
+ device->classes |= CLASS_DPAD;
+ }
+
+ LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
+ publicID, device->id, name, propName, keylayoutFilename);
}
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
deviceName, device, mFDCount, devid, device->classes);
@@ -674,6 +753,25 @@
return 0;
}
+bool EventHub::hasKeycode(device_t* device, int keycode) const
+{
+ if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+ return false;
+ }
+
+ Vector<int32_t> scanCodes;
+ device->layoutMap->findScancodes(keycode, &scanCodes);
+ const size_t N = scanCodes.size();
+ for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+ int32_t sc = scanCodes.itemAt(i);
+ if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
int EventHub::close_device(const char *deviceName)
{
AutoMutex _l(mLock);
@@ -733,6 +831,7 @@
int event_pos = 0;
struct inotify_event *event;
+LOGD("EventHub::read_notify nfd: %d\n", nfd);
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
new file mode 100644
index 0000000..90b5163
--- /dev/null
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -0,0 +1,267 @@
+/*
+**
+** 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.
+*/
+
+#define LOG_TAG "FramebufferNativeWindow"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class NativeBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ NativeBuffer,
+ LightRefBase<NativeBuffer> >
+{
+public:
+ NativeBuffer(int w, int h, int f, int u) : BASE() {
+ android_native_buffer_t::width = w;
+ android_native_buffer_t::height = h;
+ android_native_buffer_t::format = f;
+ android_native_buffer_t::usage = u;
+ }
+private:
+ friend class LightRefBase<NativeBuffer>;
+ ~NativeBuffer() { }; // this class cannot be overloaded
+};
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ * In fact this is an implementation of android_native_window_t on top of
+ * the framebuffer.
+ *
+ * Currently it is pretty simple, it manages only two buffers (the front and
+ * back buffer).
+ *
+ */
+
+FramebufferNativeWindow::FramebufferNativeWindow()
+ : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
+{
+ hw_module_t const* module;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ int stride;
+ int err;
+ err = framebuffer_open(module, &fbDev);
+ LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+
+ err = gralloc_open(module, &grDev);
+ LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
+
+ // bail out if we can't initialize the modules
+ if (!fbDev || !grDev)
+ return;
+
+ mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+ // initialize the buffer FIFO
+ mNumBuffers = 2;
+ mNumFreeBuffers = 2;
+ mBufferHead = mNumBuffers-1;
+ buffers[0] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+ buffers[1] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);
+
+ LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);
+
+ LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+ }
+
+ const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags;
+ const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
+ const_cast<int&>(android_native_window_t::minSwapInterval) =
+ fbDev->minSwapInterval;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) =
+ fbDev->maxSwapInterval;
+
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+}
+
+FramebufferNativeWindow::~FramebufferNativeWindow()
+{
+ if (grDev) {
+ if (buffers[0] != NULL)
+ grDev->free(grDev, buffers[0]->handle);
+ if (buffers[1] != NULL)
+ grDev->free(grDev, buffers[1]->handle);
+ gralloc_close(grDev);
+ }
+
+ if (fbDev) {
+ framebuffer_close(fbDev);
+ }
+}
+
+status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
+{
+ if (!mUpdateOnDemand) {
+ return INVALID_OPERATION;
+ }
+ return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+int FramebufferNativeWindow::setSwapInterval(
+ android_native_window_t* window, int interval)
+{
+ framebuffer_device_t* fb = getSelf(window)->fbDev;
+ return fb->setSwapInterval(fb, interval);
+}
+
+int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+
+ // wait for a free buffer
+ while (!self->mNumFreeBuffers) {
+ self->mCondition.wait(self->mutex);
+ }
+ // get this buffer
+ self->mNumFreeBuffers--;
+ int index = self->mBufferHead++;
+ if (self->mBufferHead >= self->mNumBuffers)
+ self->mBufferHead = 0;
+
+ *buffer = self->buffers[index].get();
+
+ return 0;
+}
+
+int FramebufferNativeWindow::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+
+ // wait that the buffer we're locking is not front anymore
+ while (self->front == buffer) {
+ self->mCondition.wait(self->mutex);
+ }
+
+ return NO_ERROR;
+}
+
+int FramebufferNativeWindow::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ int res = fb->post(fb, handle);
+ self->front = static_cast<NativeBuffer*>(buffer);
+ self->mNumFreeBuffers++;
+ self->mCondition.broadcast();
+ return res;
+}
+
+int FramebufferNativeWindow::query(android_native_window_t* window,
+ int what, int* value)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = fb->format;
+ return NO_ERROR;
+ }
+ *value = 0;
+ return BAD_VALUE;
+}
+
+int FramebufferNativeWindow::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLNativeWindowType android_createDisplaySurface(void)
+{
+ FramebufferNativeWindow* w;
+ w = new FramebufferNativeWindow();
+ if (w->getDevice() == NULL) {
+ // get a ref so it can be destroyed when we exit this block
+ sp<FramebufferNativeWindow> ref(w);
+ return NULL;
+ }
+ return (EGLNativeWindowType)w;
+}
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index ab0fef1..805c2ca 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ICamera.h>
namespace android {
@@ -221,12 +221,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index 59a6cf2..42b4da4 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -78,12 +78,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
index e5687fe..84986c6 100644
--- a/libs/ui/ICameraService.cpp
+++ b/libs/ui/ICameraService.cpp
@@ -18,9 +18,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ICameraService.h>
@@ -49,12 +49,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
index fed47c2..65e6b4f 100644
--- a/libs/ui/IOverlay.cpp
+++ b/libs/ui/IOverlay.cpp
@@ -18,8 +18,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
#include <ui/IOverlay.h>
@@ -49,12 +49,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnOverlay::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index d5e9f81..b78e8b5 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -14,19 +14,25 @@
* limitations under the License.
*/
+#define LOG_TAG "ISurface"
+
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
+#include <ui/Surface.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
+// ----------------------------------------------------------------------
+
ISurface::BufferHeap::BufferHeap()
: w(0), h(0), hor_stride(0), ver_stride(0), format(0),
transform(0), flags(0)
@@ -55,6 +61,8 @@
{
}
+// ----------------------------------------------------------------------
+
class BpSurface : public BpInterface<ISurface>
{
public:
@@ -63,6 +71,16 @@
{
}
+ virtual sp<SurfaceBuffer> getBuffer(int usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(usage);
+ remote()->transact(GET_BUFFER, data, &reply);
+ sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
+ return buffer;
+ }
+
virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
@@ -112,16 +130,16 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
+ case GET_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int usage = data.readInt32();
+ sp<SurfaceBuffer> buffer(getBuffer(usage));
+ return SurfaceBuffer::writeToParcel(reply, buffer.get());
+ }
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
BufferHeap buffer;
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
index 76597e1..fd2a590 100644
--- a/libs/ui/ISurfaceComposer.cpp
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -20,10 +20,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -54,12 +54,12 @@
return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
}
- virtual sp<IMemory> getCblk() const
+ virtual sp<IMemoryHeap> getCblk() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
- return interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual void openGlobalTransaction()
@@ -114,36 +114,6 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback, gpu_info_t* gpu)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(callback->asBinder());
- remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
- gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->count = reply.readInt32();
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
- if (gpu->count > maxCount)
- return BAD_VALUE;
-
- for (size_t i=0 ; i<gpu->count ; i++) {
- gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->regions[i].reserved = reply.readInt32();
- }
- return reply.readInt32();
- }
-
- virtual status_t revokeGPU()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
- return reply.readInt32();
- }
-
virtual void signal() const
{
Parcel data, reply;
@@ -156,124 +126,61 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
- if (err == NO_ERROR)
- return err;
-
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
switch(code) {
case CREATE_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case OPEN_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
openGlobalTransaction();
} break;
case CLOSE_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
closeGlobalTransaction();
} break;
case SET_ORIENTATION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
int orientation = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( setOrientation(dpy, orientation, flags) );
} break;
case FREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( freezeDisplay(dpy, flags) );
} break;
case UNFREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( unfreezeDisplay(dpy, flags) );
} break;
case BOOT_FINISHED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case REVOKE_GPU: {
- reply->writeInt32( revokeGPU() );
- } break;
case SIGNAL: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
signal();
} break;
case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();
reply->writeStrongBinder(b);
} break;
- case REQUEST_GPU: {
- // TODO: this should be protected by a permission
- gpu_info_t info;
- sp<IGPUCallback> callback
- = interface_cast<IGPUCallback>(data.readStrongBinder());
- status_t res = requestGPU(callback, &info);
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
- if (info.count > maxCount)
- return BAD_VALUE;
-
- reply->writeStrongBinder(info.regs->asBinder());
- reply->writeInt32(info.count);
- for (size_t i=0 ; i<info.count ; i++) {
- reply->writeStrongBinder(info.regions[i].region->asBinder());
- reply->writeInt32(info.regions[i].reserved);
- }
- reply->writeInt32(res);
- } break;
default:
- return UNKNOWN_TRANSACTION;
+ return BBinder::onTransact(code, data, reply, flags);
}
return NO_ERROR;
}
// ----------------------------------------------------------------------------
-enum {
- // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
- GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpGPUCallback : public BpInterface<IGPUCallback>
-{
-public:
- BpGPUCallback(const sp<IBinder>& impl)
- : BpInterface<IGPUCallback>(impl)
- {
- }
-
- virtual void gpuLost()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
- remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
-
-status_t BnGPUCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GPU_LOST: {
- CHECK_INTERFACE(IGPUCallback, data, reply);
- gpuLost();
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dab5f71..51e8422 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -21,10 +21,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurface.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -64,12 +64,12 @@
{
}
- virtual void getControlBlocks(sp<IMemory>* ctl) const
+ virtual sp<IMemoryHeap> getControlBlock() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
remote()->transact(GET_CBLK, data, &reply);
- *ctl = interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual sp<ISurface> createSurface( surface_data_t* params,
@@ -118,12 +118,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -132,8 +126,7 @@
switch(code) {
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
- sp<IMemory> ctl;
- getControlBlocks(&ctl);
+ sp<IMemoryHeap> ctl(getControlBlock());
reply->writeStrongBinder(ctl->asBinder());
return NO_ERROR;
} break;
@@ -198,8 +191,6 @@
{
token = parcel.readInt32();
identity = parcel.readInt32();
- heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
- heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
return NO_ERROR;
}
@@ -207,8 +198,6 @@
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
return NO_ERROR;
}
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
index 0b6374b..a53ffb7 100644
--- a/libs/ui/LayerState.cpp
+++ b/libs/ui/LayerState.cpp
@@ -15,7 +15,7 @@
*/
#include <utils/Errors.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <private/ui/LayerState.h>
namespace android {
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index 59c6514..3aa8950 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <utils/IMemory.h>
-#include <utils/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
#include <utils/Errors.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/IOverlay.h>
#include <ui/Overlay.h>
@@ -59,6 +59,30 @@
return mOverlayData->queueBuffer(mOverlayData, buffer);
}
+status_t Overlay::resizeInput(uint32_t width, uint32_t height)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->resizeInput(mOverlayData, width, height);
+}
+
+status_t Overlay::setParameter(int param, int value)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setParameter(mOverlayData, param, value);
+}
+
+status_t Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setCrop(mOverlayData, x, y, w, h);
+}
+
+status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->getCrop(mOverlayData, x, y, w, h);
+}
+
int32_t Overlay::getBufferCount() const
{
if (mStatus != NO_ERROR) return mStatus;
@@ -73,6 +97,15 @@
void Overlay::destroy() {
if (mStatus != NO_ERROR) return;
+
+ // Must delete the objects in reverse creation order, thus the
+ // data side must be closed first and then the destroy send to
+ // the control side.
+ if (mOverlayData) {
+ overlay_data_close(mOverlayData);
+ mOverlayData = NULL;
+ }
+
mOverlayRef->mOverlayChannel->destroy();
}
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 26e694a..d21ed57 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -16,295 +16,661 @@
#define LOG_TAG "Region"
-#include <stdio.h>
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
+#include <limits.h>
+
+#include <utils/Log.h>
#include <utils/String8.h>
+
+#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Point.h>
+
+#include <private/ui/RegionHelper.h>
+
+// ----------------------------------------------------------------------------
+#define VALIDATE_REGIONS (false)
+#define VALIDATE_WITH_CORECG (false)
+// ----------------------------------------------------------------------------
+
+#if VALIDATE_WITH_CORECG
+#include <core/SkRegion.h>
+#endif
namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+ op_nand = region_operator<Rect>::op_nand,
+ op_and = region_operator<Rect>::op_and,
+ op_or = region_operator<Rect>::op_or,
+ op_xor = region_operator<Rect>::op_xor
+};
// ----------------------------------------------------------------------------
Region::Region()
+ : mBounds(0,0)
{
}
Region::Region(const Region& rhs)
- : mRegion(rhs.mRegion)
+ : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
{
}
-Region::Region(const SkRegion& rhs)
- : mRegion(rhs)
+Region::Region(const Rect& rhs)
+ : mBounds(rhs)
{
}
+Region::Region(const Parcel& parcel)
+{
+ status_t err = read(parcel);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
+}
+
+Region::Region(const void* buffer)
+{
+ status_t err = read(buffer);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
+}
+
Region::~Region()
{
}
-Region::Region(const Rect& rhs)
-{
- set(rhs);
-}
-
-Region::Region(const Parcel& parcel)
-{
- read(parcel);
-}
-
-Region::Region(const void* buffer)
-{
- read(buffer);
-}
-
Region& Region::operator = (const Region& rhs)
{
- mRegion = rhs.mRegion;
+#if VALIDATE_REGIONS
+ validate(rhs, "operator=");
+#endif
+ mBounds = rhs.mBounds;
+ mStorage = rhs.mStorage;
return *this;
}
-const SkRegion& Region::toSkRegion() const
+Region& Region::makeBoundsSelf()
{
- return mRegion;
-}
-
-Rect Region::bounds() const
-{
- const SkIRect& b(mRegion.getBounds());
- return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+ mStorage.clear();
+ return *this;
}
void Region::clear()
{
- mRegion.setEmpty();
+ mBounds.clear();
+ mStorage.clear();
}
void Region::set(const Rect& r)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.setRect(ir);
+ mBounds = r;
+ mStorage.clear();
+}
+
+void Region::set(uint32_t w, uint32_t h)
+{
+ mBounds = Rect(int(w), int(h));
+ mStorage.clear();
}
// ----------------------------------------------------------------------------
-Region& Region::orSelf(const Rect& r)
+void Region::addRectUnchecked(int l, int t, int r, int b)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kUnion_Op);
- return *this;
+ mStorage.add(Rect(l,t,r,b));
+#if VALIDATE_REGIONS
+ validate(*this, "addRectUnchecked");
+#endif
}
-Region& Region::andSelf(const Rect& r)
-{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r) {
+ return operationSelf(r, op_or);
+}
+Region& Region::andSelf(const Rect& r) {
+ return operationSelf(r, op_and);
+}
+Region& Region::subtractSelf(const Rect& r) {
+ return operationSelf(r, op_nand);
+}
+Region& Region::operationSelf(const Rect& r, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, r);
return *this;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, op_or);
}
-
Region& Region::andSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+ return operationSelf(rhs, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs);
return *this;
}
Region& Region::translateSelf(int x, int y) {
- if (x|y) mRegion.translate(x, y);
+ if (x|y) translate(*this, x, y);
return *this;
}
-Region Region::merge(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Rect& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Rect& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Rect& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Rect& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::intersect(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Region& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Region& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Region& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::subtract(const Region& rhs) const {
+const Region Region::translate(int x, int y) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
- return result;
-}
-
-Region Region::translate(int x, int y) const {
- Region result;
- mRegion.translate(x, y, &result.mRegion);
+ translate(result, *this, x, y);
return result;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_or);
}
-
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kDifference_Op);
+ return operationSelf(rhs, dx, dy, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs, dx, dy);
return *this;
}
-Region Region::merge(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
- return result;
-}
+// ----------------------------------------------------------------------------
-Region Region::intersect(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
- return result;
+const Region Region::merge(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_or);
}
-
-Region Region::subtract(const Region& rhs, int dx, int dy) const {
+const Region Region::intersect(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_and);
+}
+const Region Region::subtract(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_nand);
+}
+const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
+ boolean_operation(op, result, *this, rhs, dx, dy);
return result;
}
// ----------------------------------------------------------------------------
-Region::iterator::iterator(const Region& r)
- : mIt(r.mRegion)
+// This is our region rasterizer, which merges rects and spans together
+// to obtain an optimal region.
+class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
+ Rect& bounds;
+ Vector<Rect>& storage;
+ Rect* head;
+ Rect* tail;
+ Vector<Rect> span;
+ Rect* cur;
+public:
+ rasterizer(Region& reg)
+ : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
+ bounds.top = bounds.bottom = 0;
+ bounds.left = INT_MAX;
+ bounds.right = INT_MIN;
+ storage.clear();
+ }
+
+ ~rasterizer() {
+ if (span.size()) {
+ flushSpan();
+ }
+ if (storage.size()) {
+ bounds.top = storage.itemAt(0).top;
+ bounds.bottom = storage.top().bottom;
+ if (storage.size() == 1) {
+ storage.clear();
+ }
+ } else {
+ bounds.left = 0;
+ bounds.right = 0;
+ }
+ }
+
+ virtual void operator()(const Rect& rect) {
+ //LOGD(">>> %3d, %3d, %3d, %3d",
+ // rect.left, rect.top, rect.right, rect.bottom);
+ if (span.size()) {
+ if (cur->top != rect.top) {
+ flushSpan();
+ } else if (cur->right == rect.left) {
+ cur->right = rect.right;
+ return;
+ }
+ }
+ span.add(rect);
+ cur = span.editArray() + (span.size() - 1);
+ }
+private:
+ template<typename T>
+ static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
+ template<typename T>
+ static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
+ void flushSpan() {
+ bool merge = false;
+ if (tail-head == ssize_t(span.size())) {
+ Rect const* p = cur;
+ Rect const* q = head;
+ if (p->top == q->bottom) {
+ merge = true;
+ while (q != tail) {
+ if ((p->left != q->left) || (p->right != q->right)) {
+ merge = false;
+ break;
+ }
+ p++, q++;
+ }
+ }
+ }
+ if (merge) {
+ const int bottom = span[0].bottom;
+ Rect* r = head;
+ while (r != tail) {
+ r->bottom = bottom;
+ r++;
+ }
+ } else {
+ bounds.left = min(span.itemAt(0).left, bounds.left);
+ bounds.right = max(span.top().right, bounds.right);
+ storage.appendVector(span);
+ tail = storage.editArray() + storage.size();
+ head = tail - span.size();
+ }
+ span.clear();
+ }
+};
+
+bool Region::validate(const Region& reg, const char* name)
+{
+ bool result = true;
+ const_iterator cur = reg.begin();
+ const_iterator const tail = reg.end();
+ const_iterator prev = cur++;
+ Rect b(*prev);
+ while (cur != tail) {
+ b.left = b.left < cur->left ? b.left : cur->left;
+ b.top = b.top < cur->top ? b.top : cur->top;
+ b.right = b.right > cur->right ? b.right : cur->right;
+ b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+ if (cur->top == prev->top) {
+ if (cur->bottom != prev->bottom) {
+ LOGE("%s: invalid span %p", name, cur);
+ result = false;
+ } else if (cur->left < prev->right) {
+ LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ } else if (cur->top < prev->bottom) {
+ LOGE("%s: spans overlap vertically prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ prev = cur;
+ cur++;
+ }
+ if (b != reg.getBounds()) {
+ result = false;
+ LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+ b.left, b.top, b.right, b.bottom,
+ reg.getBounds().left, reg.getBounds().top,
+ reg.getBounds().right, reg.getBounds().bottom);
+ }
+ if (result == false) {
+ reg.dump(name);
+ }
+ return result;
}
-int Region::iterator::iterate(Rect* rect)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Region& rhs, int dx, int dy)
{
- if (mIt.done())
- return 0;
- const SkIRect& r(mIt.rect());
- rect->left = r.fLeft;
- rect->top = r.fTop;
- rect->right = r.fRight;
- rect->bottom= r.fBottom;
- mIt.next();
- return 1;
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ size_t rhs_count;
+ Rect const * const rhs_rects = rhs.getArray(&rhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#if VALIDATE_REGIONS
+ validate(lhs, "boolean_operation: lhs");
+ validate(rhs, "boolean_operation: rhs");
+ validate(dst, "boolean_operation: dst");
+#endif
+
+#if VALIDATE_WITH_CORECG
+ SkRegion sk_lhs;
+ SkRegion sk_rhs;
+ SkRegion sk_dst;
+
+ for (size_t i=0 ; i<lhs_count ; i++)
+ sk_lhs.op(
+ lhs_rects[i].left + dx,
+ lhs_rects[i].top + dy,
+ lhs_rects[i].right + dx,
+ lhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ for (size_t i=0 ; i<rhs_count ; i++)
+ sk_rhs.op(
+ rhs_rects[i].left + dx,
+ rhs_rects[i].top + dy,
+ rhs_rects[i].right + dx,
+ rhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ const char* name = "---";
+ SkRegion::Op sk_op;
+ switch (op) {
+ case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+ case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
+ case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
+ }
+ sk_dst.op(sk_lhs, sk_rhs, sk_op);
+
+ if (sk_dst.isEmpty() && dst.isEmpty())
+ return;
+
+ bool same = true;
+ Region::const_iterator head = dst.begin();
+ Region::const_iterator const tail = dst.end();
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ if (head != tail) {
+ if (
+ head->left != it.rect().fLeft ||
+ head->top != it.rect().fTop ||
+ head->right != it.rect().fRight ||
+ head->bottom != it.rect().fBottom
+ ) {
+ same = false;
+ break;
+ }
+ } else {
+ same = false;
+ break;
+ }
+ head++;
+ it.next();
+ }
+
+ if (head != tail) {
+ same = false;
+ }
+
+ if(!same) {
+ LOGD("---\nregion boolean %s failed", name);
+ lhs.dump("lhs");
+ rhs.dump("rhs");
+ dst.dump("dst");
+ LOGD("should be");
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ LOGD(" [%3d, %3d, %3d, %3d]",
+ it.rect().fLeft,
+ it.rect().fTop,
+ it.rect().fRight,
+ it.rect().fBottom);
+ it.next();
+ }
+ }
+#endif
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Rect& rhs, int dx, int dy)
+{
+#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+ boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
+#else
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#endif
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs)
+{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
+}
+
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs)
+{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
+}
+
+void Region::translate(Region& reg, int dx, int dy)
+{
+ if (!reg.isEmpty()) {
+#if VALIDATE_REGIONS
+ validate(reg, "translate (before)");
+#endif
+ reg.mBounds.translate(dx, dy);
+ size_t count = reg.mStorage.size();
+ Rect* rects = reg.mStorage.editArray();
+ while (count) {
+ rects->translate(dx, dy);
+ rects++;
+ count--;
+ }
+#if VALIDATE_REGIONS
+ validate(reg, "translate (after)");
+#endif
+ }
+}
+
+void Region::translate(Region& dst, const Region& reg, int dx, int dy)
+{
+ dst = reg;
+ translate(dst, dx, dy);
}
// ----------------------------------------------------------------------------
-// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
-
status_t Region::write(Parcel& parcel) const
{
- int32_t size = mRegion.flatten(NULL);
- parcel.writeInt32(size);
- mRegion.flatten(parcel.writeInplace(size));
+#if VALIDATE_REGIONS
+ validate(*this, "write(Parcel)");
+#endif
+ status_t err;
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ void* buffer = parcel.writeInplace(sizeNeeded);
+ if (!buffer) return NO_MEMORY;
+ ssize_t written = Region::write(buffer, sizeNeeded);
+ if (written < 0) return status_t(written);
return NO_ERROR;
}
status_t Region::read(const Parcel& parcel)
{
- size_t size = parcel.readInt32();
- mRegion.unflatten(parcel.readInplace(size));
+ void const* buffer = parcel.readInplace(sizeof(int32_t));
+ if (!buffer) return NO_MEMORY;
+ const size_t count = *static_cast<int32_t const *>(buffer);
+ void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
+ if (!dummy) return NO_MEMORY;
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ const ssize_t read = Region::read(buffer);
+ if (read < 0) return status_t(read);
+#if VALIDATE_REGIONS
+ validate(*this, "read(Parcel)");
+#endif
return NO_ERROR;
}
ssize_t Region::write(void* buffer, size_t size) const
{
- size_t sizeNeeded = mRegion.flatten(NULL);
+#if VALIDATE_REGIONS
+ validate(*this, "write(buffer)");
+#endif
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
if (sizeNeeded > size) return NO_MEMORY;
- return mRegion.flatten(buffer);
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ *p = count;
+ memcpy(p+1, &mBounds, sizeof(Rect));
+ if (count) {
+ memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+ }
+ return ssize_t(sizeNeeded);
}
ssize_t Region::read(const void* buffer)
{
- return mRegion.unflatten(buffer);
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ const size_t count = *p;
+ memcpy(&mBounds, p+1, sizeof(Rect));
+ mStorage.clear();
+ if (count) {
+ mStorage.insertAt(0, count);
+ memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
+ }
+#if VALIDATE_REGIONS
+ validate(*this, "read(buffer)");
+#endif
+ return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
}
ssize_t Region::writeEmpty(void* buffer, size_t size)
{
- if (size < 4) return NO_MEMORY;
- // this needs to stay in sync with SkRegion
- *static_cast<int32_t*>(buffer) = -1;
- return 4;
+ const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
+ if (sizeNeeded > size) return NO_MEMORY;
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ memset(p, 0, sizeNeeded);
+ return ssize_t(sizeNeeded);
}
bool Region::isEmpty(void* buffer)
{
- // this needs to stay in sync with SkRegion
- return *static_cast<int32_t*>(buffer) == -1;
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ Rect const* const b = reinterpret_cast<Rect const *>(p+1);
+ return b->isEmpty();
}
-size_t Region::rects(Vector<Rect>& rectList) const
+// ----------------------------------------------------------------------------
+
+Region::const_iterator Region::begin() const {
+ return isRect() ? &mBounds : mStorage.array();
+}
+
+Region::const_iterator Region::end() const {
+ return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
+}
+
+Rect const* Region::getArray(size_t* count) const {
+ const_iterator const b(begin());
+ const_iterator const e(end());
+ if (count) *count = e-b;
+ return b;
+}
+
+size_t Region::getRects(Vector<Rect>& rectList) const
{
- rectList.clear();
- if (!isEmpty()) {
- SkRegion::Iterator iterator(mRegion);
- while( !iterator.done() ) {
- const SkIRect& ir(iterator.rect());
- rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
- iterator.next();
- }
+ rectList = mStorage;
+ if (rectList.isEmpty()) {
+ rectList.clear();
+ rectList.add(mBounds);
}
return rectList.size();
}
+// ----------------------------------------------------------------------------
+
void Region::dump(String8& out, const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
-
+ const_iterator head = begin();
+ const_iterator const tail = end();
+
size_t SIZE = 256;
char buffer[SIZE];
-
- snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size());
+
+ snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
+ what, this, tail-head);
out.append(buffer);
- for (size_t i=0 ; i<r.size() ; i++) {
+ while (head != tail) {
snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
out.append(buffer);
+ head++;
}
}
void Region::dump(const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
- LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size());
- for (size_t i=0 ; i<r.size() ; i++) {
+ const_iterator head = begin();
+ const_iterator const tail = end();
+ LOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
+ while (head != tail) {
LOGD(" [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
+ head++;
}
}
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..f6792c4 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,233 +23,786 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
+#include <ui/BufferMapper.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
+#include <pixelflinger/pixelflinger.h>
+
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
-// ---------------------------------------------------------------------------
+// ============================================================================
+// SurfaceBuffer
+// ============================================================================
-Surface::Surface(const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner)
- : mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity),
- mFormat(format), mFlags(flags), mOwner(owner)
+SurfaceBuffer::SurfaceBuffer()
+ : BASE(), mOwner(false), mBufferMapper(BufferMapper::get())
{
- mSwapRectangle.makeInvalid();
- mSurfaceHeapBase[0] = 0;
- mSurfaceHeapBase[1] = 0;
- mHeap[0] = data.heap[0];
- mHeap[1] = data.heap[1];
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
}
-Surface::Surface(Surface const* rhs)
- : mOwner(false)
+SurfaceBuffer::SurfaceBuffer(const Parcel& data)
+ : BASE(), mOwner(true), mBufferMapper(BufferMapper::get())
{
- mToken = rhs->mToken;
- mIdentity= rhs->mIdentity;
- mClient = rhs->mClient;
- mSurface = rhs->mSurface;
- mHeap[0] = rhs->mHeap[0];
- mHeap[1] = rhs->mHeap[1];
- mFormat = rhs->mFormat;
- mFlags = rhs->mFlags;
- mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
- mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
- mSwapRectangle.makeInvalid();
+ // 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();
}
-Surface::~Surface()
+SurfaceBuffer::~SurfaceBuffer()
{
- if (mOwner && mToken>=0 && mClient!=0) {
- mClient->destroySurface(mToken);
+ if (handle && mOwner) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
}
- mClient.clear();
- mSurface.clear();
- mHeap[0].clear();
- mHeap[1].clear();
- IPCThreadState::self()->flushCommands();
}
-sp<Surface> Surface::dup() const
+status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr)
{
- Surface const * r = this;
- if (this && mOwner) {
- // the only reason we need to do this is because of Java's garbage
- // collector: because we're creating a copy of the Surface
- // instead of a reference, we can garantee that when our last
- // reference goes away, the real surface will be deleted.
- // Without this hack (the code is correct too), we'd have to
- // wait for a GC for the surface to go away.
- r = new Surface(this);
+ const Rect lockBounds(width, height);
+ status_t res = lock(usage, lockBounds, vaddr);
+ return res;
+}
+
+status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
+{
+ if (rect.left < 0 || rect.right > this->width ||
+ rect.top < 0 || rect.bottom > this->height) {
+ LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
+ rect.left, rect.top, rect.right, rect.bottom,
+ this->width, this->height);
+ return BAD_VALUE;
}
- return const_cast<Surface*>(r);
+ status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
+ return res;
}
-status_t Surface::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
-}
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->lockSurface(this, info, dirty, blocking);
-}
-
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
-}
-
-status_t Surface::unlock() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockSurface(this);
-}
-
-status_t Surface::setLayer(int32_t layer) {
- return mClient->setLayer(this, layer);
-}
-status_t Surface::setPosition(int32_t x, int32_t y) {
- return mClient->setPosition(this, x, y);
-}
-status_t Surface::setSize(uint32_t w, uint32_t h) {
- return mClient->setSize(this, w, h);
-}
-status_t Surface::hide() {
- return mClient->hide(this);
-}
-status_t Surface::show(int32_t layer) {
- return mClient->show(this, layer);
-}
-status_t Surface::freeze() {
- return mClient->freeze(this);
-}
-status_t Surface::unfreeze() {
- return mClient->unfreeze(this);
-}
-status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
- return mClient->setFlags(this, flags, mask);
-}
-status_t Surface::setTransparentRegionHint(const Region& transparent) {
- return mClient->setTransparentRegionHint(this, transparent);
-}
-status_t Surface::setAlpha(float alpha) {
- return mClient->setAlpha(this, alpha);
-}
-status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
-}
-status_t Surface::setFreezeTint(uint32_t tint) {
- return mClient->setFreezeTint(this, tint);
-}
-
-Region Surface::dirtyRegion() const {
- return mDirtyRegion;
-}
-void Surface::setDirtyRegion(const Region& region) const {
- mDirtyRegion = region;
-}
-const Rect& Surface::swapRectangle() const {
- return mSwapRectangle;
-}
-void Surface::setSwapRectangle(const Rect& r) {
- mSwapRectangle = r;
-}
-
-sp<Surface> Surface::readFromParcel(Parcel* parcel)
+status_t SurfaceBuffer::unlock()
{
- sp<SurfaceComposerClient> client;
- ISurfaceFlingerClient::surface_data_t data;
- sp<IBinder> clientBinder= parcel->readStrongBinder();
- sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
- data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.token = parcel->readInt32();
- data.identity = parcel->readInt32();
- PixelFormat format = parcel->readInt32();
- uint32_t flags = parcel->readInt32();
-
- if (clientBinder != NULL)
- client = SurfaceComposerClient::clientForConnection(clientBinder);
-
- return new Surface(client, surface, data, 0, 0, format, flags, false);
+ status_t res = getBufferMapper().unlock(handle);
+ return res;
}
-status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+status_t SurfaceBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
{
- uint32_t flags=0;
- uint32_t format=0;
- SurfaceID token = -1;
- uint32_t identity = 0;
- sp<SurfaceComposerClient> client;
- sp<ISurface> sur;
- sp<IMemoryHeap> heap[2];
- if (surface->isValid()) {
- token = surface->mToken;
- identity = surface->mIdentity;
- client = surface->mClient;
- sur = surface->mSurface;
- heap[0] = surface->mHeap[0];
- heap[1] = surface->mHeap[1];
- format = surface->mFormat;
- flags = surface->mFlags;
+ if (buffer == NULL) {
+ return BAD_VALUE;
}
- parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
- parcel->writeInt32(token);
- parcel->writeInt32(identity);
- parcel->writeInt32(format);
- parcel->writeInt32(flags);
+ 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;
}
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+// ----------------------------------------------------------------------
+
+static status_t copyBlt(
+ const sp<SurfaceBuffer>& dst,
+ const sp<SurfaceBuffer>& src,
+ const Region& reg)
+{
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ // NOTE: dst and src must be the same format
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::surface_data_t& data,
+ 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)
+{
+}
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
+}
+
+void SurfaceControl::destroy()
+{
+ if (isValid()) {
+ mClient->destroySurface(mToken);
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+void SurfaceControl::clear()
+{
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
+}
+
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
{
if (lhs == 0 || rhs == 0)
return false;
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-void* Surface::heapBase(int i) const
+status_t SurfaceControl::setLayer(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setLayer(mToken, layer);
+}
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setPosition(mToken, x, y);
+}
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setSize(mToken, w, h);
+}
+status_t SurfaceControl::hide() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->hide(mToken);
+}
+status_t SurfaceControl::show(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->show(mToken, layer);
+}
+status_t SurfaceControl::freeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->freeze(mToken);
+}
+status_t SurfaceControl::unfreeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->unfreeze(mToken);
+}
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFlags(mToken, flags, mask);
+}
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setTransparentRegionHint(mToken, transparent);
+}
+status_t SurfaceControl::setAlpha(float alpha) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setAlpha(mToken, alpha);
+}
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setFreezeTint(uint32_t tint) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFreezeTint(mToken, tint);
+}
+
+status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const
{
- void* heapBase = mSurfaceHeapBase[i];
- // map lazily so it doesn't get mapped in clients that don't need it
- if (heapBase == 0) {
- const sp<IMemoryHeap>& heap(mHeap[i]);
- if (heap != 0) {
- heapBase = static_cast<uint8_t*>(heap->base());
- if (heapBase == MAP_FAILED) {
- heapBase = NULL;
- LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
- heap->asBinder().get(), heap.get());
- }
- mSurfaceHeapBase[i] = heapBase;
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
+{
+ uint32_t flags = 0;
+ uint32_t format = 0;
+ SurfaceID token = -1;
+ uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ sp<SurfaceComposerClient> client;
+ sp<ISurface> sur;
+ if (SurfaceControl::isValid(control)) {
+ token = control->mToken;
+ identity = control->mIdentity;
+ client = control->mClient;
+ sur = control->mSurface;
+ width = control->mWidth;
+ height = control->mHeight;
+ format = control->mFormat;
+ flags = control->mFlags;
+ }
+ parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ return NO_ERROR;
+}
+
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
+
+Surface::Surface(const sp<SurfaceControl>& surface)
+ : mClient(surface->mClient), mSurface(surface->mSurface),
+ mToken(surface->mToken), mIdentity(surface->mIdentity),
+ mFormat(surface->mFormat), mFlags(surface->mFlags),
+ mBufferMapper(BufferMapper::get()),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
+{
+ init();
+}
+
+Surface::Surface(const Parcel& parcel)
+ : mBufferMapper(BufferMapper::get())
+{
+ sp<IBinder> clientBinder = parcel.readStrongBinder();
+ mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
+ mToken = parcel.readInt32();
+ mIdentity = parcel.readInt32();
+ mWidth = parcel.readInt32();
+ mHeight = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+
+ if (clientBinder != NULL)
+ mClient = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ init();
+}
+
+void Surface::init()
+{
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+ mSwapRectangle.makeInvalid();
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
+ 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) {
+ getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
}
}
- return heapBase;
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ 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, client.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+
+bool Surface::isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval)
+{
+ return 0;
+}
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+int Surface::query(android_native_window_t* window,
+ int what, int* value)
+{
+ Surface* self = getSelf(window);
+ return self->query(what, value);
+}
+
+int Surface::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ va_list args;
+ va_start(args, operation);
+ Surface* self = getSelf(window);
+ int res = self->perform(operation, args);
+ va_end(args);
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
+{
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ if (err == NO_ERROR) {
+ *buffer = SurfaceBuffer::getSelf(out);
+ }
+ return err;
+}
+
+status_t Surface::lockBuffer(const sp<SurfaceBuffer>& buffer)
+{
+ return lockBuffer(buffer.get());
+}
+
+status_t Surface::queueBuffer(const sp<SurfaceBuffer>& buffer)
+{
+ return queueBuffer(buffer.get());
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ // FIXME: dequeueBuffer() needs proper implementation
+
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ SurfaceID index(mToken);
+
+ int32_t backIdx = cblk->lock_layer(size_t(index),
+ per_client_cblk_t::BLOCKING);
+
+ if (backIdx < 0)
+ return status_t(backIdx);
+
+ 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) || mUsageChanged) {
+ mUsageChanged = false;
+ err = getBufferLocked(backIdx, mUsage);
+ }
+
+ if (err == NO_ERROR) {
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+ // reset the width/height with the what we get from the buffer
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ }
+
+ return err;
+}
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ // FIXME: lockBuffer() needs proper implementation
+ return 0;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
+ }
+
+ // transmit the dirty region
+ SurfaceID index(mToken);
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ _send_dirty_region(lcblk, mDirtyRegion);
+
+ uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+ if (!(newstate & eNextFlipPending))
+ client->signalServer();
+
+ return NO_ERROR;
+}
+
+int Surface::query(int what, int* value)
+{
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = int(mWidth);
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = int(mHeight);
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = int(mFormat);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+int Surface::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ setUsage( va_arg(args, int) );
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ 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) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ sp<SurfaceBuffer> backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer);
+ if (err == NO_ERROR) {
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region scratch(bounds);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+
+ 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) {
+ // content is meaningless in this case and the whole surface
+ // needs to be redrawn.
+ newDirtyRegion.set(bounds);
+ } else {
+ newDirtyRegion.andSelf(bounds);
+ const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
+ if (backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ !(lcblk->flags & eNoCopyBack))
+ {
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer, copyback);
+ }
+ }
+ }
+ mDirtyRegion = newDirtyRegion;
+ mOldDirtyRegion = newDirtyRegion;
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer %d (%p)",
+ mBackbufferIndex, backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0)
+ return BAD_VALUE;
+
+ status_t res = mLockedBuffer->unlock();
+ LOGW_IF(res, "failed unlocking buffer %d (%p)",
+ mBackbufferIndex, mLockedBuffer->handle);
+
+ status_t err = queueBuffer(mLockedBuffer);
+ mLockedBuffer = 0;
+ return err;
+}
+
+void Surface::_send_dirty_region(
+ layer_cblk_t* lcblk, const Region& dirty)
+{
+ const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+ flat_region_t* flat_region = lcblk->region + index;
+ status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+ if (err < NO_ERROR) {
+ // region doesn't fit, use the bounds
+ const Region reg(dirty.bounds());
+ reg.write(flat_region, sizeof(flat_region_t));
+ }
+}
+
+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 = 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;
+ }
+ }
+ return err;
}
}; // namespace android
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..d2cef78 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,27 +29,21 @@
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/IMemory.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
#include <ui/ISurface.h>
#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <ui/Point.h>
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceFlingerSynchro.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include <utils/BpBinder.h>
-
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
@@ -65,7 +59,7 @@
static sp<ISurfaceComposer> gSurfaceManager;
static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions;
-static sp<IMemory> gServerCblkMemory;
+static sp<IMemoryHeap> gServerCblkMemory;
static volatile surface_flinger_cblk_t* gServerCblk;
const sp<ISurfaceComposer>& _get_surface_manager()
@@ -100,7 +94,7 @@
if (gServerCblk == 0) {
gServerCblkMemory = sm->getCblk();
LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
- gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
LOGE_IF(gServerCblk==0, "Can't get server control block address");
}
}
@@ -109,50 +103,8 @@
// ---------------------------------------------------------------------------
-static void copyBlt(const GGLSurface& dst,
- const GGLSurface& src, const Region& reg)
-{
- Region::iterator iterator(reg);
- if (iterator) {
- // NOTE: dst and src must be the same format
- Rect r;
- const size_t bpp = bytesPerPixel(src.format);
- const size_t dbpr = dst.stride * bpp;
- const size_t sbpr = src.stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
- uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-surface_flinger_cblk_t::surface_flinger_cblk_t()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-per_client_cblk_t::per_client_cblk_t()
-{
-}
-
// these functions are used by the clients
-inline status_t per_client_cblk_t::validate(size_t i) const {
+status_t per_client_cblk_t::validate(size_t i) const {
if (uint32_t(i) >= NUM_LAYERS_MAX)
return BAD_INDEX;
if (layers[i].swapState & eInvalidSurface)
@@ -248,8 +200,9 @@
index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
// make sure this buffer is valid
- if (layer->surface[index].bits_offset < 0) {
- return status_t(layer->surface[index].bits_offset);
+ status_t err = layer->surface[index].status;
+ if (err < 0) {
+ return err;
}
if (inspect) {
@@ -273,7 +226,7 @@
uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
{
- // atomically set eFlipRequested and clear eLocked and optionnaly
+ // atomically set eFlipRequested and clear eLocked and optionally
// set eNextFlipPending if eFlipRequested was already set
layer_cblk_t * const layer = layers + i;
@@ -290,7 +243,7 @@
if (oldvalue & eFlipRequested)
newvalue |= eNextFlipPending;
- // if eFlipRequested was alread set, set eNextFlipPending
+ // if eFlipRequested was already set, set eNextFlipPending
} while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
@@ -298,9 +251,9 @@
int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
int(newvalue));
- // from this point, the server can kick in at anytime and use the first
+ // from this point, the server can kick in at any time and use the first
// buffer, so we cannot use it anymore, and we must use the 'other'
- // buffer instead (or wait if it is not availlable yet, see lock_layer).
+ // buffer instead (or wait if it is not available yet, see lock_layer).
return newvalue;
}
@@ -360,9 +313,9 @@
return;
}
- mClient->getControlBlocks(&mControlMemory);
+ mControlMemory = mClient->getControlBlock();
mSignalServer = new SurfaceFlingerSynchro(sm);
- mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+ mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@@ -376,32 +329,6 @@
return mStatus;
}
-status_t SurfaceComposerClient::validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface)
-{
- SurfaceID index = surface->ID();
- if (cblk == 0) {
- LOGE("cblk is null (surface id=%d, identity=%u)",
- index, surface->getIdentity());
- return NO_INIT;
- }
-
- status_t err = cblk->validate(index);
- if (err != NO_ERROR) {
- LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
- index, surface->getIdentity(), err, strerror(-err));
- return err;
- }
-
- if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
- LOGE("using an invalid surface id=%d, identity=%u should be %d",
- index, surface->getIdentity(), cblk->layers[index].identity);
- return NO_INIT;
- }
-
- return NO_ERROR;
-}
-
sp<IBinder> SurfaceComposerClient::connection() const
{
return (mClient != 0) ? mClient->asBinder() : 0;
@@ -437,9 +364,8 @@
{
// this can be called more than once.
- sp<IMemory> controlMemory;
+ sp<IMemoryHeap> controlMemory;
sp<ISurfaceFlingerClient> client;
- sp<IMemoryHeap> surfaceHeap;
{
Mutex::Autolock _lg(gLock);
@@ -462,9 +388,7 @@
delete mPrebuiltLayerState;
mPrebuiltLayerState = 0;
controlMemory = mControlMemory;
- surfaceHeap = mSurfaceHeap;
mControlMemory.clear();
- mSurfaceHeap.clear();
mControl = 0;
mStatus = NO_INIT;
}
@@ -528,7 +452,13 @@
return n;
}
-sp<Surface> SurfaceComposerClient::createSurface(
+
+void SurfaceComposerClient::signalServer()
+{
+ mSignalServer->signal();
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
int pid,
DisplayID display,
uint32_t w,
@@ -536,14 +466,14 @@
PixelFormat format,
uint32_t flags)
{
- sp<Surface> result;
+ sp<SurfaceControl> result;
if (mStatus == NO_ERROR) {
ISurfaceFlingerClient::surface_data_t data;
sp<ISurface> surface = mClient->createSurface(&data, pid,
display, w, h, format, flags);
if (surface != 0) {
if (uint32_t(data.token) < NUM_LAYERS_MAX) {
- result = new Surface(this, surface, data, w, h, format, flags);
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
}
}
}
@@ -568,186 +498,6 @@
return err;
}
-status_t SurfaceComposerClient::nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info)
-{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = surface->mBackbufferIndex;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- info->w = front->w;
- info->h = front->h;
- info->format = front->format;
- info->base = surface->heapBase(1-backIdx);
- info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
- info->bpr = front->bpr;
-
- return 0;
-}
-
-status_t SurfaceComposerClient::lockSurface(
- Surface* surface,
- Surface::SurfaceInfo* other,
- Region* dirty,
- bool blocking)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = cblk->lock_layer(size_t(index),
- per_client_cblk_t::BLOCKING);
- if (backIdx >= 0) {
- surface->mBackbufferIndex = backIdx;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const back = lcblk->surface + backIdx;
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- other->w = back->w;
- other->h = back->h;
- other->format = back->format;
- other->base = surface->heapBase(backIdx);
- other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
- other->bpr = back->bpr;
-
- const Rect bounds(other->w, other->h);
- Region newDirtyRegion;
-
- if (back->flags & surface_info_t::eBufferDirty) {
- /* it is safe to write *back here, because we're guaranteed
- * SurfaceFlinger is not touching it (since it just granted
- * access to us) */
- const_cast<surface_info_t*>(back)->flags &=
- ~surface_info_t::eBufferDirty;
-
- // content is meaningless in this case and the whole surface
- // needs to be redrawn.
-
- newDirtyRegion.set(bounds);
- if (dirty) {
- *dirty = newDirtyRegion;
- }
-
- //if (bytesPerPixel(other->format) == 4) {
- // android_memset32(
- // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
- //} else {
- // android_memset16( // fill with green
- // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
- //}
- }
- else
- {
- if (dirty) {
- dirty->andSelf(Region(bounds));
- newDirtyRegion = *dirty;
- } else {
- newDirtyRegion.set(bounds);
- }
-
- Region copyback;
- if (!(lcblk->flags & eNoCopyBack)) {
- const Region previousDirtyRegion(surface->dirtyRegion());
- copyback = previousDirtyRegion.subtract(newDirtyRegion);
- }
-
- if (!copyback.isEmpty()) {
- // copy front to back
- GGLSurface cb;
- cb.version = sizeof(GGLSurface);
- cb.width = back->w;
- cb.height = back->h;
- cb.stride = back->stride;
- cb.data = (GGLubyte*)surface->heapBase(backIdx);
- cb.data += back->bits_offset;
- cb.format = back->format;
-
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = front->w;
- t.height = front->h;
- t.stride = front->stride;
- t.data = (GGLubyte*)surface->heapBase(1-backIdx);
- t.data += front->bits_offset;
- t.format = front->format;
-
- //const Region copyback(lcblk->region + 1-backIdx);
- copyBlt(cb, t, copyback);
- }
- }
-
- // update dirty region
- surface->setDirtyRegion(newDirtyRegion);
- }
- return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
-}
-
-void SurfaceComposerClient::_signal_server()
-{
- mSignalServer->signal();
-}
-
-void SurfaceComposerClient::_send_dirty_region(
- layer_cblk_t* lcblk, const Region& dirty)
-{
- const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
- flat_region_t* flat_region = lcblk->region + index;
- status_t err = dirty.write(flat_region, sizeof(flat_region_t));
- if (err < NO_ERROR) {
- // region doesn't fit, use the bounds
- const Region reg(dirty.bounds());
- reg.write(flat_region, sizeof(flat_region_t));
- }
-}
-
-status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- Region dirty(surface->dirtyRegion());
- const Rect& swapRect(surface->swapRectangle());
- if (swapRect.isValid()) {
- dirty.set(swapRect);
- }
-
- // transmit the dirty region
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- _send_dirty_region(lcblk, dirty);
- uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
- if (!(newstate & eNextFlipPending))
- _signal_server();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::unlockSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- cblk->unlock_layer(size_t(index));
- return NO_ERROR;
-}
-
void SurfaceComposerClient::openGlobalTransaction()
{
Mutex::Autolock _l(gLock);
@@ -866,14 +616,8 @@
return NO_ERROR;
}
-layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)
{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface.get());
- if (err != NO_ERROR)
- return 0;
-
// API usage error, do nothing.
if (mTransactionOpen<=0) {
LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
@@ -892,11 +636,11 @@
return mStates.editArray() + i;
}
-layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id)
{
layer_state_t* s;
mLock.lock();
- s = _get_state_l(surface);
+ s = _get_state_l(id);
if (!s) mLock.unlock();
return s;
}
@@ -906,9 +650,9 @@
mLock.unlock();
}
-status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::ePositionChanged;
s->x = x;
@@ -917,9 +661,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eSizeChanged;
s->w = w;
@@ -928,9 +672,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eLayerChanged;
s->z = z;
@@ -938,32 +682,32 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::hide(Surface* surface)
+status_t SurfaceComposerClient::hide(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerHidden,
+ return setFlags(id, ISurfaceComposer::eLayerHidden,
ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+ return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::freeze(Surface* surface)
+status_t SurfaceComposerClient::freeze(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+ return setFlags(id, ISurfaceComposer::eLayerFrozen,
ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::unfreeze(Surface* surface)
+status_t SurfaceComposerClient::unfreeze(SurfaceID id)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+ return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::setFlags(Surface* surface,
+status_t SurfaceComposerClient::setFlags(SurfaceID id,
uint32_t flags, uint32_t mask)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eVisibilityChanged;
s->flags &= ~mask;
@@ -973,11 +717,10 @@
return NO_ERROR;
}
-
status_t SurfaceComposerClient::setTransparentRegionHint(
- Surface* surface, const Region& transparentRegion)
+ SurfaceID id, const Region& transparentRegion)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
@@ -985,9 +728,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eAlphaChanged;
s->alpha = alpha;
@@ -996,11 +739,11 @@
}
status_t SurfaceComposerClient::setMatrix(
- Surface* surface,
+ SurfaceID id,
float dsdx, float dtdx,
float dsdy, float dtdy )
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eMatrixChanged;
layer_state_t::matrix22_t matrix;
@@ -1013,9 +756,9 @@
return NO_ERROR;
}
-status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eFreezeTintChanged;
s->tint = tint;
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
index 5cd9755..c81db71 100644
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -14,19 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlingerSynchro"
-
#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
#include <private/ui/SurfaceFlingerSynchro.h>
@@ -34,61 +22,10 @@
// ---------------------------------------------------------------------------
-SurfaceFlingerSynchro::Barrier::Barrier()
- : state(CLOSED) {
-}
-
-SurfaceFlingerSynchro::Barrier::~Barrier() {
-}
-
-void SurfaceFlingerSynchro::Barrier::open() {
- asm volatile ("":::"memory");
- Mutex::Autolock _l(lock);
- state = OPENED;
- cv.broadcast();
-}
-
-void SurfaceFlingerSynchro::Barrier::close() {
- Mutex::Autolock _l(lock);
- state = CLOSED;
-}
-
-void SurfaceFlingerSynchro::Barrier::waitAndClose()
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- cv.wait(lock);
- }
- state = CLOSED;
-}
-
-status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout)
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- int err = cv.waitRelative(lock, timeout);
- if (err != 0)
- return err;
- }
- state = CLOSED;
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
: mSurfaceComposer(flinger)
{
}
-
-SurfaceFlingerSynchro::SurfaceFlingerSynchro()
-{
-}
-
SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
{
}
@@ -99,24 +36,6 @@
return NO_ERROR;
}
-status_t SurfaceFlingerSynchro::wait()
-{
- mBarrier.waitAndClose();
- return NO_ERROR;
-}
-
-status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
-{
- if (timeout == 0)
- return SurfaceFlingerSynchro::wait();
- return mBarrier.waitAndClose(timeout);
-}
-
-void SurfaceFlingerSynchro::open()
-{
- mBarrier.open();
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
new file mode 100644
index 0000000..6cc4a5a
--- /dev/null
+++ b/libs/ui/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ region.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-region
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/ui/tests/region.cpp b/libs/ui/tests/region.cpp
new file mode 100644
index 0000000..0deb2ba
--- /dev/null
+++ b/libs/ui/tests/region.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Debug.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+using namespace android;
+
+int main()
+{
+ Region reg0( Rect( 0, 0, 100, 100 ) );
+ Region reg1 = reg0;
+ Region reg2, reg3;
+
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(150, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(300, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ //reg2 = reg0 | reg0.translate(0, 100);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+
+ //reg3 = reg0 | reg0.translate(0, 150);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+ //reg3.dump("reg3");
+
+ LOGD("---");
+ reg2 = reg0 | reg0.translate(100, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+ reg2.dump("reg2");
+
+ return 0;
+}
+
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 9bdd64a..59409a2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -32,52 +32,24 @@
StopWatch.cpp \
String8.cpp \
String16.cpp \
+ StringArray.cpp \
SystemClock.cpp \
TextOutput.cpp \
Threads.cpp \
- TimerProbe.cpp \
Timers.cpp \
VectorImpl.cpp \
ZipFileCRO.cpp \
ZipFileRO.cpp \
ZipUtils.cpp \
- misc.cpp \
- ported.cpp \
- LogSocket.cpp
+ misc.cpp
-#
-# The cpp files listed here do not belong in the device
-# build. Consult with the swetland before even thinking about
-# putting them in commonSources.
-#
-# They're used by the simulator runtime and by host-side tools like
-# aapt and the simulator front-end.
-#
-hostSources:= \
- InetAddress.cpp \
- Pipe.cpp \
- Socket.cpp \
- ZipEntry.cpp \
- ZipFile.cpp
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
-
-ifeq ($(HOST_OS),linux)
-# Use the futex based mutex and condition variable
-# implementation from android-arm because it's shared mem safe
- LOCAL_SRC_FILES += \
- futex_synchro.c \
- executablepath_linux.cpp
-endif
-ifeq ($(HOST_OS),darwin)
- LOCAL_SRC_FILES += \
- executablepath_darwin.cpp
-endif
+LOCAL_SRC_FILES:= $(commonSources)
LOCAL_MODULE:= libutils
@@ -103,37 +75,18 @@
# we have the common sources, plus some device-specific stuff
LOCAL_SRC_FILES:= \
$(commonSources) \
- Binder.cpp \
- BpBinder.cpp \
- IInterface.cpp \
- IMemory.cpp \
- IPCThreadState.cpp \
- MemoryDealer.cpp \
- MemoryBase.cpp \
- MemoryHeapBase.cpp \
- MemoryHeapPmem.cpp \
- Parcel.cpp \
- ProcessState.cpp \
- IPermissionController.cpp \
- IServiceManager.cpp \
Unicode.cpp \
BackupData.cpp \
BackupHelpers.cpp
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_SRC_FILES += $(hostSources)
-endif
-
ifeq ($(TARGET_OS),linux)
-# Use the futex based mutex and condition variable
-# implementation from android-arm because it's shared mem safe
-LOCAL_SRC_FILES += futex_synchro.c
LOCAL_LDLIBS += -lrt -ldl
endif
LOCAL_C_INCLUDES += \
external/zlib \
external/icu4c/common
+
LOCAL_LDLIBS += -lpthread
LOCAL_SHARED_LIBRARIES := \
@@ -144,15 +97,10 @@
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
-LOCAL_SHARED_LIBRARIES += \
- libdl
+LOCAL_SHARED_LIBRARIES += libdl
endif # linux-x86
endif # sim
LOCAL_MODULE:= libutils
-
-#LOCAL_CFLAGS+=
-#LOCAL_LDFLAGS:=
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index cce754a..0cef35a 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -193,9 +193,11 @@
if ((actual) != (expected)) { \
if ((actual) == 0) { \
m_status = EIO; \
+ m_done = true; \
} else { \
m_status = errno; \
} \
+ LOGD("CHECK_SIZE failed with at line %d m_status='%s'", __LINE__, strerror(m_status)); \
return m_status; \
} \
} while(0)
@@ -203,6 +205,7 @@
do { \
status_t err = skip_padding(); \
if (err != NO_ERROR) { \
+ LOGD("SKIP_PADDING FAILED at line %d", __LINE__); \
m_status = err; \
return err; \
} \
@@ -218,10 +221,19 @@
int amt;
- // No error checking here, in case we're at the end of the stream. Just let read() fail.
- skip_padding();
+ amt = skip_padding();
+ if (amt == EIO) {
+ *done = m_done = true;
+ return NO_ERROR;
+ }
+ else if (amt != NO_ERROR) {
+ return amt;
+ }
amt = read(m_fd, &m_header, sizeof(m_header));
*done = m_done = (amt == 0);
+ if (*done) {
+ return NO_ERROR;
+ }
CHECK_SIZE(amt, sizeof(m_header));
m_pos += sizeof(m_header);
if (type) {
@@ -298,10 +310,12 @@
}
if (m_header.entity.dataSize > 0) {
int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
- return pos == -1 ? (int)errno : (int)NO_ERROR;
- } else {
- return NO_ERROR;
+ if (pos == -1) {
+ return errno;
+ }
}
+ SKIP_PADDING();
+ return NO_ERROR;
}
ssize_t
@@ -325,6 +339,10 @@
m_status = errno;
return -1;
}
+ if (amt == 0) {
+ m_status = EIO;
+ m_done = true;
+ }
m_pos += amt;
return amt;
}
diff --git a/libs/utils/Binder.cpp b/libs/utils/Binder.cpp
deleted file mode 100644
index 37e4685..0000000
--- a/libs/utils/Binder.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/Binder.h>
-
-#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
-{
- return NULL;
-}
-
-BBinder* IBinder::localBinder()
-{
- return NULL;
-}
-
-BpBinder* IBinder::remoteBinder()
-{
- return NULL;
-}
-
-bool IBinder::checkSubclass(const void* /*subclassID*/) const
-{
- return false;
-}
-
-// ---------------------------------------------------------------------------
-
-class BBinder::Extras
-{
-public:
- Mutex mLock;
- BpBinder::ObjectManager mObjects;
-};
-
-// ---------------------------------------------------------------------------
-
-BBinder::BBinder()
- : mExtras(NULL)
-{
-}
-
-bool BBinder::isBinderAlive() const
-{
- return true;
-}
-
-status_t BBinder::pingBinder()
-{
- return NO_ERROR;
-}
-
-String16 BBinder::getInterfaceDescriptor() const
-{
- LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
- return String16();
-}
-
-status_t BBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- data.setDataPosition(0);
-
- status_t err = NO_ERROR;
- switch (code) {
- case PING_TRANSACTION:
- reply->writeInt32(pingBinder());
- break;
- default:
- err = onTransact(code, data, reply, flags);
- break;
- }
-
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
-
- return err;
-}
-
-status_t BBinder::linkToDeath(
- const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
-{
- return INVALID_OPERATION;
-}
-
-status_t BBinder::unlinkToDeath(
- const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
- wp<DeathRecipient>* outRecipient)
-{
- return INVALID_OPERATION;
-}
-
-status_t BBinder::dump(int fd, const Vector<String16>& args)
-{
- return NO_ERROR;
-}
-
-void BBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
- Extras* e = mExtras;
-
- if (!e) {
- e = new Extras;
- if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
- reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
- delete e;
- e = mExtras;
- }
- if (e == 0) return; // out of memory
- }
-
- AutoMutex _l(e->mLock);
- e->mObjects.attach(objectID, object, cleanupCookie, func);
-}
-
-void* BBinder::findObject(const void* objectID) const
-{
- Extras* e = mExtras;
- if (!e) return NULL;
-
- AutoMutex _l(e->mLock);
- return e->mObjects.find(objectID);
-}
-
-void BBinder::detachObject(const void* objectID)
-{
- Extras* e = mExtras;
- if (!e) return;
-
- AutoMutex _l(e->mLock);
- e->mObjects.detach(objectID);
-}
-
-BBinder* BBinder::localBinder()
-{
- return this;
-}
-
-BBinder::~BBinder()
-{
- if (mExtras) delete mExtras;
-}
-
-
-status_t BBinder::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case INTERFACE_TRANSACTION:
- reply->writeString16(getInterfaceDescriptor());
- return NO_ERROR;
-
- case DUMP_TRANSACTION: {
- int fd = data.readFileDescriptor();
- int argc = data.readInt32();
- Vector<String16> args;
- for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
- args.add(data.readString16());
- }
- return dump(fd, args);
- }
- default:
- return UNKNOWN_TRANSACTION;
- }
-}
-
-// ---------------------------------------------------------------------------
-
-enum {
- // This is used to transfer ownership of the remote binder from
- // the BpRefBase object holding it (when it is constructed), to the
- // owner of the BpRefBase object when it first acquires that BpRefBase.
- kRemoteAcquired = 0x00000001
-};
-
-BpRefBase::BpRefBase(const sp<IBinder>& o)
- : mRemote(o.get()), mRefs(NULL), mState(0)
-{
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
-
- if (mRemote) {
- mRemote->incStrong(this); // Removed on first IncStrong().
- mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
- }
-}
-
-BpRefBase::~BpRefBase()
-{
- if (mRemote) {
- if (!(mState&kRemoteAcquired)) {
- mRemote->decStrong(this);
- }
- mRefs->decWeak(this);
- }
-}
-
-void BpRefBase::onFirstRef()
-{
- android_atomic_or(kRemoteAcquired, &mState);
-}
-
-void BpRefBase::onLastStrongRef(const void* id)
-{
- if (mRemote) {
- mRemote->decStrong(this);
- }
-}
-
-bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
-{
- return mRemote ? mRefs->attemptIncStrong(this) : false;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/BpBinder.cpp b/libs/utils/BpBinder.cpp
deleted file mode 100644
index 69ab195..0000000
--- a/libs/utils/BpBinder.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BpBinder"
-//#define LOG_NDEBUG 0
-
-#include <utils/BpBinder.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-
-//#undef LOGV
-//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-BpBinder::ObjectManager::ObjectManager()
-{
-}
-
-BpBinder::ObjectManager::~ObjectManager()
-{
- kill();
-}
-
-void BpBinder::ObjectManager::attach(
- const void* objectID, void* object, void* cleanupCookie,
- IBinder::object_cleanup_func func)
-{
- entry_t e;
- e.object = object;
- e.cleanupCookie = cleanupCookie;
- e.func = func;
-
- if (mObjects.indexOfKey(objectID) >= 0) {
- LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
- objectID, this, object);
- return;
- }
-
- mObjects.add(objectID, e);
-}
-
-void* BpBinder::ObjectManager::find(const void* objectID) const
-{
- const ssize_t i = mObjects.indexOfKey(objectID);
- if (i < 0) return NULL;
- return mObjects.valueAt(i).object;
-}
-
-void BpBinder::ObjectManager::detach(const void* objectID)
-{
- mObjects.removeItem(objectID);
-}
-
-void BpBinder::ObjectManager::kill()
-{
- const size_t N = mObjects.size();
- LOGV("Killing %d objects in manager %p", N, this);
- for (size_t i=0; i<N; i++) {
- const entry_t& e = mObjects.valueAt(i);
- if (e.func != NULL) {
- e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
- }
- }
-
- mObjects.clear();
-}
-
-// ---------------------------------------------------------------------------
-
-BpBinder::BpBinder(int32_t handle)
- : mHandle(handle)
- , mAlive(1)
- , mObitsSent(0)
- , mObituaries(NULL)
-{
- LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
-
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- IPCThreadState::self()->incWeakHandle(handle);
-}
-
-String16 BpBinder::getInterfaceDescriptor() const
-{
- String16 res;
- Parcel send, reply;
- status_t err = const_cast<BpBinder*>(this)->transact(
- INTERFACE_TRANSACTION, send, &reply);
- if (err == NO_ERROR) {
- res = reply.readString16();
- }
- return res;
-}
-
-bool BpBinder::isBinderAlive() const
-{
- return mAlive != 0;
-}
-
-status_t BpBinder::pingBinder()
-{
- Parcel send;
- Parcel reply;
- status_t err = transact(PING_TRANSACTION, send, &reply);
- if (err != NO_ERROR) return err;
- if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
- return (status_t)reply.readInt32();
-}
-
-status_t BpBinder::dump(int fd, const Vector<String16>& args)
-{
- Parcel send;
- Parcel reply;
- send.writeFileDescriptor(fd);
- const size_t numArgs = args.size();
- send.writeInt32(numArgs);
- for (size_t i = 0; i < numArgs; i++) {
- send.writeString16(args[i]);
- }
- status_t err = transact(DUMP_TRANSACTION, send, &reply);
- return err;
-}
-
-status_t BpBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // Once a binder has died, it will never come back to life.
- if (mAlive) {
- status_t status = IPCThreadState::self()->transact(
- mHandle, code, data, reply, flags);
- if (status == DEAD_OBJECT) mAlive = 0;
- return status;
- }
-
- return DEAD_OBJECT;
-}
-
-status_t BpBinder::linkToDeath(
- const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
-{
- Obituary ob;
- ob.recipient = recipient;
- ob.cookie = cookie;
- ob.flags = flags;
-
- LOG_ALWAYS_FATAL_IF(recipient == NULL,
- "linkToDeath(): recipient must be non-NULL");
-
- {
- AutoMutex _l(mLock);
-
- if (!mObitsSent) {
- if (!mObituaries) {
- mObituaries = new Vector<Obituary>;
- if (!mObituaries) {
- return NO_MEMORY;
- }
- LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
- getWeakRefs()->incWeak(this);
- IPCThreadState* self = IPCThreadState::self();
- self->requestDeathNotification(mHandle, this);
- self->flushCommands();
- }
- ssize_t res = mObituaries->add(ob);
- return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
- }
- }
-
- return DEAD_OBJECT;
-}
-
-status_t BpBinder::unlinkToDeath(
- const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
- wp<DeathRecipient>* outRecipient)
-{
- AutoMutex _l(mLock);
-
- if (mObitsSent) {
- return DEAD_OBJECT;
- }
-
- const size_t N = mObituaries ? mObituaries->size() : 0;
- for (size_t i=0; i<N; i++) {
- const Obituary& obit = mObituaries->itemAt(i);
- if ((obit.recipient == recipient
- || (recipient == NULL && obit.cookie == cookie))
- && obit.flags == flags) {
- const uint32_t allFlags = obit.flags|flags;
- if (outRecipient != NULL) {
- *outRecipient = mObituaries->itemAt(i).recipient;
- }
- mObituaries->removeAt(i);
- if (mObituaries->size() == 0) {
- LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
- IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
- self->flushCommands();
- delete mObituaries;
- mObituaries = NULL;
- }
- return NO_ERROR;
- }
- }
-
- return NAME_NOT_FOUND;
-}
-
-void BpBinder::sendObituary()
-{
- LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
- this, mHandle, mObitsSent ? "true" : "false");
-
- mAlive = 0;
- if (mObitsSent) return;
-
- mLock.lock();
- Vector<Obituary>* obits = mObituaries;
- if(obits != NULL) {
- LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
- IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
- self->flushCommands();
- mObituaries = NULL;
- }
- mObitsSent = 1;
- mLock.unlock();
-
- LOGV("Reporting death of proxy %p for %d recipients\n",
- this, obits ? obits->size() : 0);
-
- if (obits != NULL) {
- const size_t N = obits->size();
- for (size_t i=0; i<N; i++) {
- reportOneDeath(obits->itemAt(i));
- }
-
- delete obits;
- }
-}
-
-void BpBinder::reportOneDeath(const Obituary& obit)
-{
- sp<DeathRecipient> recipient = obit.recipient.promote();
- LOGV("Reporting death to recipient: %p\n", recipient.get());
- if (recipient == NULL) return;
-
- recipient->binderDied(this);
-}
-
-
-void BpBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
- AutoMutex _l(mLock);
- LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
- mObjects.attach(objectID, object, cleanupCookie, func);
-}
-
-void* BpBinder::findObject(const void* objectID) const
-{
- AutoMutex _l(mLock);
- return mObjects.find(objectID);
-}
-
-void BpBinder::detachObject(const void* objectID)
-{
- AutoMutex _l(mLock);
- mObjects.detach(objectID);
-}
-
-BpBinder* BpBinder::remoteBinder()
-{
- return this;
-}
-
-BpBinder::~BpBinder()
-{
- LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
-
- IPCThreadState* ipc = IPCThreadState::self();
-
- mLock.lock();
- Vector<Obituary>* obits = mObituaries;
- if(obits != NULL) {
- if (ipc) ipc->clearDeathNotification(mHandle, this);
- mObituaries = NULL;
- }
- mLock.unlock();
-
- if (obits != NULL) {
- // XXX Should we tell any remaining DeathRecipient
- // objects that the last strong ref has gone away, so they
- // are no longer linked?
- delete obits;
- }
-
- if (ipc) {
- ipc->expungeHandle(mHandle, this);
- ipc->decWeakHandle(mHandle);
- }
-}
-
-void BpBinder::onFirstRef()
-{
- LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
- IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->incStrongHandle(mHandle);
-}
-
-void BpBinder::onLastStrongRef(const void* id)
-{
- LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
- IF_LOGV() {
- printRefs();
- }
- IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->decStrongHandle(mHandle);
-}
-
-bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
-{
- LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
- IPCThreadState* ipc = IPCThreadState::self();
- return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 2fdaa71..55b6024 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -311,7 +311,8 @@
} else {
void const* start = 0;
name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
- snprintf(tmp, 256, "pc %08lx %s", uintptr_t(ip)-uintptr_t(start), name);
+ snprintf(tmp, 256, "pc %08lx %s",
+ long(uintptr_t(ip)-uintptr_t(start)), name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp
deleted file mode 100644
index c6d49aa..0000000
--- a/libs/utils/IDataConnection.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Parcel.h>
-
-#include <utils/IDataConnection.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-enum
-{
- CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
-};
-
-class BpDataConnection : public BpInterface<IDataConnection>
-{
-public:
- BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
- : BpInterface<IDataConnection>(impl)
- {
- }
-
- virtual void connect()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IDataConnection::descriptor());
- remote()->transact(CONNECT_TRANSACTION, data, &reply);
- }
-
- virtual void disconnect()
- {
- Parcel data, reply;
- remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code)
- {
- case CONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- connect();
- return NO_ERROR;
- }
-
- case DISCONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- disconnect();
- return NO_ERROR;
- }
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/IInterface.cpp b/libs/utils/IInterface.cpp
deleted file mode 100644
index 6ea8178..0000000
--- a/libs/utils/IInterface.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-sp<IBinder> IInterface::asBinder()
-{
- return this ? onAsBinder() : NULL;
-}
-
-sp<const IBinder> IInterface::asBinder() const
-{
- return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/IMemory.cpp b/libs/utils/IMemory.cpp
deleted file mode 100644
index 429bc2b..0000000
--- a/libs/utils/IMemory.cpp
+++ /dev/null
@@ -1,486 +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.
- */
-
-#define LOG_TAG "IMemory"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <utils/IMemory.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/Atomic.h>
-#include <utils/Parcel.h>
-#include <utils/CallStack.h>
-
-#define VERBOSE 0
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class HeapCache : public IBinder::DeathRecipient
-{
-public:
- HeapCache();
- virtual ~HeapCache();
-
- virtual void binderDied(const wp<IBinder>& who);
-
- sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
- void pin_heap(const sp<IBinder>& binder);
- void free_heap(const sp<IBinder>& binder);
- sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
- void dump_heaps();
-
-private:
- // For IMemory.cpp
- struct heap_info_t {
- sp<IMemoryHeap> heap;
- int32_t count;
- };
-
- void free_heap(const wp<IBinder>& binder);
-
- Mutex mHeapCacheLock;
- KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
-};
-
-static sp<HeapCache> gHeapCache = new HeapCache();
-
-/******************************************************************************/
-
-enum {
- HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpMemoryHeap : public BpInterface<IMemoryHeap>
-{
-public:
- BpMemoryHeap(const sp<IBinder>& impl);
- virtual ~BpMemoryHeap();
-
- virtual int getHeapID() const;
- virtual void* getBase() const;
- virtual size_t getSize() const;
- virtual uint32_t getFlags() const;
-
-private:
- friend class IMemory;
- friend class HeapCache;
-
- // for debugging in this module
- static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
- return gHeapCache->find_heap(binder);
- }
- static inline void free_heap(const sp<IBinder>& binder) {
- gHeapCache->free_heap(binder);
- }
- static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
- return gHeapCache->get_heap(binder);
- }
- static inline void dump_heaps() {
- gHeapCache->dump_heaps();
- }
- void inline pin_heap() const {
- gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
- }
-
- void assertMapped() const;
- void assertReallyMapped() const;
- void pinHeap() const;
-
- mutable volatile int32_t mHeapId;
- mutable void* mBase;
- mutable size_t mSize;
- mutable uint32_t mFlags;
- mutable bool mRealHeap;
- mutable Mutex mLock;
-};
-
-// ----------------------------------------------------------------------------
-
-enum {
- GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpMemory : public BpInterface<IMemory>
-{
-public:
- BpMemory(const sp<IBinder>& impl);
- virtual ~BpMemory();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
-
-private:
- mutable sp<IMemoryHeap> mHeap;
- mutable ssize_t mOffset;
- mutable size_t mSize;
-};
-
-/******************************************************************************/
-
-void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
-{
- sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
- void* const base = realHeap->base();
- if (base == MAP_FAILED)
- return 0;
- return static_cast<char*>(base) + offset;
-}
-
-void* IMemory::pointer() const {
- ssize_t offset;
- sp<IMemoryHeap> heap = getMemory(&offset);
- void* const base = heap!=0 ? heap->base() : MAP_FAILED;
- if (base == MAP_FAILED)
- return 0;
- return static_cast<char*>(base) + offset;
-}
-
-size_t IMemory::size() const {
- size_t size;
- getMemory(NULL, &size);
- return size;
-}
-
-ssize_t IMemory::offset() const {
- ssize_t offset;
- getMemory(&offset);
- return offset;
-}
-
-/******************************************************************************/
-
-BpMemory::BpMemory(const sp<IBinder>& impl)
- : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
-{
-}
-
-BpMemory::~BpMemory()
-{
-}
-
-sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
-{
- if (mHeap == 0) {
- Parcel data, reply;
- data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
- if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
- sp<IBinder> heap = reply.readStrongBinder();
- ssize_t o = reply.readInt32();
- size_t s = reply.readInt32();
- if (heap != 0) {
- mHeap = interface_cast<IMemoryHeap>(heap);
- if (mHeap != 0) {
- mOffset = o;
- mSize = s;
- }
- }
- }
- }
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return mHeap;
-}
-
-// ---------------------------------------------------------------------------
-
-IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnMemory::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GET_MEMORY: {
- CHECK_INTERFACE(IMemory, data, reply);
- ssize_t offset;
- size_t size;
- reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
- reply->writeInt32(offset);
- reply->writeInt32(size);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-
-/******************************************************************************/
-
-BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
- : BpInterface<IMemoryHeap>(impl),
- mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
-{
-}
-
-BpMemoryHeap::~BpMemoryHeap() {
- if (mHeapId != -1) {
- close(mHeapId);
- if (mRealHeap) {
- // by construction we're the last one
- if (mBase != MAP_FAILED) {
- sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
-
- if (VERBOSE) {
- LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
- binder.get(), this, mSize, mHeapId);
- CallStack stack;
- stack.update();
- stack.dump("callstack");
- }
-
- munmap(mBase, mSize);
- }
- } else {
- // remove from list only if it was mapped before
- sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
- free_heap(binder);
- }
- }
-}
-
-void BpMemoryHeap::assertMapped() const
-{
- if (mHeapId == -1) {
- sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
- sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
- heap->assertReallyMapped();
- if (heap->mBase != MAP_FAILED) {
- Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
- mBase = heap->mBase;
- mSize = heap->mSize;
- android_atomic_write( dup( heap->mHeapId ), &mHeapId );
- }
- } else {
- // something went wrong
- free_heap(binder);
- }
- }
-}
-
-void BpMemoryHeap::assertReallyMapped() const
-{
- if (mHeapId == -1) {
-
- // remote call without mLock held, worse case scenario, we end up
- // calling transact() from multiple threads, but that's not a problem,
- // only mmap below must be in the critical section.
-
- Parcel data, reply;
- data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
- status_t err = remote()->transact(HEAP_ID, data, &reply);
- int parcel_fd = reply.readFileDescriptor();
- ssize_t size = reply.readInt32();
- uint32_t flags = reply.readInt32();
-
- LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
- asBinder().get(), parcel_fd, size, err, strerror(-err));
-
- int fd = dup( parcel_fd );
- LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
- parcel_fd, size, err, strerror(errno));
-
- int access = PROT_READ;
- if (!(flags & READ_ONLY)) {
- access |= PROT_WRITE;
- }
-
- Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
- mRealHeap = true;
- mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
- if (mBase == MAP_FAILED) {
- LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
- asBinder().get(), size, fd, strerror(errno));
- close(fd);
- } else {
- if (flags & MAP_ONCE) {
- //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
- // asBinder().get(), size, fd);
- pin_heap();
- }
- mSize = size;
- mFlags = flags;
- android_atomic_write(fd, &mHeapId);
- }
- }
- }
-}
-
-int BpMemoryHeap::getHeapID() const {
- assertMapped();
- return mHeapId;
-}
-
-void* BpMemoryHeap::getBase() const {
- assertMapped();
- return mBase;
-}
-
-size_t BpMemoryHeap::getSize() const {
- assertMapped();
- return mSize;
-}
-
-uint32_t BpMemoryHeap::getFlags() const {
- assertMapped();
- return mFlags;
-}
-
-// ---------------------------------------------------------------------------
-
-IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
-
-status_t BnMemoryHeap::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case HEAP_ID: {
- CHECK_INTERFACE(IMemoryHeap, data, reply);
- reply->writeFileDescriptor(getHeapID());
- reply->writeInt32(getSize());
- reply->writeInt32(getFlags());
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-/*****************************************************************************/
-
-HeapCache::HeapCache()
- : DeathRecipient()
-{
-}
-
-HeapCache::~HeapCache()
-{
-}
-
-void HeapCache::binderDied(const wp<IBinder>& binder)
-{
- //LOGD("binderDied binder=%p", binder.unsafe_get());
- free_heap(binder);
-}
-
-sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
-{
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info = mHeapCache.editValueAt(i);
- LOGD_IF(VERBOSE,
- "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
- binder.get(), info.heap.get(),
- static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
- info.count);
- android_atomic_inc(&info.count);
- return info.heap;
- } else {
- heap_info_t info;
- info.heap = interface_cast<IMemoryHeap>(binder);
- info.count = 1;
- //LOGD("adding binder=%p, heap=%p, count=%d",
- // binder.get(), info.heap.get(), info.count);
- mHeapCache.add(binder, info);
- return info.heap;
- }
-}
-
-void HeapCache::pin_heap(const sp<IBinder>& binder)
-{
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
- android_atomic_inc(&info.count);
- binder->linkToDeath(this);
- } else {
- LOGE("pin_heap binder=%p not found!!!", binder.get());
- }
-}
-
-void HeapCache::free_heap(const sp<IBinder>& binder) {
- free_heap( wp<IBinder>(binder) );
-}
-
-void HeapCache::free_heap(const wp<IBinder>& binder)
-{
- sp<IMemoryHeap> rel;
- {
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
- int32_t c = android_atomic_dec(&info.count);
- if (c == 1) {
- LOGD_IF(VERBOSE,
- "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
- binder.unsafe_get(), info.heap.get(),
- static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
- info.count);
- rel = mHeapCache.valueAt(i).heap;
- mHeapCache.removeItemsAt(i);
- }
- } else {
- LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
- }
- }
-}
-
-sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
-{
- sp<IMemoryHeap> realHeap;
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
- else realHeap = interface_cast<IMemoryHeap>(binder);
- return realHeap;
-}
-
-void HeapCache::dump_heaps()
-{
- Mutex::Autolock _l(mHeapCacheLock);
- int c = mHeapCache.size();
- for (int i=0 ; i<c ; i++) {
- const heap_info_t& info = mHeapCache.valueAt(i);
- BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
- LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
- mHeapCache.keyAt(i).unsafe_get(),
- info.heap.get(), info.count,
- h->mHeapId, h->mBase, h->mSize);
- }
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
deleted file mode 100644
index 04ae142..0000000
--- a/libs/utils/IPCThreadState.cpp
+++ /dev/null
@@ -1,1030 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/IPCThreadState.h>
-
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/TextOutput.h>
-#include <utils/threads.h>
-
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
-
-#include <sys/ioctl.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef HAVE_PTHREADS
-#include <pthread.h>
-#include <sched.h>
-#include <sys/resource.h>
-#endif
-#ifdef HAVE_WIN32_THREADS
-#include <windows.h>
-#endif
-
-
-#if LOG_NDEBUG
-
-#define IF_LOG_TRANSACTIONS() if (false)
-#define IF_LOG_COMMANDS() if (false)
-#define LOG_REMOTEREFS(...)
-#define IF_LOG_REMOTEREFS() if (false)
-#define LOG_THREADPOOL(...)
-#define LOG_ONEWAY(...)
-
-#else
-
-#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
-#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
-#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
-#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
-#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
-#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
-
-#endif
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-static const char* getReturnString(size_t idx);
-static const char* getCommandString(size_t idx);
-static const void* printReturnCommand(TextOutput& out, const void* _cmd);
-static const void* printCommand(TextOutput& out, const void* _cmd);
-
-// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
-// conditionals don't get stripped... but that is probably what we want.
-#if !LOG_NDEBUG
-static const char *kReturnStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
- "BR_OK",
- "BR_TIMEOUT",
- "BR_WAKEUP",
- "BR_TRANSACTION",
- "BR_REPLY",
- "BR_ACQUIRE_RESULT",
- "BR_DEAD_REPLY",
- "BR_TRANSACTION_COMPLETE",
- "BR_INCREFS",
- "BR_ACQUIRE",
- "BR_RELEASE",
- "BR_DECREFS",
- "BR_ATTEMPT_ACQUIRE",
- "BR_EVENT_OCCURRED",
- "BR_NOOP",
- "BR_SPAWN_LOOPER",
- "BR_FINISHED",
- "BR_DEAD_BINDER",
- "BR_CLEAR_DEATH_NOTIFICATION_DONE"
-#endif
-};
-
-static const char *kCommandStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
- "BC_NOOP",
- "BC_TRANSACTION",
- "BC_REPLY",
- "BC_ACQUIRE_RESULT",
- "BC_FREE_BUFFER",
- "BC_TRANSACTION_COMPLETE",
- "BC_INCREFS",
- "BC_ACQUIRE",
- "BC_RELEASE",
- "BC_DECREFS",
- "BC_INCREFS_DONE",
- "BC_ACQUIRE_DONE",
- "BC_ATTEMPT_ACQUIRE",
- "BC_RETRIEVE_ROOT_OBJECT",
- "BC_SET_THREAD_ENTRY",
- "BC_REGISTER_LOOPER",
- "BC_ENTER_LOOPER",
- "BC_EXIT_LOOPER",
- "BC_SYNC",
- "BC_STOP_PROCESS",
- "BC_STOP_SELF",
- "BC_REQUEST_DEATH_NOTIFICATION",
- "BC_CLEAR_DEATH_NOTIFICATION",
- "BC_DEAD_BINDER_DONE"
-#endif
-};
-
-static const char* getReturnString(size_t idx)
-{
- if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
- return kReturnStrings[idx];
- else
- return "unknown";
-}
-
-static const char* getCommandString(size_t idx)
-{
- if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
- return kCommandStrings[idx];
- else
- return "unknown";
-}
-
-static const void* printBinderTransactionData(TextOutput& out, const void* data)
-{
- const binder_transaction_data* btd =
- (const binder_transaction_data*)data;
- out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
- << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
- << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
- << " bytes)" << endl
- << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
- << " bytes)" << endl;
- return btd+1;
-}
-
-static const void* printReturnCommand(TextOutput& out, const void* _cmd)
-{
- static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
-
- const int32_t* cmd = (const int32_t*)_cmd;
- int32_t code = *cmd++;
- if (code == BR_ERROR) {
- out << "BR_ERROR: " << (void*)(*cmd++) << endl;
- return cmd;
- } else if (code < 0 || code >= N) {
- out << "Unknown reply: " << code << endl;
- return cmd;
- }
-
- out << kReturnStrings[code];
- switch (code) {
- case BR_TRANSACTION:
- case BR_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
- } break;
-
- case BR_ACQUIRE_RESULT: {
- const int32_t res = *cmd++;
- out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
- } break;
-
- case BR_INCREFS:
- case BR_ACQUIRE:
- case BR_RELEASE:
- case BR_DECREFS: {
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
- } break;
-
- case BR_ATTEMPT_ACQUIRE: {
- const int32_t p = *cmd++;
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c
- << "), pri=" << p;
- } break;
-
- case BR_DEAD_BINDER:
- case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
- const int32_t c = *cmd++;
- out << ": death cookie " << (void*)c;
- } break;
- }
-
- out << endl;
- return cmd;
-}
-
-static const void* printCommand(TextOutput& out, const void* _cmd)
-{
- static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
-
- const int32_t* cmd = (const int32_t*)_cmd;
- int32_t code = *cmd++;
- if (code < 0 || code >= N) {
- out << "Unknown command: " << code << endl;
- return cmd;
- }
-
- out << kCommandStrings[code];
- switch (code) {
- case BC_TRANSACTION:
- case BC_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
- } break;
-
- case BC_ACQUIRE_RESULT: {
- const int32_t res = *cmd++;
- out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
- } break;
-
- case BC_FREE_BUFFER: {
- const int32_t buf = *cmd++;
- out << ": buffer=" << (void*)buf;
- } break;
-
- case BC_INCREFS:
- case BC_ACQUIRE:
- case BC_RELEASE:
- case BC_DECREFS: {
- const int32_t d = *cmd++;
- out << ": descriptor=" << (void*)d;
- } break;
-
- case BC_INCREFS_DONE:
- case BC_ACQUIRE_DONE: {
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
- } break;
-
- case BC_ATTEMPT_ACQUIRE: {
- const int32_t p = *cmd++;
- const int32_t d = *cmd++;
- out << ": decriptor=" << (void*)d << ", pri=" << p;
- } break;
-
- case BC_REQUEST_DEATH_NOTIFICATION:
- case BC_CLEAR_DEATH_NOTIFICATION: {
- const int32_t h = *cmd++;
- const int32_t c = *cmd++;
- out << ": handle=" << h << " (death cookie " << (void*)c << ")";
- } break;
-
- case BC_DEAD_BINDER_DONE: {
- const int32_t c = *cmd++;
- out << ": death cookie " << (void*)c;
- } break;
- }
-
- out << endl;
- return cmd;
-}
-#endif
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-static bool gShutdown = false;
-
-IPCThreadState* IPCThreadState::self()
-{
- if (gHaveTLS) {
-restart:
- const pthread_key_t k = gTLS;
- IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
- if (st) return st;
- return new IPCThreadState;
- }
-
- if (gShutdown) return NULL;
-
- pthread_mutex_lock(&gTLSMutex);
- if (!gHaveTLS) {
- if (pthread_key_create(&gTLS, threadDestructor) != 0) {
- pthread_mutex_unlock(&gTLSMutex);
- return NULL;
- }
- gHaveTLS = true;
- }
- pthread_mutex_unlock(&gTLSMutex);
- goto restart;
-}
-
-void IPCThreadState::shutdown()
-{
- gShutdown = true;
-
- if (gHaveTLS) {
- // XXX Need to wait for all thread pool threads to exit!
- IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
- if (st) {
- delete st;
- pthread_setspecific(gTLS, NULL);
- }
- gHaveTLS = false;
- }
-}
-
-sp<ProcessState> IPCThreadState::process()
-{
- return mProcess;
-}
-
-status_t IPCThreadState::clearLastError()
-{
- const status_t err = mLastError;
- mLastError = NO_ERROR;
- return err;
-}
-
-int IPCThreadState::getCallingPid()
-{
- return mCallingPid;
-}
-
-int IPCThreadState::getCallingUid()
-{
- return mCallingUid;
-}
-
-int64_t IPCThreadState::clearCallingIdentity()
-{
- int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
- clearCaller();
- return token;
-}
-
-void IPCThreadState::restoreCallingIdentity(int64_t token)
-{
- mCallingUid = (int)(token>>32);
- mCallingPid = (int)token;
-}
-
-void IPCThreadState::clearCaller()
-{
- if (mProcess->supportsProcesses()) {
- mCallingPid = getpid();
- mCallingUid = getuid();
- } else {
- mCallingPid = -1;
- mCallingUid = -1;
- }
-}
-
-void IPCThreadState::flushCommands()
-{
- if (mProcess->mDriverFD <= 0)
- return;
- talkWithDriver(false);
-}
-
-void IPCThreadState::joinThreadPool(bool isMain)
-{
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
-
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
-
- status_t result;
- do {
- int32_t cmd;
-
- // When we've cleared the incoming command queue, process any pending derefs
- if (mIn.dataPosition() >= mIn.dataSize()) {
- size_t numPending = mPendingWeakDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- RefBase::weakref_type* refs = mPendingWeakDerefs[i];
- refs->decWeak(mProcess.get());
- }
- mPendingWeakDerefs.clear();
- }
-
- numPending = mPendingStrongDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- BBinder* obj = mPendingStrongDerefs[i];
- obj->decStrong(mProcess.get());
- }
- mPendingStrongDerefs.clear();
- }
- }
-
- // now get the next command to be processed, waiting if necessary
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- IF_LOG_COMMANDS() {
- alog << "Processing top-level Command: "
- << getReturnString(cmd) << endl;
- }
- result = executeCommand(cmd);
- }
-
- // Let this thread exit the thread pool if it is no longer
- // needed and it is not the main process thread.
- if(result == TIMED_OUT && !isMain) {
- break;
- }
- } while (result != -ECONNREFUSED && result != -EBADF);
-
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
- (void*)pthread_self(), getpid(), (void*)result);
-
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
-}
-
-void IPCThreadState::stopProcess(bool immediate)
-{
- //LOGI("**** STOPPING PROCESS");
- flushCommands();
- int fd = mProcess->mDriverFD;
- mProcess->mDriverFD = -1;
- close(fd);
- //kill(getpid(), SIGKILL);
-}
-
-status_t IPCThreadState::transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
- status_t err = data.errorCheck();
-
- flags |= TF_ACCEPT_FDS;
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
- << handle << " / code " << TypeCode(code) << ": "
- << indent << data << dedent << endl;
- }
-
- if (err == NO_ERROR) {
- LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
- (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
- err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
- }
-
- if (err != NO_ERROR) {
- if (reply) reply->setError(err);
- return (mLastError = err);
- }
-
- if ((flags & TF_ONE_WAY) == 0) {
- if (reply) {
- err = waitForResponse(reply);
- } else {
- Parcel fakeReply;
- err = waitForResponse(&fakeReply);
- }
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
- << handle << ": ";
- if (reply) alog << indent << *reply << dedent << endl;
- else alog << "(none requested)" << endl;
- }
- } else {
- err = waitForResponse(NULL, NULL);
- }
-
- return err;
-}
-
-void IPCThreadState::incStrongHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
- mOut.writeInt32(BC_ACQUIRE);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::decStrongHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
- mOut.writeInt32(BC_RELEASE);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::incWeakHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
- mOut.writeInt32(BC_INCREFS);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::decWeakHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
- mOut.writeInt32(BC_DECREFS);
- mOut.writeInt32(handle);
-}
-
-status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
-{
- mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
- mOut.writeInt32(0); // xxx was thread priority
- mOut.writeInt32(handle);
- status_t result = UNKNOWN_ERROR;
-
- waitForResponse(NULL, &result);
-
-#if LOG_REFCOUNTS
- printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
- handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
-#endif
-
- return result;
-}
-
-void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
-{
-#if LOG_REFCOUNTS
- printf("IPCThreadState::expungeHandle(%ld)\n", handle);
-#endif
- self()->mProcess->expungeHandle(handle, binder);
-}
-
-status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
-{
- mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
- mOut.writeInt32((int32_t)handle);
- mOut.writeInt32((int32_t)proxy);
- return NO_ERROR;
-}
-
-status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
-{
- mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
- mOut.writeInt32((int32_t)handle);
- mOut.writeInt32((int32_t)proxy);
- return NO_ERROR;
-}
-
-IPCThreadState::IPCThreadState()
- : mProcess(ProcessState::self())
-{
- pthread_setspecific(gTLS, this);
- clearCaller();
- mIn.setDataCapacity(256);
- mOut.setDataCapacity(256);
-}
-
-IPCThreadState::~IPCThreadState()
-{
-}
-
-status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
-{
- status_t err;
- status_t statusBuffer;
- err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
- if (err < NO_ERROR) return err;
-
- return waitForResponse(NULL, NULL);
-}
-
-status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
-{
- int32_t cmd;
- int32_t err;
-
- while (1) {
- if ((err=talkWithDriver()) < NO_ERROR) break;
- err = mIn.errorCheck();
- if (err < NO_ERROR) break;
- if (mIn.dataAvail() == 0) continue;
-
- cmd = mIn.readInt32();
-
- IF_LOG_COMMANDS() {
- alog << "Processing waitForResponse Command: "
- << getReturnString(cmd) << endl;
- }
-
- switch (cmd) {
- case BR_TRANSACTION_COMPLETE:
- if (!reply && !acquireResult) goto finish;
- break;
-
- case BR_DEAD_REPLY:
- err = DEAD_OBJECT;
- goto finish;
-
- case BR_FAILED_REPLY:
- err = FAILED_TRANSACTION;
- goto finish;
-
- case BR_ACQUIRE_RESULT:
- {
- LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
- const int32_t result = mIn.readInt32();
- if (!acquireResult) continue;
- *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
- }
- goto finish;
-
- case BR_REPLY:
- {
- binder_transaction_data tr;
- err = mIn.read(&tr, sizeof(tr));
- LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
- if (err != NO_ERROR) goto finish;
-
- if (reply) {
- if ((tr.flags & TF_STATUS_CODE) == 0) {
- reply->ipcSetDataReference(
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t),
- freeBuffer, this);
- } else {
- err = *static_cast<const status_t*>(tr.data.ptr.buffer);
- freeBuffer(NULL,
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), this);
- }
- } else {
- freeBuffer(NULL,
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), this);
- continue;
- }
- }
- goto finish;
-
- default:
- err = executeCommand(cmd);
- if (err != NO_ERROR) goto finish;
- break;
- }
- }
-
-finish:
- if (err != NO_ERROR) {
- if (acquireResult) *acquireResult = err;
- if (reply) reply->setError(err);
- mLastError = err;
- }
-
- return err;
-}
-
-status_t IPCThreadState::talkWithDriver(bool doReceive)
-{
- LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
-
- binder_write_read bwr;
-
- // Is the read buffer empty?
- const bool needRead = mIn.dataPosition() >= mIn.dataSize();
-
- // We don't want to write anything if we are still reading
- // from data left in the input buffer and the caller
- // has requested to read the next data.
- const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
-
- bwr.write_size = outAvail;
- bwr.write_buffer = (long unsigned int)mOut.data();
-
- // This is what we'll read.
- if (doReceive && needRead) {
- bwr.read_size = mIn.dataCapacity();
- bwr.read_buffer = (long unsigned int)mIn.data();
- } else {
- bwr.read_size = 0;
- }
-
- IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- if (outAvail != 0) {
- alog << "Sending commands to driver: " << indent;
- const void* cmds = (const void*)bwr.write_buffer;
- const void* end = ((const uint8_t*)cmds)+bwr.write_size;
- alog << HexDump(cmds, bwr.write_size) << endl;
- while (cmds < end) cmds = printCommand(alog, cmds);
- alog << dedent;
- }
- alog << "Size of receive buffer: " << bwr.read_size
- << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
- }
-
- // Return immediately if there is nothing to do.
- if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
-
- bwr.write_consumed = 0;
- bwr.read_consumed = 0;
- status_t err;
- do {
- IF_LOG_COMMANDS() {
- alog << "About to read/write, write size = " << mOut.dataSize() << endl;
- }
-#if defined(HAVE_ANDROID_OS)
- if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
- err = NO_ERROR;
- else
- err = -errno;
-#else
- err = INVALID_OPERATION;
-#endif
- IF_LOG_COMMANDS() {
- alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
- }
- } while (err == -EINTR);
-
- IF_LOG_COMMANDS() {
- alog << "Our err: " << (void*)err << ", write consumed: "
- << bwr.write_consumed << " (of " << mOut.dataSize()
- << "), read consumed: " << bwr.read_consumed << endl;
- }
-
- if (err >= NO_ERROR) {
- if (bwr.write_consumed > 0) {
- if (bwr.write_consumed < (ssize_t)mOut.dataSize())
- mOut.remove(0, bwr.write_consumed);
- else
- mOut.setDataSize(0);
- }
- if (bwr.read_consumed > 0) {
- mIn.setDataSize(bwr.read_consumed);
- mIn.setDataPosition(0);
- }
- IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- alog << "Remaining data size: " << mOut.dataSize() << endl;
- alog << "Received commands from driver: " << indent;
- const void* cmds = mIn.data();
- const void* end = mIn.data() + mIn.dataSize();
- alog << HexDump(cmds, mIn.dataSize()) << endl;
- while (cmds < end) cmds = printReturnCommand(alog, cmds);
- alog << dedent;
- }
- return NO_ERROR;
- }
-
- return err;
-}
-
-status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
- int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
-{
- binder_transaction_data tr;
-
- tr.target.handle = handle;
- tr.code = code;
- tr.flags = binderFlags;
-
- const status_t err = data.errorCheck();
- if (err == NO_ERROR) {
- tr.data_size = data.ipcDataSize();
- tr.data.ptr.buffer = data.ipcData();
- tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
- tr.data.ptr.offsets = data.ipcObjects();
- } else if (statusBuffer) {
- tr.flags |= TF_STATUS_CODE;
- *statusBuffer = err;
- tr.data_size = sizeof(status_t);
- tr.data.ptr.buffer = statusBuffer;
- tr.offsets_size = 0;
- tr.data.ptr.offsets = NULL;
- } else {
- return (mLastError = err);
- }
-
- mOut.writeInt32(cmd);
- mOut.write(&tr, sizeof(tr));
-
- return NO_ERROR;
-}
-
-sp<BBinder> the_context_object;
-
-void setTheContextObject(sp<BBinder> obj)
-{
- the_context_object = obj;
-}
-
-status_t IPCThreadState::executeCommand(int32_t cmd)
-{
- BBinder* obj;
- RefBase::weakref_type* refs;
- status_t result = NO_ERROR;
-
- switch (cmd) {
- case BR_ERROR:
- result = mIn.readInt32();
- break;
-
- case BR_OK:
- break;
-
- case BR_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- obj->incStrong(mProcess.get());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
- obj->printRefs();
- }
- mOut.writeInt32(BC_ACQUIRE_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_RELEASE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_RELEASE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
- obj->printRefs();
- }
- mPendingStrongDerefs.push(obj);
- break;
-
- case BR_INCREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- refs->incWeak(mProcess.get());
- mOut.writeInt32(BC_INCREFS_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_DECREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- // NOTE: This assertion is not valid, because the object may no
- // longer exist (thus the (BBinder*)cast above resulting in a different
- // memory address).
- //LOG_ASSERT(refs->refBase() == obj,
- // "BR_DECREFS: object %p does not match cookie %p (expected %p)",
- // refs, obj, refs->refBase());
- mPendingWeakDerefs.push(refs);
- break;
-
- case BR_ATTEMPT_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
-
- {
- const bool success = refs->attemptIncStrong(mProcess.get());
- LOG_ASSERT(success && refs->refBase() == obj,
- "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
-
- mOut.writeInt32(BC_ACQUIRE_RESULT);
- mOut.writeInt32((int32_t)success);
- }
- break;
-
- case BR_TRANSACTION:
- {
- binder_transaction_data tr;
- result = mIn.read(&tr, sizeof(tr));
- LOG_ASSERT(result == NO_ERROR,
- "Not enough command data for brTRANSACTION");
- if (result != NO_ERROR) break;
-
- Parcel buffer;
- buffer.ipcSetDataReference(
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), freeBuffer, this);
-
- const pid_t origPid = mCallingPid;
- const uid_t origUid = mCallingUid;
-
- mCallingPid = tr.sender_pid;
- mCallingUid = tr.sender_euid;
-
- //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
-
- Parcel reply;
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_TRANSACTION thr " << (void*)pthread_self()
- << " / obj " << tr.target.ptr << " / code "
- << TypeCode(tr.code) << ": " << indent << buffer
- << dedent << endl
- << "Data addr = "
- << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
- << ", offsets addr="
- << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
- }
- if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- const status_t error = b->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
-
- } else {
- const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- }
-
- //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
- // mCallingPid, origPid, origUid);
-
- if ((tr.flags & TF_ONE_WAY) == 0) {
- LOG_ONEWAY("Sending reply to %d!", mCallingPid);
- sendReply(reply, 0);
- } else {
- LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
- }
-
- mCallingPid = origPid;
- mCallingUid = origUid;
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
- << tr.target.ptr << ": " << indent << reply << dedent << endl;
- }
-
- }
- break;
-
- case BR_DEAD_BINDER:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->sendObituary();
- mOut.writeInt32(BC_DEAD_BINDER_DONE);
- mOut.writeInt32((int32_t)proxy);
- } break;
-
- case BR_CLEAR_DEATH_NOTIFICATION_DONE:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->getWeakRefs()->decWeak(proxy);
- } break;
-
- case BR_FINISHED:
- result = TIMED_OUT;
- break;
-
- case BR_NOOP:
- break;
-
- case BR_SPAWN_LOOPER:
- mProcess->spawnPooledThread(false);
- break;
-
- default:
- printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
- result = UNKNOWN_ERROR;
- break;
- }
-
- if (result != NO_ERROR) {
- mLastError = result;
- }
-
- return result;
-}
-
-void IPCThreadState::threadDestructor(void *st)
-{
- IPCThreadState* const self = static_cast<IPCThreadState*>(st);
- if (self) {
- self->flushCommands();
-#if defined(HAVE_ANDROID_OS)
- ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
-#endif
- delete self;
- }
-}
-
-
-void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie)
-{
- //LOGI("Freeing parcel %p", &parcel);
- IF_LOG_COMMANDS() {
- alog << "Writing BC_FREE_BUFFER for " << data << endl;
- }
- LOG_ASSERT(data != NULL, "Called with NULL data");
- if (parcel != NULL) parcel->closeFileDescriptors();
- IPCThreadState* state = self();
- state->mOut.writeInt32(BC_FREE_BUFFER);
- state->mOut.writeInt32((int32_t)data);
-}
-
-}; // namespace android
diff --git a/libs/utils/IPermissionController.cpp b/libs/utils/IPermissionController.cpp
deleted file mode 100644
index f01d38f..0000000
--- a/libs/utils/IPermissionController.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "PermissionController"
-
-#include <utils/IPermissionController.h>
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/String8.h>
-
-#include <private/utils/Static.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpPermissionController : public BpInterface<IPermissionController>
-{
-public:
- BpPermissionController(const sp<IBinder>& impl)
- : BpInterface<IPermissionController>(impl)
- {
- }
-
- virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
- data.writeString16(permission);
- data.writeInt32(pid);
- data.writeInt32(uid);
- remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
- // fail on exception
- if (reply.readInt32() != 0) return 0;
- return reply.readInt32() != 0;
- }
-};
-
-IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
-
-// ----------------------------------------------------------------------
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnPermissionController::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- //printf("PermissionController received: "); data.print();
- switch(code) {
- case CHECK_PERMISSION_TRANSACTION: {
- CHECK_INTERFACE(IPermissionController, data, reply);
- String16 permission = data.readString16();
- int32_t pid = data.readInt32();
- int32_t uid = data.readInt32();
- bool res = checkPermission(permission, pid, uid);
- // write exception
- reply->writeInt32(0);
- reply->writeInt32(res ? 1 : 0);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
-
diff --git a/libs/utils/IServiceManager.cpp b/libs/utils/IServiceManager.cpp
deleted file mode 100644
index 9beeadd..0000000
--- a/libs/utils/IServiceManager.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ServiceManager"
-
-#include <utils/IServiceManager.h>
-
-#include <utils/Debug.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-
-#include <private/utils/Static.h>
-
-#include <unistd.h>
-
-namespace android {
-
-sp<IServiceManager> defaultServiceManager()
-{
- if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
-
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- if (gDefaultServiceManager == NULL) {
- gDefaultServiceManager = interface_cast<IServiceManager>(
- ProcessState::self()->getContextObject(NULL));
- }
- }
-
- return gDefaultServiceManager;
-}
-
-bool checkCallingPermission(const String16& permission)
-{
- return checkCallingPermission(permission, NULL, NULL);
-}
-
-static String16 _permission("permission");
-
-bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
-{
- IPCThreadState* ipcState = IPCThreadState::self();
- int32_t pid = ipcState->getCallingPid();
- int32_t uid = ipcState->getCallingUid();
- if (outPid) *outPid = pid;
- if (outUid) *outUid= uid;
-
- sp<IPermissionController> pc;
- gDefaultServiceManagerLock.lock();
- pc = gPermissionController;
- gDefaultServiceManagerLock.unlock();
-
- int64_t startTime = 0;
-
- while (true) {
- if (pc != NULL) {
- bool res = pc->checkPermission(permission, pid, uid);
- if (res) {
- if (startTime != 0) {
- LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
- (int)((uptimeMillis()-startTime)/1000),
- String8(permission).string(), uid, pid);
- }
- return res;
- }
-
- // Is this a permission failure, or did the controller go away?
- if (pc->asBinder()->isBinderAlive()) {
- LOGW("Permission failure: %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
- return false;
- }
-
- // Object is dead!
- gDefaultServiceManagerLock.lock();
- if (gPermissionController == pc) {
- gPermissionController = NULL;
- }
- gDefaultServiceManagerLock.unlock();
- }
-
- // Need to retrieve the permission controller.
- sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
- if (binder == NULL) {
- // Wait for the permission controller to come back...
- if (startTime == 0) {
- startTime = uptimeMillis();
- LOGI("Waiting to check permission %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
- }
- sleep(1);
- } else {
- pc = interface_cast<IPermissionController>(binder);
- // Install the new permission controller, and try again.
- gDefaultServiceManagerLock.lock();
- gPermissionController = pc;
- gDefaultServiceManagerLock.unlock();
- }
- }
-}
-
-// ----------------------------------------------------------------------
-
-class BpServiceManager : public BpInterface<IServiceManager>
-{
-public:
- BpServiceManager(const sp<IBinder>& impl)
- : BpInterface<IServiceManager>(impl)
- {
- }
-
- virtual sp<IBinder> getService(const String16& name) const
- {
- unsigned n;
- for (n = 0; n < 5; n++){
- sp<IBinder> svc = checkService(name);
- if (svc != NULL) return svc;
- LOGI("Waiting for sevice %s...\n", String8(name).string());
- sleep(1);
- }
- return NULL;
- }
-
- virtual sp<IBinder> checkService( const String16& name) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
- }
-
- virtual status_t addService(const String16& name, const sp<IBinder>& service)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readInt32() : err;
- }
-
- virtual Vector<String16> listServices()
- {
- Vector<String16> res;
- int n = 0;
-
- for (;;) {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeInt32(n++);
- status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
- if (err != NO_ERROR)
- break;
- res.add(reply.readString16());
- }
- return res;
- }
-};
-
-IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
-
-// ----------------------------------------------------------------------
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnServiceManager::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- //printf("ServiceManager received: "); data.print();
- switch(code) {
- case GET_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
- reply->writeStrongBinder(b);
- return NO_ERROR;
- } break;
- case CHECK_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
- reply->writeStrongBinder(b);
- return NO_ERROR;
- } break;
- case ADD_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = data.readStrongBinder();
- status_t err = addService(which, b);
- reply->writeInt32(err);
- return NO_ERROR;
- } break;
- case LIST_SERVICES_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- Vector<String16> list = listServices();
- const size_t N = list.size();
- reply->writeInt32(N);
- for (size_t i=0; i<N; i++) {
- reply->writeString16(list[i]);
- }
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
-
diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp
deleted file mode 100644
index 39a0a68..0000000
--- a/libs/utils/InetAddress.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-#ifdef HAVE_WINSOCK
-# include <winsock2.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-//# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include <utils/inet_address.h>
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * InetAddress
- * ===========================================================================
- */
-
-// lock for the next couple of functions; could tuck into InetAddress
-static Mutex* gGHBNLock;
-
-/*
- * Lock/unlock access to the hostent struct returned by gethostbyname().
- */
-static inline void lock_gethostbyname(void)
-{
- if (gGHBNLock == NULL)
- gGHBNLock = new Mutex;
- gGHBNLock->lock();
-}
-static inline void unlock_gethostbyname(void)
-{
- assert(gGHBNLock != NULL);
- gGHBNLock->unlock();
-}
-
-
-/*
- * Constructor -- just init members. This is private so that callers
- * are required to use getByName().
- */
-InetAddress::InetAddress(void)
- : mAddress(NULL), mLength(-1), mName(NULL)
-{
-}
-
-/*
- * Destructor -- free address storage.
- */
-InetAddress::~InetAddress(void)
-{
- delete[] (char*) mAddress;
- delete[] mName;
-}
-
-/*
- * Copy constructor.
- */
-InetAddress::InetAddress(const InetAddress& orig)
-{
- *this = orig; // use assignment code
-}
-
-/*
- * Assignment operator.
- */
-InetAddress& InetAddress::operator=(const InetAddress& addr)
-{
- // handle self-assignment
- if (this == &addr)
- return *this;
- // copy mLength and mAddress
- mLength = addr.mLength;
- if (mLength > 0) {
- mAddress = new char[mLength];
- memcpy(mAddress, addr.mAddress, mLength);
- LOG(LOG_DEBUG, "socket",
- "HEY: copied %d bytes in assignment operator\n", mLength);
- } else {
- mAddress = NULL;
- }
- // copy mName
- mName = new char[strlen(addr.mName)+1];
- strcpy(mName, addr.mName);
-
- return *this;
-}
-
-/*
- * Create a new object from a name or a dotted-number IP notation.
- *
- * Returns NULL on failure.
- */
-InetAddress*
-InetAddress::getByName(const char* host)
-{
- InetAddress* newAddr = NULL;
- struct sockaddr_in addr;
- struct hostent* he;
- DurationTimer hostTimer, lockTimer;
-
- // gethostbyname() isn't reentrant, so we need to lock things until
- // we can copy the data out.
- lockTimer.start();
- lock_gethostbyname();
- hostTimer.start();
-
- he = gethostbyname(host);
- if (he == NULL) {
- LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
- unlock_gethostbyname();
- return NULL;
- }
-
- memcpy(&addr.sin_addr, he->h_addr, he->h_length);
- addr.sin_family = he->h_addrtype;
- addr.sin_port = 0;
-
- // got it, unlock us
- hostTimer.stop();
- he = NULL;
- unlock_gethostbyname();
-
- lockTimer.stop();
- if ((long) lockTimer.durationUsecs() > 100000) {
- long lockTime = (long) lockTimer.durationUsecs();
- long hostTime = (long) hostTimer.durationUsecs();
- LOG(LOG_DEBUG, "socket",
- "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
- host, lockTime / 1000000.0, hostTime / 1000000.0,
- (lockTime - hostTime) / 1000000.0);
- }
-
- // Alloc storage and copy it over.
- newAddr = new InetAddress();
- if (newAddr == NULL)
- return NULL;
-
- newAddr->mLength = sizeof(struct sockaddr_in);
- newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
- if (newAddr->mAddress == NULL) {
- delete newAddr;
- return NULL;
- }
- memcpy(newAddr->mAddress, &addr, newAddr->mLength);
-
- // Keep this for debug messages.
- newAddr->mName = new char[strlen(host)+1];
- if (newAddr->mName == NULL) {
- delete newAddr;
- return NULL;
- }
- strcpy(newAddr->mName, host);
-
- return newAddr;
-}
-
-
-/*
- * ===========================================================================
- * InetSocketAddress
- * ===========================================================================
- */
-
-/*
- * Create an address with the host wildcard (INADDR_ANY).
- */
-bool InetSocketAddress::create(int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName("0.0.0.0");
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const InetAddress* addr, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = new InetAddress(*addr); // make a copy
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const char* host, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName(host);
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
deleted file mode 100644
index 55c1b99..0000000
--- a/libs/utils/LogSocket.cpp
+++ /dev/null
@@ -1,129 +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.
- */
-
-
-#ifndef HAVE_WINSOCK
-//#define SOCKETLOG
-#endif
-
-#ifdef SOCKETLOG
-
-#define LOG_TAG "SOCKETLOG"
-
-#include <string.h>
-#include <cutils/log.h>
-#include "utils/LogSocket.h"
-#include "utils/logger.h"
-#include "cutils/hashmap.h"
-
-// defined in //device/data/etc/event-log-tags
-#define SOCKET_CLOSE_LOG 51000
-
-static Hashmap* statsMap = NULL;
-
-#define LOG_LIST_NUMBER 5
-
-typedef struct SocketStats {
- int fd;
- unsigned int send;
- unsigned int recv;
- unsigned int ip;
- unsigned short port;
- short reason;
-}SocketStats;
-
-SocketStats *get_socket_stats(int fd) {
- if (statsMap == NULL) {
- statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
- }
-
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s == NULL) {
- // LOGD("create SocketStats for fd %d", fd);
- s = (SocketStats*) malloc(sizeof(SocketStats));
- memset(s, 0, sizeof(SocketStats));
- s->fd = fd;
- hashmapPut(statsMap, &s->fd, s);
- }
- return s;
-}
-
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
- // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
- SocketStats *s = get_socket_stats(fd);
- s->ip = ip;
- s->port = port;
-}
-
-void add_send_stats(int fd, int send) {
- if (send <=0) {
- LOGE("add_send_stats send %d", send);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->send += send;
- // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-void add_recv_stats(int fd, int recv) {
- if (recv <=0) {
- LOGE("add_recv_stats recv %d", recv);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->recv += recv;
- // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-char* put_int(char* buf, int value) {
- *buf = EVENT_TYPE_INT;
- buf++;
- memcpy(buf, &value, sizeof(int));
- return buf + sizeof(int);
-}
-
-void log_socket_close(int fd, short reason) {
- if (statsMap) {
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s != NULL) {
- if (s->send != 0 || s->recv != 0) {
- s->reason = reason;
- // 5 int + list type need 2 bytes
- char buf[LOG_LIST_NUMBER * 5 + 2];
- buf[0] = EVENT_TYPE_LIST;
- buf[1] = LOG_LIST_NUMBER;
- char* writePos = buf + 2;
- writePos = put_int(writePos, s->send);
- writePos = put_int(writePos, s->recv);
- writePos = put_int(writePos, s->ip);
- writePos = put_int(writePos, s->port);
- writePos = put_int(writePos, s->reason);
-
- android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
- // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
- }
- hashmapRemove(statsMap, &s->fd);
- free(s);
- }
- }
-}
-
-#else
-void add_send_stats(int fd, int send) {}
-void add_recv_stats(int fd, int recv) {}
-void log_socket_close(int fd, short reason) {}
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
-#endif
diff --git a/libs/utils/MemoryBase.cpp b/libs/utils/MemoryBase.cpp
deleted file mode 100644
index f25e11c..0000000
--- a/libs/utils/MemoryBase.cpp
+++ /dev/null
@@ -1,46 +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.
- */
-
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/MemoryBase.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
- ssize_t offset, size_t size)
- : mSize(size), mOffset(offset), mHeap(heap)
-{
-}
-
-sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
-{
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return mHeap;
-}
-
-MemoryBase::~MemoryBase()
-{
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
deleted file mode 100644
index cf8201b..0000000
--- a/libs/utils/MemoryDealer.cpp
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "MemoryDealer"
-
-#include <utils/MemoryDealer.h>
-
-#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-#include <utils/MemoryBase.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/file.h>
-
-namespace android {
-
-
-// ----------------------------------------------------------------------------
-
-class SimpleMemory : public MemoryBase {
-public:
- SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
- virtual ~SimpleMemory();
-};
-
-
-// ----------------------------------------------------------------------------
-
-MemoryDealer::Allocation::Allocation(
- const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
- const sp<IMemory>& memory)
- : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
-{
-}
-
-MemoryDealer::Allocation::~Allocation()
-{
- if (mSize) {
- /* NOTE: it's VERY important to not free allocations of size 0 because
- * they're special as they don't have any record in the allocator
- * and could alias some real allocation (their offset is zero). */
- mDealer->deallocate(mOffset);
- }
-}
-
-sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
- ssize_t* offset, size_t* size) const
-{
- return mMemory->getMemory(offset, size);
-}
-
-// ----------------------------------------------------------------------------
-
-MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
- : mHeap(new SharedHeap(size, flags, name)),
- mAllocator(new SimpleBestFitAllocator(size))
-{
-}
-
-MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
- : mHeap(heap),
- mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
-{
-}
-
-MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
- const sp<AllocatorInterface>& allocator)
- : mHeap(heap), mAllocator(allocator)
-{
-}
-
-MemoryDealer::~MemoryDealer()
-{
-}
-
-sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
-{
- sp<IMemory> memory;
- const ssize_t offset = allocator()->allocate(size, flags);
- if (offset >= 0) {
- sp<IMemory> new_memory = heap()->mapMemory(offset, size);
- if (new_memory != 0) {
- memory = new Allocation(this, offset, size, new_memory);
- } else {
- LOGE("couldn't map [%8x, %d]", offset, size);
- if (size) {
- /* NOTE: it's VERY important to not free allocations of size 0
- * because they're special as they don't have any record in the
- * allocator and could alias some real allocation
- * (their offset is zero). */
- allocator()->deallocate(offset);
- }
- }
- }
- return memory;
-}
-
-void MemoryDealer::deallocate(size_t offset)
-{
- allocator()->deallocate(offset);
-}
-
-void MemoryDealer::dump(const char* what, uint32_t flags) const
-{
- allocator()->dump(what, flags);
-}
-
-const sp<HeapInterface>& MemoryDealer::heap() const {
- return mHeap;
-}
-
-const sp<AllocatorInterface>& MemoryDealer::allocator() const {
- return mAllocator;
-}
-
-// ----------------------------------------------------------------------------
-
-// align all the memory blocks on a cache-line boundary
-const int SimpleBestFitAllocator::kMemoryAlign = 32;
-
-SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
-{
- size_t pagesize = getpagesize();
- mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
-
- chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
- mList.insertHead(node);
-}
-
-SimpleBestFitAllocator::~SimpleBestFitAllocator()
-{
- while(!mList.isEmpty()) {
- delete mList.remove(mList.head());
- }
-}
-
-size_t SimpleBestFitAllocator::size() const
-{
- return mHeapSize;
-}
-
-size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
-{
- Mutex::Autolock _l(mLock);
- ssize_t offset = alloc(size, flags);
- return offset;
-}
-
-status_t SimpleBestFitAllocator::deallocate(size_t offset)
-{
- Mutex::Autolock _l(mLock);
- chunk_t const * const freed = dealloc(offset);
- if (freed) {
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
-}
-
-ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
-{
- if (size == 0) {
- return 0;
- }
- size = (size + kMemoryAlign-1) / kMemoryAlign;
- chunk_t* free_chunk = 0;
- chunk_t* cur = mList.head();
-
- size_t pagesize = getpagesize();
- while (cur) {
- int extra = 0;
- if (flags & PAGE_ALIGNED)
- extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
-
- // best fit
- if (cur->free && (cur->size >= (size+extra))) {
- if ((!free_chunk) || (cur->size < free_chunk->size)) {
- free_chunk = cur;
- }
- if (cur->size == size) {
- break;
- }
- }
- cur = cur->next;
- }
-
- if (free_chunk) {
- const size_t free_size = free_chunk->size;
- free_chunk->free = 0;
- free_chunk->size = size;
- if (free_size > size) {
- int extra = 0;
- if (flags & PAGE_ALIGNED)
- extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
- if (extra) {
- chunk_t* split = new chunk_t(free_chunk->start, extra);
- free_chunk->start += extra;
- mList.insertBefore(free_chunk, split);
- }
-
- LOGE_IF((flags&PAGE_ALIGNED) &&
- ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
- "PAGE_ALIGNED requested, but page is not aligned!!!");
-
- const ssize_t tail_free = free_size - (size+extra);
- if (tail_free > 0) {
- chunk_t* split = new chunk_t(
- free_chunk->start + free_chunk->size, tail_free);
- mList.insertAfter(free_chunk, split);
- }
- }
- return (free_chunk->start)*kMemoryAlign;
- }
- return NO_MEMORY;
-}
-
-SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
-{
- start = start / kMemoryAlign;
- chunk_t* cur = mList.head();
- while (cur) {
- if (cur->start == start) {
- LOG_FATAL_IF(cur->free,
- "block at offset 0x%08lX of size 0x%08lX already freed",
- cur->start*kMemoryAlign, cur->size*kMemoryAlign);
-
- // merge freed blocks together
- chunk_t* freed = cur;
- cur->free = 1;
- do {
- chunk_t* const p = cur->prev;
- chunk_t* const n = cur->next;
- if (p && (p->free || !cur->size)) {
- freed = p;
- p->size += cur->size;
- mList.remove(cur);
- delete cur;
- }
- cur = n;
- } while (cur && cur->free);
-
- #ifndef NDEBUG
- if (!freed->free) {
- dump_l("dealloc (!freed->free)");
- }
- #endif
- LOG_FATAL_IF(!freed->free,
- "freed block at offset 0x%08lX of size 0x%08lX is not free!",
- freed->start * kMemoryAlign, freed->size * kMemoryAlign);
-
- return freed;
- }
- cur = cur->next;
- }
- return 0;
-}
-
-void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
-{
- Mutex::Autolock _l(mLock);
- dump_l(what, flags);
-}
-
-void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
-{
- String8 result;
- dump_l(result, what, flags);
- LOGD("%s", result.string());
-}
-
-void SimpleBestFitAllocator::dump(String8& result,
- const char* what, uint32_t flags) const
-{
- Mutex::Autolock _l(mLock);
- dump_l(result, what, flags);
-}
-
-void SimpleBestFitAllocator::dump_l(String8& result,
- const char* what, uint32_t flags) const
-{
- size_t size = 0;
- int32_t i = 0;
- chunk_t const* cur = mList.head();
-
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
- what, this, (unsigned int)mHeapSize);
-
- result.append(buffer);
-
- while (cur) {
- const char* errs[] = {"", "| link bogus NP",
- "| link bogus PN", "| link bogus NP+PN" };
- int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
- int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
-
- snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
- i, int(cur), int(cur->start*kMemoryAlign),
- int(cur->size*kMemoryAlign),
- int(cur->free) ? "F" : "A",
- errs[np|pn]);
-
- result.append(buffer);
-
- if (!cur->free)
- size += cur->size*kMemoryAlign;
-
- i++;
- cur = cur->next;
- }
- snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
- result.append(buffer);
-}
-
-// ----------------------------------------------------------------------------
-
-
-SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
- : MemoryHeapBase(size, flags, name)
-{
-}
-
-SharedHeap::~SharedHeap()
-{
-}
-
-sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
-{
- return new SimpleMemory(this, offset, size);
-}
-
-
-SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
- ssize_t offset, size_t size)
- : MemoryBase(heap, offset, size)
-{
-#ifndef NDEBUG
- void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
- memset(start_ptr, 0xda, size);
-#endif
-}
-
-SimpleMemory::~SimpleMemory()
-{
- size_t freedOffset = getOffset();
- size_t freedSize = getSize();
-
- // keep the size to unmap in excess
- size_t pagesize = getpagesize();
- size_t start = freedOffset;
- size_t end = start + freedSize;
- start &= ~(pagesize-1);
- end = (end + pagesize-1) & ~(pagesize-1);
-
- // give back to the kernel the pages we don't need
- size_t free_start = freedOffset;
- size_t free_end = free_start + freedSize;
- if (start < free_start)
- start = free_start;
- if (end > free_end)
- end = free_end;
- start = (start + pagesize-1) & ~(pagesize-1);
- end &= ~(pagesize-1);
-
- if (start < end) {
- void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
- size_t size = end-start;
-
-#ifndef NDEBUG
- memset(start_ptr, 0xdf, size);
-#endif
-
- // MADV_REMOVE is not defined on Dapper based Goobuntu
-#ifdef MADV_REMOVE
- if (size) {
- int err = madvise(start_ptr, size, MADV_REMOVE);
- LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
- start_ptr, size, err<0 ? strerror(errno) : "Ok");
- }
-#endif
- }
-}
-
-}; // namespace android
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/utils/MemoryHeapBase.cpp
deleted file mode 100644
index 8251728..0000000
--- a/libs/utils/MemoryHeapBase.cpp
+++ /dev/null
@@ -1,183 +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.
- */
-
-#define LOG_TAG "MemoryHeapBase"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/ashmem.h>
-#include <cutils/atomic.h>
-
-#include <utils/MemoryHeapBase.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapBase::MemoryHeapBase()
- : mFD(-1), mSize(0), mBase(MAP_FAILED),
- mDevice(NULL), mNeedUnmap(false)
-{
-}
-
-MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
- : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
- mDevice(0), mNeedUnmap(false)
-{
- const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
- LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
- if (fd >= 0) {
- if (mapfd(fd, size) == NO_ERROR) {
- if (flags & READ_ONLY) {
- ashmem_set_prot_region(fd, PROT_READ);
- }
- }
- }
-}
-
-MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
- : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
- mDevice(0), mNeedUnmap(false)
-{
- int fd = open(device, O_RDWR);
- LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
- if (fd >= 0) {
- const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- if (mapfd(fd, size) == NO_ERROR) {
- mDevice = device;
- }
- }
-}
-
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
- : 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);
-}
-
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
-{
- if (mFD != -1) {
- return INVALID_OPERATION;
- }
- mFD = fd;
- mBase = base;
- mSize = size;
- mFlags = flags;
- mDevice = device;
- return NO_ERROR;
-}
-
-status_t MemoryHeapBase::mapfd(int fd, size_t size)
-{
- if (size == 0) {
- // try to figure out the size automatically
-#if HAVE_ANDROID_OS
- // first try the PMEM ioctl
- pmem_region reg;
- int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®);
- if (err == 0)
- size = reg.len;
-#endif
- if (size == 0) { // try fstat
- struct stat sb;
- if (fstat(fd, &sb) == 0)
- size = sb.st_size;
- }
- // if it didn't work, let mmap() fail.
- }
-
- if ((mFlags & DONT_MAP_LOCALLY) == 0) {
- void* base = (uint8_t*)mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (base == MAP_FAILED) {
- LOGE("mmap(fd=%d, size=%u) failed (%s)",
- fd, uint32_t(size), strerror(errno));
- close(fd);
- return -errno;
- }
- //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
- mBase = base;
- mNeedUnmap = true;
- } else {
- mBase = 0; // not MAP_FAILED
- mNeedUnmap = false;
- }
- mFD = fd;
- mSize = size;
- return NO_ERROR;
-}
-
-MemoryHeapBase::~MemoryHeapBase()
-{
- dispose();
-}
-
-void MemoryHeapBase::dispose()
-{
- int fd = android_atomic_or(-1, &mFD);
- if (fd >= 0) {
- if (mNeedUnmap) {
- //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
- munmap(mBase, mSize);
- }
- mBase = 0;
- mSize = 0;
- close(fd);
- }
-}
-
-int MemoryHeapBase::getHeapID() const {
- return mFD;
-}
-
-void* MemoryHeapBase::getBase() const {
- return mBase;
-}
-
-size_t MemoryHeapBase::getSize() const {
- return mSize;
-}
-
-uint32_t MemoryHeapBase::getFlags() const {
- return mFlags;
-}
-
-const char* MemoryHeapBase::getDevice() const {
- return mDevice;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
deleted file mode 100644
index eba2b30..0000000
--- a/libs/utils/MemoryHeapPmem.cpp
+++ /dev/null
@@ -1,248 +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.
- */
-
-#define LOG_TAG "MemoryHeapPmem"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
- : BnMemory(), mClientHeap(heap)
-{
-}
-
-MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
- if (mClientHeap != NULL) {
- mClientHeap->remove(this);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
-public:
- SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
- virtual ~SubRegionMemory();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
-private:
- friend class MemoryHeapPmem;
- void revoke();
- size_t mSize;
- ssize_t mOffset;
-};
-
-SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
- ssize_t offset, size_t size)
- : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
-{
-#ifndef NDEBUG
- void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
- memset(start_ptr, 0xda, size);
-#endif
-
-#if HAVE_ANDROID_OS
- if (size > 0) {
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = heap->heapID();
- struct pmem_region sub = { offset, size };
- int err = ioctl(our_fd, PMEM_MAP, &sub);
- LOGE_IF(err<0, "PMEM_MAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
-}
-#endif
-}
-
-sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
-{
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return getHeap();
-}
-
-SubRegionMemory::~SubRegionMemory()
-{
- revoke();
-}
-
-
-void SubRegionMemory::revoke()
-{
- // NOTE: revoke() doesn't need to be protected by a lock because it
- // can only be called from MemoryHeapPmem::revoke(), which means
- // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
- // which means MemoryHeapPmem::revoke() wouldn't have been able to
- // promote() it.
-
-#if HAVE_ANDROID_OS
- if (mSize != NULL) {
- const sp<MemoryHeapPmem>& heap(getHeap());
- int our_fd = heap->heapID();
- struct pmem_region sub;
- sub.offset = mOffset;
- sub.len = mSize;
- int err = ioctl(our_fd, PMEM_UNMAP, &sub);
- LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- mSize = 0;
- }
-#endif
-}
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
- uint32_t flags)
- : HeapInterface(), MemoryHeapBase()
-{
- char const * const device = pmemHeap->getDevice();
-#if HAVE_ANDROID_OS
- if (device) {
- int fd = open(device, O_RDWR);
- LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
- if (fd >= 0) {
- int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
- if (err < 0) {
- LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
- strerror(errno), fd, pmemHeap->heapID());
- close(fd);
- } else {
- // everything went well...
- mParentHeap = pmemHeap;
- MemoryHeapBase::init(fd,
- pmemHeap->getBase(),
- pmemHeap->getSize(),
- pmemHeap->getFlags() | flags,
- device);
- }
- }
- }
-#else
- mParentHeap = pmemHeap;
- MemoryHeapBase::init(
- dup(pmemHeap->heapID()),
- pmemHeap->getBase(),
- pmemHeap->getSize(),
- pmemHeap->getFlags() | flags,
- device);
-#endif
-}
-
-MemoryHeapPmem::~MemoryHeapPmem()
-{
-}
-
-sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
-{
- sp<MemoryPmem> memory = createMemory(offset, size);
- if (memory != 0) {
- Mutex::Autolock _l(mLock);
- mAllocations.add(memory);
- }
- return memory;
-}
-
-sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
- size_t offset, size_t size)
-{
- sp<SubRegionMemory> memory;
- if (heapID() > 0)
- memory = new SubRegionMemory(this, offset, size);
- return memory;
-}
-
-status_t MemoryHeapPmem::slap()
-{
-#if HAVE_ANDROID_OS
- size_t size = getSize();
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = getHeapID();
- struct pmem_region sub = { 0, size };
- int err = ioctl(our_fd, PMEM_MAP, &sub);
- LOGE_IF(err<0, "PMEM_MAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- return -errno;
-#else
- return NO_ERROR;
-#endif
-}
-
-status_t MemoryHeapPmem::unslap()
-{
-#if HAVE_ANDROID_OS
- size_t size = getSize();
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = getHeapID();
- struct pmem_region sub = { 0, size };
- int err = ioctl(our_fd, PMEM_UNMAP, &sub);
- LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- return -errno;
-#else
- return NO_ERROR;
-#endif
-}
-
-void MemoryHeapPmem::revoke()
-{
- SortedVector< wp<MemoryPmem> > allocations;
-
- { // scope for lock
- Mutex::Autolock _l(mLock);
- allocations = mAllocations;
- }
-
- ssize_t count = allocations.size();
- for (ssize_t i=0 ; i<count ; i++) {
- sp<MemoryPmem> memory(allocations[i].promote());
- if (memory != 0)
- memory->revoke();
- }
-}
-
-void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
-{
- Mutex::Autolock _l(mLock);
- mAllocations.remove(memory);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
deleted file mode 100644
index b0e3750..0000000
--- a/libs/utils/Parcel.cpp
+++ /dev/null
@@ -1,1363 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Parcel"
-//#define LOG_NDEBUG 0
-
-#include <utils/Parcel.h>
-
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
-#include <utils/Debug.h>
-#include <utils/ProcessState.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-#include <utils/TextOutput.h>
-#include <utils/misc.h>
-
-#include <private/utils/binder_module.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#ifndef INT32_MAX
-#define INT32_MAX ((int32_t)(2147483647))
-#endif
-
-#define LOG_REFS(...)
-//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
-
-// ---------------------------------------------------------------------------
-
-#define PAD_SIZE(s) (((s)+3)&~3)
-
-// XXX This can be made public if we want to provide
-// support for typed data.
-struct small_flat_data
-{
- uint32_t type;
- uint32_t data;
-};
-
-namespace android {
-
-void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
-{
- switch (obj.type) {
- case BINDER_TYPE_BINDER:
- if (obj.binder) {
- LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
- static_cast<IBinder*>(obj.cookie)->incStrong(who);
- }
- return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
- return;
- case BINDER_TYPE_HANDLE: {
- const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
- if (b != NULL) {
- LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
- b->incStrong(who);
- }
- return;
- }
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != NULL) b.get_refs()->incWeak(who);
- return;
- }
- case BINDER_TYPE_FD: {
- // intentionally blank -- nothing to do to acquire this, but we do
- // recognize it as a legitimate object type.
- return;
- }
- }
-
- LOGD("Invalid object type 0x%08lx", obj.type);
-}
-
-void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
-{
- switch (obj.type) {
- case BINDER_TYPE_BINDER:
- if (obj.binder) {
- LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
- static_cast<IBinder*>(obj.cookie)->decStrong(who);
- }
- return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
- return;
- case BINDER_TYPE_HANDLE: {
- const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
- if (b != NULL) {
- LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
- b->decStrong(who);
- }
- return;
- }
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != NULL) b.get_refs()->decWeak(who);
- return;
- }
- case BINDER_TYPE_FD: {
- if (obj.cookie != (void*)0) close(obj.handle);
- return;
- }
- }
-
- LOGE("Invalid object type 0x%08lx", obj.type);
-}
-
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
-{
- return out->writeObject(flat, false);
-}
-
-status_t flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, Parcel* out)
-{
- flat_binder_object obj;
-
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- IBinder *local = binder->localBinder();
- if (!local) {
- BpBinder *proxy = binder->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = local->getWeakRefs();
- obj.cookie = local;
- }
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- }
-
- return finish_flatten_binder(binder, obj, out);
-}
-
-status_t flatten_binder(const sp<ProcessState>& proc,
- const wp<IBinder>& binder, Parcel* out)
-{
- flat_binder_object obj;
-
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- sp<IBinder> real = binder.promote();
- if (real != NULL) {
- IBinder *local = real->localBinder();
- if (!local) {
- BpBinder *proxy = real->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_WEAK_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_WEAK_BINDER;
- obj.binder = binder.get_refs();
- obj.cookie = binder.unsafe_get();
- }
- return finish_flatten_binder(real, obj, out);
- }
-
- // XXX How to deal? In order to flatten the given binder,
- // we need to probe it for information, which requires a primary
- // reference... but we don't have one.
- //
- // The OpenBinder implementation uses a dynamic_cast<> here,
- // but we can't do that with the different reference counting
- // implementation we are using.
- LOGE("Unable to unflatten Binder weak reference!");
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- return finish_flatten_binder(NULL, obj, out);
-
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- return finish_flatten_binder(NULL, obj, out);
- }
-}
-
-inline static status_t finish_unflatten_binder(
- BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
-{
- return NO_ERROR;
-}
-
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_BINDER:
- *out = static_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, wp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_BINDER:
- *out = static_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_WEAK_BINDER:
- if (flat->binder != NULL) {
- out->set_object_and_refs(
- static_cast<IBinder*>(flat->cookie),
- static_cast<RefBase::weakref_type*>(flat->binder));
- } else {
- *out = NULL;
- }
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_HANDLE:
- case BINDER_TYPE_WEAK_HANDLE:
- *out = proc->getWeakProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
-// ---------------------------------------------------------------------------
-
-Parcel::Parcel()
-{
- initState();
-}
-
-Parcel::~Parcel()
-{
- freeDataNoInit();
-}
-
-const uint8_t* Parcel::data() const
-{
- return mData;
-}
-
-size_t Parcel::dataSize() const
-{
- return (mDataSize > mDataPos ? mDataSize : mDataPos);
-}
-
-size_t Parcel::dataAvail() const
-{
- // TODO: decide what to do about the possibility that this can
- // report an available-data size that exceeds a Java int's max
- // positive value, causing havoc. Fortunately this will only
- // happen if someone constructs a Parcel containing more than two
- // gigabytes of data, which on typical phone hardware is simply
- // not possible.
- return dataSize() - dataPosition();
-}
-
-size_t Parcel::dataPosition() const
-{
- return mDataPos;
-}
-
-size_t Parcel::dataCapacity() const
-{
- return mDataCapacity;
-}
-
-status_t Parcel::setDataSize(size_t size)
-{
- status_t err;
- err = continueWrite(size);
- if (err == NO_ERROR) {
- mDataSize = size;
- LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
- }
- return err;
-}
-
-void Parcel::setDataPosition(size_t pos) const
-{
- mDataPos = pos;
- mNextObjectHint = 0;
-}
-
-status_t Parcel::setDataCapacity(size_t size)
-{
- if (size > mDataSize) return continueWrite(size);
- return NO_ERROR;
-}
-
-status_t Parcel::setData(const uint8_t* buffer, size_t len)
-{
- status_t err = restartWrite(len);
- if (err == NO_ERROR) {
- memcpy(const_cast<uint8_t*>(data()), buffer, len);
- mDataSize = len;
- mFdsKnown = false;
- }
- return err;
-}
-
-status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
-{
- const sp<ProcessState> proc(ProcessState::self());
- status_t err;
- uint8_t *data = parcel->mData;
- size_t *objects = parcel->mObjects;
- size_t size = parcel->mObjectsSize;
- int startPos = mDataPos;
- int firstIndex = -1, lastIndex = -2;
-
- if (len == 0) {
- return NO_ERROR;
- }
-
- // range checks against the source parcel size
- if ((offset > parcel->mDataSize)
- || (len > parcel->mDataSize)
- || (offset + len > parcel->mDataSize)) {
- return BAD_VALUE;
- }
-
- // Count objects in range
- for (int i = 0; i < (int) size; i++) {
- size_t off = objects[i];
- if ((off >= offset) && (off < offset + len)) {
- if (firstIndex == -1) {
- firstIndex = i;
- }
- lastIndex = i;
- }
- }
- int numObjects = lastIndex - firstIndex + 1;
-
- // grow data
- err = growData(len);
- if (err != NO_ERROR) {
- return err;
- }
-
- // append data
- memcpy(mData + mDataPos, data + offset, len);
- mDataPos += len;
- mDataSize += len;
-
- if (numObjects > 0) {
- // grow objects
- if (mObjectsCapacity < mObjectsSize + numObjects) {
- int newSize = ((mObjectsSize + numObjects)*3)/2;
- size_t *objects =
- (size_t*)realloc(mObjects, newSize*sizeof(size_t));
- if (objects == (size_t*)0) {
- return NO_MEMORY;
- }
- mObjects = objects;
- mObjectsCapacity = newSize;
- }
-
- // append and acquire objects
- int idx = mObjectsSize;
- for (int i = firstIndex; i <= lastIndex; i++) {
- size_t off = objects[i] - offset + startPos;
- mObjects[idx++] = off;
- mObjectsSize++;
-
- flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData + off);
- acquire_object(proc, *flat, this);
-
- if (flat->type == BINDER_TYPE_FD) {
- // If this is a file descriptor, we need to dup it so the
- // new Parcel now owns its own fd, and can declare that we
- // officially know we have fds.
- flat->handle = dup(flat->handle);
- flat->cookie = (void*)1;
- mHasFds = mFdsKnown = true;
- }
- }
- }
-
- return NO_ERROR;
-}
-
-bool Parcel::hasFileDescriptors() const
-{
- if (!mFdsKnown) {
- scanForFds();
- }
- return mHasFds;
-}
-
-status_t Parcel::writeInterfaceToken(const String16& interface)
-{
- // currently the interface identification token is just its name as a string
- return writeString16(interface);
-}
-
-bool Parcel::enforceInterface(const String16& interface) const
-{
- String16 str = readString16();
- if (str == interface) {
- return true;
- } else {
- LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
- String8(interface).string(), String8(str).string());
- return false;
- }
-}
-
-const size_t* Parcel::objects() const
-{
- return mObjects;
-}
-
-size_t Parcel::objectsCount() const
-{
- return mObjectsSize;
-}
-
-status_t Parcel::errorCheck() const
-{
- return mError;
-}
-
-void Parcel::setError(status_t err)
-{
- mError = err;
-}
-
-status_t Parcel::finishWrite(size_t len)
-{
- //printf("Finish write of %d\n", len);
- mDataPos += len;
- LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
- if (mDataPos > mDataSize) {
- mDataSize = mDataPos;
- LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
- }
- //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
- return NO_ERROR;
-}
-
-status_t Parcel::writeUnpadded(const void* data, size_t len)
-{
- size_t end = mDataPos + len;
- if (end < mDataPos) {
- // integer overflow
- return BAD_VALUE;
- }
-
- if (end <= mDataCapacity) {
-restart_write:
- memcpy(mData+mDataPos, data, len);
- return finishWrite(len);
- }
-
- status_t err = growData(len);
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::write(const void* data, size_t len)
-{
- void* const d = writeInplace(len);
- if (d) {
- memcpy(d, data, len);
- return NO_ERROR;
- }
- return mError;
-}
-
-void* Parcel::writeInplace(size_t len)
-{
- const size_t padded = PAD_SIZE(len);
-
- // sanity check for integer overflow
- if (mDataPos+padded < mDataPos) {
- return NULL;
- }
-
- if ((mDataPos+padded) <= mDataCapacity) {
-restart_write:
- //printf("Writing %ld bytes, padded to %ld\n", len, padded);
- uint8_t* const data = mData+mDataPos;
-
- // Need to pad at end?
- if (padded != len) {
-#if BYTE_ORDER == BIG_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
- };
-#endif
-#if BYTE_ORDER == LITTLE_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
- };
-#endif
- //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
- // *reinterpret_cast<void**>(data+padded-4));
- *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
- }
-
- finishWrite(padded);
- return data;
- }
-
- status_t err = growData(padded);
- if (err == NO_ERROR) goto restart_write;
- return NULL;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-status_t Parcel::writeDouble(double val)
-{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<double*>(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::writeCString(const char* str)
-{
- return write(str, strlen(str)+1);
-}
-
-status_t Parcel::writeString8(const String8& str)
-{
- status_t err = writeInt32(str.bytes());
- if (err == NO_ERROR) {
- err = write(str.string(), str.bytes()+1);
- }
- return err;
-}
-
-status_t Parcel::writeString16(const String16& str)
-{
- return writeString16(str.string(), str.size());
-}
-
-status_t Parcel::writeString16(const char16_t* str, size_t len)
-{
- if (str == NULL) return writeInt32(-1);
-
- status_t err = writeInt32(len);
- if (err == NO_ERROR) {
- len *= sizeof(char16_t);
- uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
- if (data) {
- memcpy(data, str, len);
- *reinterpret_cast<char16_t*>(data+len) = 0;
- return NO_ERROR;
- }
- err = mError;
- }
- return err;
-}
-
-status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
-status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
-status_t Parcel::writeNativeHandle(const native_handle* handle)
-{
- if (handle->version != sizeof(native_handle))
- return BAD_TYPE;
-
- status_t err;
- err = writeInt32(handle->numFds);
- if (err != NO_ERROR) return err;
-
- err = writeInt32(handle->numInts);
- if (err != NO_ERROR) return err;
-
- for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++)
- err = writeDupFileDescriptor(handle->data[i]);
-
- if (err != NO_ERROR) {
- LOGD("write native handle, write dup fd failed");
- return err;
- }
- err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);
- return err;
-}
-
-status_t Parcel::writeFileDescriptor(int fd)
-{
- flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj.handle = fd;
- obj.cookie = (void*)0;
- return writeObject(obj, true);
-}
-
-status_t Parcel::writeDupFileDescriptor(int fd)
-{
- flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj.handle = dup(fd);
- obj.cookie = (void*)1;
- return writeObject(obj, true);
-}
-
-status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
-{
- const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
- const bool enoughObjects = mObjectsSize < mObjectsCapacity;
- if (enoughData && enoughObjects) {
-restart_write:
- *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
-
- // Need to write meta-data?
- if (nullMetaData || val.binder != NULL) {
- mObjects[mObjectsSize] = mDataPos;
- acquire_object(ProcessState::self(), val, this);
- mObjectsSize++;
- }
-
- // remember if it's a file descriptor
- if (val.type == BINDER_TYPE_FD) {
- mHasFds = mFdsKnown = true;
- }
-
- return finishWrite(sizeof(flat_binder_object));
- }
-
- if (!enoughData) {
- const status_t err = growData(sizeof(val));
- if (err != NO_ERROR) return err;
- }
- if (!enoughObjects) {
- size_t newSize = ((mObjectsSize+2)*3)/2;
- size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
- if (objects == NULL) return NO_MEMORY;
- mObjects = objects;
- mObjectsCapacity = newSize;
- }
-
- goto restart_write;
-}
-
-
-void Parcel::remove(size_t start, size_t amt)
-{
- LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
-}
-
-status_t Parcel::read(void* outData, size_t len) const
-{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
- memcpy(outData, mData+mDataPos, len);
- mDataPos += PAD_SIZE(len);
- LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
- return NO_ERROR;
- }
- return NOT_ENOUGH_DATA;
-}
-
-const void* Parcel::readInplace(size_t len) const
-{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += PAD_SIZE(len);
- LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
- return data;
- }
- return NULL;
-}
-
-status_t Parcel::readInt32(int32_t *pArg) const
-{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- *pArg = *reinterpret_cast<const int32_t*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
-}
-
-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;
-}
-
-
-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;
- }
-}
-
-
-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;
-}
-
-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;
- }
-}
-
-
-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;
-}
-
-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;
- }
-}
-
-
-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;
-}
-
-
-const char* Parcel::readCString() const
-{
- const size_t avail = mDataSize-mDataPos;
- if (avail > 0) {
- const char* str = reinterpret_cast<const char*>(mData+mDataPos);
- // is the string's trailing NUL within the parcel's valid bounds?
- const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
- if (eos) {
- const size_t len = eos - str;
- mDataPos += PAD_SIZE(len+1);
- LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
- return str;
- }
- }
- return NULL;
-}
-
-String8 Parcel::readString8() const
-{
- int32_t size = readInt32();
- // watch for potential int overflow adding 1 for trailing NUL
- if (size > 0 && size < INT32_MAX) {
- const char* str = (const char*)readInplace(size+1);
- if (str) return String8(str, size);
- }
- return String8();
-}
-
-String16 Parcel::readString16() const
-{
- size_t len;
- const char16_t* str = readString16Inplace(&len);
- if (str) return String16(str, len);
- LOGE("Reading a NULL string not supported here.");
- return String16();
-}
-
-const char16_t* Parcel::readString16Inplace(size_t* outLen) const
-{
- int32_t size = readInt32();
- // watch for potential int overflow from size+1
- if (size >= 0 && size < INT32_MAX) {
- *outLen = size;
- const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
- if (str != NULL) {
- return str;
- }
- }
- *outLen = 0;
- return NULL;
-}
-
-sp<IBinder> Parcel::readStrongBinder() const
-{
- sp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
-wp<IBinder> Parcel::readWeakBinder() const
-{
- wp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
-
-native_handle* Parcel::readNativeHandle() const
-{
- int numFds, numInts;
- status_t err;
- err = readInt32(&numFds);
- if (err != NO_ERROR) return 0;
- err = readInt32(&numInts);
- if (err != NO_ERROR) return 0;
-
- native_handle* h = native_handle_create(numFds, numInts);
- for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
- h->data[i] = dup(readFileDescriptor());
- if (h->data[i] < 0) err = BAD_VALUE;
- }
- err = read(h->data + numFds, sizeof(int)*numInts);
- if (err != NO_ERROR) {
- native_handle_close(h);
- native_handle_delete(h);
- h = 0;
- }
- return h;
-}
-
-
-int Parcel::readFileDescriptor() const
-{
- const flat_binder_object* flat = readObject(true);
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_FD:
- //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
- return flat->handle;
- }
- }
- return BAD_TYPE;
-}
-
-const flat_binder_object* Parcel::readObject(bool nullMetaData) const
-{
- const size_t DPOS = mDataPos;
- if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
- const flat_binder_object* obj
- = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
- mDataPos = DPOS + sizeof(flat_binder_object);
- if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
- // When transferring a NULL object, we don't write it into
- // the object list, so we don't want to check for it when
- // reading.
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
-
- // Ensure that this object is valid...
- size_t* const OBJS = mObjects;
- const size_t N = mObjectsSize;
- size_t opos = mNextObjectHint;
-
- if (N > 0) {
- LOGV("Parcel %p looking for obj at %d, hint=%d\n",
- this, DPOS, opos);
-
- // Start at the current hint position, looking for an object at
- // the current data position.
- if (opos < N) {
- while (opos < (N-1) && OBJS[opos] < DPOS) {
- opos++;
- }
- } else {
- opos = N-1;
- }
- if (OBJS[opos] == DPOS) {
- // Found it!
- LOGV("Parcel found obj %d at index %d with forward search",
- this, DPOS, opos);
- mNextObjectHint = opos+1;
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
-
- // Look backwards for it...
- while (opos > 0 && OBJS[opos] > DPOS) {
- opos--;
- }
- if (OBJS[opos] == DPOS) {
- // Found it!
- LOGV("Parcel found obj %d at index %d with backward search",
- this, DPOS, opos);
- mNextObjectHint = opos+1;
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
- }
- LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
- this, DPOS);
- }
- return NULL;
-}
-
-void Parcel::closeFileDescriptors()
-{
- size_t i = mObjectsSize;
- if (i > 0) {
- //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
- }
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- //LOGI("Closing fd: %ld\n", flat->handle);
- close(flat->handle);
- }
- }
-}
-
-const uint8_t* Parcel::ipcData() const
-{
- return mData;
-}
-
-size_t Parcel::ipcDataSize() const
-{
- return (mDataSize > mDataPos ? mDataSize : mDataPos);
-}
-
-const size_t* Parcel::ipcObjects() const
-{
- return mObjects;
-}
-
-size_t Parcel::ipcObjectsCount() const
-{
- return mObjectsSize;
-}
-
-void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
-{
- freeDataNoInit();
- mError = NO_ERROR;
- mData = const_cast<uint8_t*>(data);
- mDataSize = mDataCapacity = dataSize;
- //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
- mDataPos = 0;
- LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
- mObjects = const_cast<size_t*>(objects);
- mObjectsSize = mObjectsCapacity = objectsCount;
- mNextObjectHint = 0;
- mOwner = relFunc;
- mOwnerCookie = relCookie;
- scanForFds();
-}
-
-void Parcel::print(TextOutput& to, uint32_t flags) const
-{
- to << "Parcel(";
-
- if (errorCheck() != NO_ERROR) {
- const status_t err = errorCheck();
- to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
- } else if (dataSize() > 0) {
- const uint8_t* DATA = data();
- to << indent << HexDump(DATA, dataSize()) << dedent;
- const size_t* OBJS = objects();
- const size_t N = objectsCount();
- for (size_t i=0; i<N; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
- to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
- << TypeCode(flat->type & 0x7f7f7f00)
- << " = " << flat->binder;
- }
- } else {
- to << "NULL";
- }
-
- to << ")";
-}
-
-void Parcel::releaseObjects()
-{
- const sp<ProcessState> proc(ProcessState::self());
- size_t i = mObjectsSize;
- uint8_t* const data = mData;
- size_t* const objects = mObjects;
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(data+objects[i]);
- release_object(proc, *flat, this);
- }
-}
-
-void Parcel::acquireObjects()
-{
- const sp<ProcessState> proc(ProcessState::self());
- size_t i = mObjectsSize;
- uint8_t* const data = mData;
- size_t* const objects = mObjects;
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(data+objects[i]);
- acquire_object(proc, *flat, this);
- }
-}
-
-void Parcel::freeData()
-{
- freeDataNoInit();
- initState();
-}
-
-void Parcel::freeDataNoInit()
-{
- if (mOwner) {
- //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
- mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
- } else {
- releaseObjects();
- if (mData) free(mData);
- if (mObjects) free(mObjects);
- }
-}
-
-status_t Parcel::growData(size_t len)
-{
- size_t newSize = ((mDataSize+len)*3)/2;
- return (newSize <= mDataSize)
- ? (status_t) NO_MEMORY
- : continueWrite(newSize);
-}
-
-status_t Parcel::restartWrite(size_t desired)
-{
- if (mOwner) {
- freeData();
- return continueWrite(desired);
- }
-
- uint8_t* data = (uint8_t*)realloc(mData, desired);
- if (!data && desired > mDataCapacity) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- releaseObjects();
-
- if (data) {
- mData = data;
- mDataCapacity = desired;
- }
-
- mDataSize = mDataPos = 0;
- LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
- LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
-
- free(mObjects);
- mObjects = NULL;
- mObjectsSize = mObjectsCapacity = 0;
- mNextObjectHint = 0;
- mHasFds = false;
- mFdsKnown = true;
-
- return NO_ERROR;
-}
-
-status_t Parcel::continueWrite(size_t desired)
-{
- // If shrinking, first adjust for any objects that appear
- // after the new data size.
- size_t objectsSize = mObjectsSize;
- if (desired < mDataSize) {
- if (desired == 0) {
- objectsSize = 0;
- } else {
- while (objectsSize > 0) {
- if (mObjects[objectsSize-1] < desired)
- break;
- objectsSize--;
- }
- }
- }
-
- if (mOwner) {
- // If the size is going to zero, just release the owner's data.
- if (desired == 0) {
- freeData();
- return NO_ERROR;
- }
-
- // If there is a different owner, we need to take
- // posession.
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- size_t* objects = NULL;
-
- if (objectsSize) {
- objects = (size_t*)malloc(objectsSize*sizeof(size_t));
- if (!objects) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- // Little hack to only acquire references on objects
- // we will be keeping.
- size_t oldObjectsSize = mObjectsSize;
- mObjectsSize = objectsSize;
- acquireObjects();
- mObjectsSize = oldObjectsSize;
- }
-
- if (mData) {
- memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
- }
- if (objects && mObjects) {
- memcpy(objects, mObjects, objectsSize*sizeof(size_t));
- }
- //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
- mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
- mOwner = NULL;
-
- mData = data;
- mObjects = objects;
- mDataSize = (mDataSize < desired) ? mDataSize : desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- mDataCapacity = desired;
- mObjectsSize = mObjectsCapacity = objectsSize;
- mNextObjectHint = 0;
-
- } else if (mData) {
- if (objectsSize < mObjectsSize) {
- // Need to release refs on any objects we are dropping.
- const sp<ProcessState> proc(ProcessState::self());
- for (size_t i=objectsSize; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- // will need to rescan because we may have lopped off the only FDs
- mFdsKnown = false;
- }
- release_object(proc, *flat, this);
- }
- size_t* objects =
- (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
- if (objects) {
- mObjects = objects;
- }
- mObjectsSize = objectsSize;
- mNextObjectHint = 0;
- }
-
- // We own the data, so we can just do a realloc().
- if (desired > mDataCapacity) {
- uint8_t* data = (uint8_t*)realloc(mData, desired);
- if (data) {
- mData = data;
- mDataCapacity = desired;
- } else if (desired > mDataCapacity) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- } else {
- mDataSize = desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- if (mDataPos > desired) {
- mDataPos = desired;
- LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- }
- }
-
- } else {
- // This is the first data. Easy!
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- if(!(mDataCapacity == 0 && mObjects == NULL
- && mObjectsCapacity == 0)) {
- LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
- }
-
- mData = data;
- mDataSize = mDataPos = 0;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- mDataCapacity = desired;
- }
-
- return NO_ERROR;
-}
-
-void Parcel::initState()
-{
- mError = NO_ERROR;
- mData = 0;
- mDataSize = 0;
- mDataCapacity = 0;
- mDataPos = 0;
- LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
- LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
- mObjects = NULL;
- mObjectsSize = 0;
- mObjectsCapacity = 0;
- mNextObjectHint = 0;
- mHasFds = false;
- mFdsKnown = true;
- mOwner = NULL;
-}
-
-void Parcel::scanForFds() const
-{
- bool hasFds = false;
- for (size_t i=0; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- hasFds = true;
- break;
- }
- }
- mHasFds = hasFds;
- mFdsKnown = true;
-}
-
-}; // namespace android
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
deleted file mode 100644
index 613906b..0000000
--- a/libs/utils/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Unidirectional pipe.
-//
-
-#include <utils/Pipe.h>
-#include <utils/Log.h>
-
-#if defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-
-/*
- * Constructor. Do little.
- */
-Pipe::Pipe(void)
- : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
- mWriteHandle(kInvalidHandle)
-{
-}
-
-/*
- * Destructor. Use the system-appropriate close call.
- */
-Pipe::~Pipe(void)
-{
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle))
- LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
- mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- FlushFileBuffers((HANDLE)mWriteHandle);
- if (!CloseHandle((HANDLE)mWriteHandle))
- LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
- mWriteHandle);
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
- (int) mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
- (int) mWriteHandle);
- }
-#endif
-}
-
-/*
- * Create the pipe.
- *
- * Use the POSIX stuff for everything but Windows.
- */
-bool Pipe::create(void)
-{
- assert(mReadHandle == kInvalidHandle);
- assert(mWriteHandle == kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- /* we use this across processes, so they need to be inheritable */
- HANDLE handles[2];
- SECURITY_ATTRIBUTES saAttr;
-
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = (unsigned long) handles[0];
- mWriteHandle = (unsigned long) handles[1];
- return true;
-#else
- int fds[2];
-
- if (pipe(fds) != 0) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = fds[0];
- mWriteHandle = fds[1];
- return true;
-#endif
-}
-
-/*
- * Create a "half pipe". Please, no Segway riding.
- */
-bool Pipe::createReader(unsigned long handle)
-{
- mReadHandle = handle;
- assert(mWriteHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Create a "half pipe" for writing.
- */
-bool Pipe::createWriter(unsigned long handle)
-{
- mWriteHandle = handle;
- assert(mReadHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Return "true" if create() has been called successfully.
- */
-bool Pipe::isCreated(void)
-{
- // one or the other should be open
- return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
-}
-
-
-/*
- * Read data from the pipe.
- *
- * For Linux and Darwin, just call read(). For Windows, implement
- * non-blocking reads by calling PeekNamedPipe first.
- */
-int Pipe::read(void* buf, int count)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail = count;
- DWORD bytesRead;
-
- if (mReadNonBlocking) {
- // use PeekNamedPipe to adjust read count expectations
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return -1;
- }
-
- if (totalBytesAvail == 0)
- return 0;
- }
-
- if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
- NULL))
- {
- DWORD err = GetLastError();
- if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
- return 0;
- LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
- return -1;
- }
-
- return (int) bytesRead;
-#else
- int cc;
- cc = ::read(mReadHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Write data to the pipe.
- *
- * POSIX systems are trivial, Windows uses a different call and doesn't
- * handle non-blocking writes.
- *
- * If we add non-blocking support here, we probably want to make it an
- * all-or-nothing write.
- *
- * DO NOT use LOG() here, we could be writing a log message.
- */
-int Pipe::write(const void* buf, int count)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD bytesWritten;
-
- if (mWriteNonBlocking) {
- // BUG: can't use PeekNamedPipe() to get the amount of space
- // left. Looks like we need to use "overlapped I/O" functions.
- // I just don't care that much.
- }
-
- if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
- // can't LOG, use stderr
- fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
- return -1;
- }
-
- return (int) bytesWritten;
-#else
- int cc;
- cc = ::write(mWriteHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Figure out if there is data available on the read fd.
- *
- * We return "true" on error because we want the caller to try to read
- * from the pipe. They'll notice the read failure and do something
- * appropriate.
- */
-bool Pipe::readReady(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail;
-
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return true;
- }
-
- return (totalBytesAvail != 0);
-#else
- errno = 0;
- fd_set readfds;
- struct timeval tv = { 0, 0 };
- int cc;
-
- FD_ZERO(&readfds);
- FD_SET(mReadHandle, &readfds);
-
- cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
- if (cc < 0) {
- LOG(LOG_ERROR, "pipe", "select() failed\n");
- return true;
- } else if (cc == 0) {
- /* timed out, nothing available */
- return false;
- } else if (cc == 1) {
- /* our fd is ready */
- return true;
- } else {
- LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
- return true;
- }
-#endif
-}
-
-/*
- * Enable or disable non-blocking mode for the read descriptor.
- *
- * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
- * actually be in non-blocking mode. If this matters -- i.e. you're not
- * using a select() call -- put a call to readReady() in front of the
- * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
- * Darwin.
- */
-bool Pipe::setReadNonBlocking(bool val)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
- return false;
- }
-#endif
-
- mReadNonBlocking = val;
- return true;
-}
-
-/*
- * Enable or disable non-blocking mode for the write descriptor.
- *
- * As with setReadNonBlocking(), this does not work on the Mac.
- */
-bool Pipe::setWriteNonBlocking(bool val)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
-#endif
-
- mWriteNonBlocking = val;
- return true;
-}
-
-/*
- * Specify whether a file descriptor can be inherited by a child process.
- * Under Linux this means setting the close-on-exec flag, under Windows
- * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
- */
-bool Pipe::disallowReadInherit(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-bool Pipe::disallowWriteInherit(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-
-/*
- * Close read descriptor.
- */
-bool Pipe::closeRead(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing read handle\n");
- return false;
- }
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing read fd\n");
- return false;
- }
- }
-#endif
- mReadHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Close write descriptor.
- */
-bool Pipe::closeWrite(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mWriteHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mWriteHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing write handle\n");
- return false;
- }
- }
-#else
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing write fd\n");
- return false;
- }
- }
-#endif
- mWriteHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Get the read handle.
- */
-unsigned long Pipe::getReadHandle(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
- return mReadHandle;
-}
-
-/*
- * Get the write handle.
- */
-unsigned long Pipe::getWriteHandle(void)
-{
- assert(mWriteHandle != kInvalidHandle);
-
- return mWriteHandle;
-}
-
diff --git a/libs/utils/ProcessState.cpp b/libs/utils/ProcessState.cpp
deleted file mode 100644
index 4567df6..0000000
--- a/libs/utils/ProcessState.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ProcessState"
-
-#include <cutils/process_name.h>
-
-#include <utils/ProcessState.h>
-
-#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/IServiceManager.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#define BINDER_VM_SIZE (1*1024*1024)
-
-static bool gSingleProcess = false;
-
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// Global variables
-int mArgC;
-const char* const* mArgV;
-int mArgLen;
-
-class PoolThread : public Thread
-{
-public:
- PoolThread(bool isMain)
- : mIsMain(isMain)
- {
- }
-
-protected:
- virtual bool threadLoop()
- {
- IPCThreadState::self()->joinThreadPool(mIsMain);
- return false;
- }
-
- const bool mIsMain;
-};
-
-sp<ProcessState> ProcessState::self()
-{
- if (gProcess != NULL) return gProcess;
-
- AutoMutex _l(gProcessMutex);
- if (gProcess == NULL) gProcess = new ProcessState;
- return gProcess;
-}
-
-void ProcessState::setSingleProcess(bool singleProcess)
-{
- gSingleProcess = singleProcess;
-}
-
-
-void ProcessState::setContextObject(const sp<IBinder>& object)
-{
- setContextObject(object, String16("default"));
-}
-
-sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
-{
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
-}
-
-void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
-{
- AutoMutex _l(mLock);
- mContexts.add(name, object);
-}
-
-sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
-{
- mLock.lock();
- sp<IBinder> object(
- mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
- mLock.unlock();
-
- //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
-
- if (object != NULL) return object;
-
- // Don't attempt to retrieve contexts if we manage them
- if (mManagesContexts) {
- LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
- String8(name).string());
- return NULL;
- }
-
- IPCThreadState* ipc = IPCThreadState::self();
- {
- Parcel data, reply;
- // no interface token on this magic transaction
- data.writeString16(name);
- data.writeStrongBinder(caller);
- status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
- if (result == NO_ERROR) {
- object = reply.readStrongBinder();
- }
- }
-
- ipc->flushCommands();
-
- if (object != NULL) setContextObject(object, name);
- return object;
-}
-
-bool ProcessState::supportsProcesses() const
-{
- return mDriverFD >= 0;
-}
-
-void ProcessState::startThreadPool()
-{
- AutoMutex _l(mLock);
- if (!mThreadPoolStarted) {
- mThreadPoolStarted = true;
- spawnPooledThread(true);
- }
-}
-
-bool ProcessState::isContextManager(void) const
-{
- return mManagesContexts;
-}
-
-bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
-{
- if (!mManagesContexts) {
- AutoMutex _l(mLock);
- mBinderContextCheckFunc = checkFunc;
- mBinderContextUserData = userData;
- if (mDriverFD >= 0) {
- int dummy = 0;
-#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
-#else
- status_t result = INVALID_OPERATION;
-#endif
- if (result == 0) {
- mManagesContexts = true;
- } else if (result == -1) {
- mBinderContextCheckFunc = NULL;
- mBinderContextUserData = NULL;
- LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
- }
- } else {
- // If there is no driver, our only world is the local
- // process so we can always become the context manager there.
- mManagesContexts = true;
- }
- }
- return mManagesContexts;
-}
-
-ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
-{
- const size_t N=mHandleToObject.size();
- if (N <= (size_t)handle) {
- handle_entry e;
- e.binder = NULL;
- e.refs = NULL;
- status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
- if (err < NO_ERROR) return NULL;
- }
- return &mHandleToObject.editItemAt(handle);
-}
-
-sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
-{
- sp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != NULL) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. See comment
- // in getWeakProxyForHandle() for more info about this.
- IBinder* b = e->binder;
- if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- result = b;
- } else {
- // This little bit of nastyness is to allow us to add a primary
- // reference to the remote proxy when this team doesn't have one
- // but another team is sending the handle to us.
- result.force_set(b);
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
-wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
-{
- wp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != NULL) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. The
- // attemptIncWeak() is safe because we know the BpBinder destructor will always
- // call expungeHandle(), which acquires the same lock we are holding now.
- // We need to do this because there is a race condition between someone
- // releasing a reference on this BpBinder, and a new reference on its handle
- // arriving from the driver.
- IBinder* b = e->binder;
- if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
- result = b;
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- } else {
- result = b;
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
-void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
-{
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- // This handle may have already been replaced with a new BpBinder
- // (if someone failed the AttemptIncWeak() above); we don't want
- // to overwrite it.
- if (e && e->binder == binder) e->binder = NULL;
-}
-
-void ProcessState::setArgs(int argc, const char* const argv[])
-{
- mArgC = argc;
- mArgV = (const char **)argv;
-
- mArgLen = 0;
- for (int i=0; i<argc; i++) {
- mArgLen += strlen(argv[i]) + 1;
- }
- mArgLen--;
-}
-
-int ProcessState::getArgC() const
-{
- return mArgC;
-}
-
-const char* const* ProcessState::getArgV() const
-{
- return mArgV;
-}
-
-void ProcessState::setArgV0(const char* txt)
-{
- if (mArgV != NULL) {
- strncpy((char*)mArgV[0], txt, mArgLen);
- set_process_name(txt);
- }
-}
-
-void ProcessState::spawnPooledThread(bool isMain)
-{
- if (mThreadPoolStarted) {
- int32_t s = android_atomic_add(1, &mThreadPoolSeq);
- char buf[32];
- sprintf(buf, "Binder Thread #%d", s);
- LOGV("Spawning new pooled thread, name=%s\n", buf);
- sp<Thread> t = new PoolThread(isMain);
- t->run(buf);
- }
-}
-
-static int open_driver()
-{
- if (gSingleProcess) {
- return -1;
- }
-
- int fd = open("/dev/binder", O_RDWR);
- if (fd >= 0) {
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- int vers;
-#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(fd, BINDER_VERSION, &vers);
-#else
- status_t result = -1;
- errno = EPERM;
-#endif
- if (result == -1) {
- LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
- close(fd);
- fd = -1;
- }
- if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
- LOGE("Binder driver protocol does not match user space protocol!");
- close(fd);
- fd = -1;
- }
-#if defined(HAVE_ANDROID_OS)
- size_t maxThreads = 15;
- result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
- if (result == -1) {
- LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
- }
-#endif
-
- } else {
- LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
- }
- return fd;
-}
-
-ProcessState::ProcessState()
- : mDriverFD(open_driver())
- , mVMStart(MAP_FAILED)
- , mManagesContexts(false)
- , mBinderContextCheckFunc(NULL)
- , mBinderContextUserData(NULL)
- , mThreadPoolStarted(false)
- , mThreadPoolSeq(1)
-{
- if (mDriverFD >= 0) {
- // XXX Ideally, there should be a specific define for whether we
- // have mmap (or whether we could possibly have the kernel module
- // availabla).
-#if !defined(HAVE_WIN32_IPC)
- // mmap the binder, providing a chunk of virtual address space to receive transactions.
- mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
- if (mVMStart == MAP_FAILED) {
- // *sigh*
- LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
- close(mDriverFD);
- mDriverFD = -1;
- }
-#else
- mDriverFD = -1;
-#endif
- }
- if (mDriverFD < 0) {
- // Need to run without the driver, starting our own thread pool.
- }
-}
-
-ProcessState::~ProcessState()
-{
-}
-
-}; // namespace android
diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp
deleted file mode 100644
index 51509a3..0000000
--- a/libs/utils/Socket.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-
-#ifdef HAVE_WINSOCK
-// This needs to come first, or Cygwin gets concerned about a potential
-// clash between WinSock and <sys/types.h>.
-# include <winsock2.h>
-#endif
-
-#include <utils/Socket.h>
-#include <utils/inet_address.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#ifndef HAVE_WINSOCK
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * Socket
- * ===========================================================================
- */
-
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET (-1)
-#endif
-#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
-
-/*static*/ bool Socket::mBootInitialized = false;
-
-/*
- * Extract system-dependent error code.
- */
-static inline int getSocketError(void) {
-#ifdef HAVE_WINSOCK
- return WSAGetLastError();
-#else
- return errno;
-#endif
-}
-
-/*
- * One-time initialization for socket code.
- */
-/*static*/ bool Socket::bootInit(void)
-{
-#ifdef HAVE_WINSOCK
- WSADATA wsaData;
- int err;
-
- err = WSAStartup(MAKEWORD(2, 0), &wsaData);
- if (err != 0) {
- LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
- return false;
- }
-
- LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
- LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
-#endif
-
- mBootInitialized = true;
- return true;
-}
-
-/*
- * One-time shutdown for socket code.
- */
-/*static*/ void Socket::finalShutdown(void)
-{
-#ifdef HAVE_WINSOCK
- WSACleanup();
-#endif
- mBootInitialized = false;
-}
-
-
-/*
- * Simple constructor. Allow the application to create us and then make
- * bind/connect calls.
- */
-Socket::Socket(void)
- : mSock(UNDEF_SOCKET)
-{
- if (!mBootInitialized)
- LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
-}
-
-/*
- * Destructor. Closes the socket and resets our storage.
- */
-Socket::~Socket(void)
-{
- close();
-}
-
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const char* host, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(host, port))
- return -1;
-
- //return doConnect(sockAddr);
- int foo;
- foo = doConnect(sockAddr);
- return foo;
-}
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const InetAddress* addr, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(addr, port))
- return -1;
-
- return doConnect(sockAddr);
-}
-
-/*
- * Finish creating a socket by connecting to the remote host.
- *
- * Returns 0 on success.
- */
-int Socket::doConnect(const InetSocketAddress& sockAddr)
-{
-#ifdef HAVE_WINSOCK
- SOCKET sock;
-#else
- int sock;
-#endif
- const InetAddress* addr = sockAddr.getAddress();
- int port = sockAddr.getPort();
- struct sockaddr_in inaddr;
- DurationTimer connectTimer;
-
- assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
- memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
- inaddr.sin_port = htons(port);
-
- //fprintf(stderr, "--- connecting to %s:%d\n",
- // sockAddr.getHostName(), port);
-
- sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock == INVALID_SOCKET) {
- int err = getSocketError();
- LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.start();
-
- if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
- int err = getSocketError();
- LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
- sockAddr.getHostName(), port, err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.stop();
- if ((long) connectTimer.durationUsecs() > 100000) {
- LOG(LOG_INFO, "socket",
- "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
- port, ((long) connectTimer.durationUsecs()) / 1000000.0);
- }
-
- mSock = (unsigned long) sock;
- LOG(LOG_VERBOSE, "socket",
- "--- connected to %s:%d\n", sockAddr.getHostName(), port);
- return 0;
-}
-
-
-/*
- * Close the socket if it needs closing.
- */
-bool Socket::close(void)
-{
- if (mSock != UNDEF_SOCKET) {
- //fprintf(stderr, "--- closing socket %lu\n", mSock);
-#ifdef HAVE_WINSOCK
- if (::closesocket((SOCKET) mSock) != 0)
- return false;
-#else
- if (::close((int) mSock) != 0)
- return false;
-#endif
- }
-
- mSock = UNDEF_SOCKET;
-
- return true;
-}
-
-/*
- * Read data from socket.
- *
- * Standard semantics: read up to "len" bytes into "buf". Returns the
- * number of bytes read, or less than zero on error.
- */
-int Socket::read(void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = recv(sock, (char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-/*
- * Write data to a socket.
- *
- * Standard semantics: write up to "len" bytes into "buf". Returns the
- * number of bytes written, or less than zero on error.
- */
-int Socket::write(const void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = send(sock, (const char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-
-/*
- * ===========================================================================
- * Socket tests
- * ===========================================================================
- */
-
-/*
- * Read all data from the socket. The data is read into a buffer that
- * expands as needed.
- *
- * On exit, the buffer is returned, and the length of the data is stored
- * in "*sz". A null byte is added to the end, but is not included in
- * the length.
- */
-static char* socketReadAll(const Socket& s, int *sz)
-{
- int max, r;
- char *data, *ptr, *tmp;
-
- data = (char*) malloc(max = 32768);
- if (data == NULL)
- return NULL;
-
- ptr = data;
-
- for (;;) {
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max *= 2);
- if(tmp == 0) {
- free(data);
- return 0;
- }
- }
- r = s.read(ptr, max - (ptr - data));
- if (r == 0)
- break;
- if (r < 0) {
- LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
- break;
- }
- ptr += r;
- }
-
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max + 1);
- if (tmp == NULL) {
- free(data);
- return NULL;
- }
- }
- *ptr = '\0';
- *sz = (ptr - data);
- return data;
-}
-
-/*
- * Exercise the Socket class.
- */
-void android::TestSockets(void)
-{
- printf("----- SOCKET TEST ------\n");
- Socket::bootInit();
-
- char* buf = NULL;
- int len, cc;
- const char* kTestStr =
- "GET / HTTP/1.0\n"
- "Connection: close\n"
- "\n";
-
- Socket sock;
- if (sock.connect("www.google.com", 80) != 0) {
- fprintf(stderr, "socket connected failed\n");
- goto bail;
- }
-
- cc = sock.write(kTestStr, strlen(kTestStr));
- if (cc != (int) strlen(kTestStr)) {
- fprintf(stderr, "write failed, res=%d\n", cc);
- goto bail;
- }
- buf = socketReadAll(sock, &len);
-
- printf("GOT '%s'\n", buf);
-
-bail:
- sock.close();
- free(buf);
-}
-
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
index 93f7e4f..4dfa578 100644
--- a/libs/utils/Static.cpp
+++ b/libs/utils/Static.cpp
@@ -20,7 +20,6 @@
#include <private/utils/Static.h>
#include <utils/BufferedTextOutput.h>
-#include <utils/IPCThreadState.h>
#include <utils/Log.h>
namespace android {
@@ -87,34 +86,4 @@
TextOutput& aout(gStdoutTextOutput);
TextOutput& aerr(gStderrTextOutput);
-#ifndef LIBUTILS_NATIVE
-
-// ------------ ProcessState.cpp
-
-Mutex gProcessMutex;
-sp<ProcessState> gProcess;
-
-class LibUtilsIPCtStatics
-{
-public:
- LibUtilsIPCtStatics()
- {
- }
-
- ~LibUtilsIPCtStatics()
- {
- IPCThreadState::shutdown();
- }
-};
-
-static LibUtilsIPCtStatics gIPCStatics;
-
-// ------------ ServiceManager.cpp
-
-Mutex gDefaultServiceManagerLock;
-sp<IServiceManager> gDefaultServiceManager;
-sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/libs/utils/StringArray.cpp b/libs/utils/StringArray.cpp
new file mode 100644
index 0000000..aa42d68
--- /dev/null
+++ b/libs/utils/StringArray.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/StringArray.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+StringArray::StringArray()
+ : mMax(0), mCurrent(0), mArray(NULL)
+{
+}
+
+StringArray:: ~StringArray() {
+ for (int i = 0; i < mCurrent; i++)
+ delete[] mArray[i];
+ delete[] mArray;
+}
+
+//
+// Add a string. A copy of the string is made.
+//
+bool StringArray::push_back(const char* str) {
+ if (mCurrent >= mMax) {
+ char** tmp;
+
+ if (mMax == 0)
+ mMax = 16; // initial storage
+ else
+ mMax *= 2;
+
+ tmp = new char*[mMax];
+ if (tmp == NULL)
+ return false;
+
+ memcpy(tmp, mArray, mCurrent * sizeof(char*));
+ delete[] mArray;
+ mArray = tmp;
+ }
+
+ int len = strlen(str);
+ mArray[mCurrent] = new char[len+1];
+ memcpy(mArray[mCurrent], str, len+1);
+ mCurrent++;
+
+ return true;
+}
+
+//
+// Delete an entry.
+//
+void StringArray::erase(int idx) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ if (idx < mCurrent-1) {
+ memmove(&mArray[idx], &mArray[idx+1],
+ (mCurrent-1 - idx) * sizeof(char*));
+ }
+ mCurrent--;
+}
+
+//
+// Sort the array.
+//
+void StringArray::sort(int (*compare)(const void*, const void*)) {
+ qsort(mArray, mCurrent, sizeof(char*), compare);
+}
+
+//
+// Pass this to the sort routine to do an ascending alphabetical sort.
+//
+int StringArray::cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
+ return strcmp(*(const char**)pstr1, *(const char**)pstr2);
+}
+
+//
+// Set entry N to specified string.
+// [should use operator[] here]
+//
+void StringArray::setEntry(int idx, const char* str) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ int len = strlen(str);
+ mArray[idx] = new char[len+1];
+ memcpy(mArray[idx], str, len+1);
+}
+
+
+}; // namespace android
diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp
index cebee99..e04823d 100644
--- a/libs/utils/TextOutput.cpp
+++ b/libs/utils/TextOutput.cpp
@@ -22,9 +22,17 @@
#include <stdlib.h>
#include <string.h>
+namespace android {
+
// ---------------------------------------------------------------------------
-namespace android {
+TextOutput::TextOutput() {
+}
+
+TextOutput::~TextOutput() {
+}
+
+// ---------------------------------------------------------------------------
TextOutput& operator<<(TextOutput& to, bool val)
{
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 9287c0b..6be372c 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -38,10 +38,6 @@
# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
#endif
-#if defined(HAVE_FUTEX)
-#include <private/utils/futex_synchro.h>
-#endif
-
#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif
@@ -56,10 +52,6 @@
// ----------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
-#if 0
-#pragma mark -
-#pragma mark PTHREAD
-#endif
// ----------------------------------------------------------------------------
/*
@@ -163,10 +155,6 @@
// ----------------------------------------------------------------------------
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#pragma mark WIN32_THREADS
-#endif
// ----------------------------------------------------------------------------
/*
@@ -252,11 +240,6 @@
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Common Thread functions
-#endif
-
int androidCreateThread(android_thread_func_t fn, void* arg)
{
return createThreadEtc(fn, arg);
@@ -294,109 +277,9 @@
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Mutex
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-/*
- * Simple pthread wrapper.
- */
-
-Mutex::Mutex()
-{
- _init();
-}
-
-Mutex::Mutex(const char* name)
-{
- // XXX: name not used for now
- _init();
-}
-
-void Mutex::_init()
-{
- pthread_mutex_t* pMutex = new pthread_mutex_t;
- pthread_mutex_init(pMutex, NULL);
- mState = pMutex;
-}
-
-Mutex::~Mutex()
-{
- delete (pthread_mutex_t*) mState;
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- pthread_mutex_unlock((pthread_mutex_t*) mState);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
-
-#define STATE ((futex_mutex_t*) (&mState))
-
-Mutex::Mutex()
-{
- _init();
-}
-
-Mutex::Mutex(const char* name)
-{
- _init();
-}
-
-void
-Mutex::_init()
-{
- futex_mutex_init(STATE);
-}
-
-Mutex::~Mutex()
-{
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- futex_mutex_unlock(STATE);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=futex_mutex_trylock(STATE)) == EINTR) ;
- return -res;
-}
-#undef STATE
-
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
Mutex::Mutex()
{
@@ -413,6 +296,19 @@
// XXX: name not used for now
HANDLE hMutex;
+ assert(sizeof(hMutex) == sizeof(mState));
+
+ hMutex = CreateMutex(NULL, FALSE, NULL);
+ mState = (void*) hMutex;
+}
+
+Mutex::Mutex(int type, const char* name)
+{
+ // XXX: type and name not used for now
+ HANDLE hMutex;
+
+ assert(sizeof(hMutex) == sizeof(mState));
+
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
@@ -456,161 +352,9 @@
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Condition
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- pthread_cond_t* pCond = new pthread_cond_t;
-
- pthread_cond_init(pCond, NULL);
- mState = pCond;
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
- pthread_cond_destroy((pthread_cond_t*) mState);
- delete (pthread_cond_t*) mState;
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int cc;
- while ((cc = pthread_cond_wait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- assert(mutex.mState != NULL);
-
- struct timespec ts;
- ts.tv_sec = abstime/1000000000;
- ts.tv_nsec = abstime-(ts.tv_sec*1000000000);
-
- int cc;
- while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- pthread_cond_signal((pthread_cond_t*) mState);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- pthread_cond_broadcast((pthread_cond_t*) mState);
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
-
-#define STATE ((futex_cond_t*) (&mState))
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- futex_cond_init(STATE);
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int res;
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ;
-
- return -res;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- nsecs_t reltime = abstime - systemTime();
- if (reltime <= 0) return true;
- return waitRelative(mutex, reltime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- assert(mutex.mState != NULL);
- int res;
- unsigned msec = ns2ms(reltime);
- if(msec == 0)
- return true;
- // This code will not time out at the correct time if interrupted by signals
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ;
- return res;
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- futex_cond_signal(STATE);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- futex_cond_broadcast(STATE);
-}
-
-#undef STATE
-
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
/*
* Windows doesn't have a condition variable solution. It's possible
@@ -753,17 +497,13 @@
return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
}
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
{
WinCondition* condState = (WinCondition*) mState;
HANDLE hMutex = (HANDLE) mutex.mState;
+ nsecs_t absTime = systemTime()+reltime;
- return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
+ return ((WinCondition*)mState)->wait(condState, hMutex, &absTime);
}
/*
@@ -841,11 +581,6 @@
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Thread::Thread
-#endif
-
/*
* This is our thread object!
*/
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
deleted file mode 100644
index 835480d..0000000
--- a/libs/utils/TimerProbe.cpp
+++ /dev/null
@@ -1,131 +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.
- */
-
-#include <utils/TimerProbe.h>
-
-#if ENABLE_TIMER_PROBE
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "time"
-
-namespace android {
-
-Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
-TimerProbe* TimerProbe::gExecuteChain;
-int TimerProbe::gIndent;
-timespec TimerProbe::gRealBase;
-
-TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
-{
- mNext = gExecuteChain;
- gExecuteChain = this;
- mIndent = gIndent;
- gIndent += 1;
- if (mIndent > 0) {
- if (*slot == 0) {
- int count = gBuckets.add();
- *slot = count;
- Bucket& bucket = gBuckets.editItemAt(count);
- memset(&bucket, 0, sizeof(Bucket));
- bucket.mTag = tag;
- bucket.mSlotPtr = slot;
- bucket.mIndent = mIndent;
- }
- mBucket = *slot;
- }
- clock_gettime(CLOCK_REALTIME, &mRealStart);
- if (gRealBase.tv_sec == 0)
- gRealBase = mRealStart;
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
-}
-
-void TimerProbe::end()
-{
- timespec realEnd, pEnd, tEnd;
- clock_gettime(CLOCK_REALTIME, &realEnd);
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
- print(realEnd, pEnd, tEnd);
- mTag = NULL;
-}
-
-TimerProbe::~TimerProbe()
-{
- if (mTag != NULL)
- end();
- gExecuteChain = mNext;
- gIndent--;
-}
-
-
-uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
-{
- int sec = end.tv_sec - start.tv_sec;
- int nsec = end.tv_nsec - start.tv_nsec;
- if (nsec < 0) {
- sec--;
- nsec += 1000000000;
- }
- return sec * 1000000 + nsec / 1000;
-}
-
-void TimerProbe::print(const timespec& r, const timespec& p,
- const timespec& t) const
-{
- uint32_t es = ElapsedTime(gRealBase, mRealStart);
- uint32_t er = ElapsedTime(mRealStart, r);
- uint32_t ep = ElapsedTime(mPStart, p);
- uint32_t et = ElapsedTime(mTStart, t);
- if (mIndent > 0) {
- Bucket& bucket = gBuckets.editItemAt(mBucket);
- if (bucket.mStart == 0)
- bucket.mStart = es;
- bucket.mReal += er;
- bucket.mProcess += ep;
- bucket.mThread += et;
- bucket.mCount++;
- return;
- }
- int index = 0;
- int buckets = gBuckets.size();
- int count = 1;
- const char* tag = mTag;
- int indent = mIndent;
- do {
- LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
- tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
- er, ep, ep * 100 / er, et, et * 100 / er);
- if (index >= buckets)
- break;
- Bucket& bucket = gBuckets.editItemAt(index);
- count = bucket.mCount;
- es = bucket.mStart;
- er = bucket.mReal;
- ep = bucket.mProcess;
- et = bucket.mThread;
- tag = bucket.mTag;
- indent = bucket.mIndent;
- *bucket.mSlotPtr = 0;
- } while (++index); // always true
- gBuckets.clear();
-}
-
-}; // namespace android
-
-#endif
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 2abc811..784f035 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -18,7 +18,6 @@
// Timer functions.
//
#include <utils/Timers.h>
-#include <utils/ported.h> // may need usleep
#include <utils/Log.h>
#include <stdlib.h>
@@ -54,130 +53,6 @@
#endif
}
-//#define MONITOR_USLEEP
-
-/*
- * Sleep long enough that we'll wake up "interval" milliseconds after
- * the previous snooze.
- *
- * The "nextTick" argument is updated on each call, and should be passed
- * in every time. Set its fields to zero on the first call.
- *
- * Returns the #of intervals we have overslept, which will be zero if we're
- * on time. [Currently just returns 0 or 1.]
- */
-int sleepForInterval(long interval, struct timeval* pNextTick)
-{
- struct timeval now;
- long long timeBeforeNext;
- long sleepTime = 0;
- bool overSlept = false;
- //int usleepBias = 0;
-
-#ifdef USLEEP_BIAS
- /*
- * Linux likes to add 9000ms or so.
- * [not using this for now]
- */
- //usleepBias = USLEEP_BIAS;
-#endif
-
- gettimeofday(&now, NULL);
-
- if (pNextTick->tv_sec == 0) {
- /* special-case for first time through */
- *pNextTick = now;
- sleepTime = interval;
- android::DurationTimer::addToTimeval(pNextTick, interval);
- } else {
- /*
- * Compute how much time there is before the next tick. If this
- * value is negative, we've run over. If we've run over a little
- * bit we can shorten the next frame to keep the pace steady, but
- * if we've dramatically overshot we need to re-sync.
- */
- timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
- //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // (long) timeBeforeNext);
- if (timeBeforeNext < -interval) {
- /* way over */
- overSlept = true;
- sleepTime = 0;
- *pNextTick = now;
- } else if (timeBeforeNext <= 0) {
- /* slightly over, keep the pace steady */
- overSlept = true;
- sleepTime = 0;
- } else if (timeBeforeNext <= interval) {
- /* right on schedule */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
- /* sleep call returned early; do a longer sleep this time */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval) {
- /* we went back in time -- somebody updated system clock? */
- /* (could also be a *seriously* broken usleep()) */
- LOG(LOG_DEBUG, "",
- " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
- sleepTime = 0;
- *pNextTick = now;
- }
- android::DurationTimer::addToTimeval(pNextTick, interval);
- }
- //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // sleepTime);
-
- /*
- * Sleep for the designated period of time.
- *
- * Linux tends to sleep for longer than requested, often by 17-18ms.
- * MinGW tends to sleep for less than requested, by as much as 14ms,
- * but occasionally oversleeps for 40+ms (looks like some external
- * factors plus round-off on a 64Hz clock). Cygwin is pretty steady.
- *
- * If you start the MinGW version, and then launch the Cygwin version,
- * the MinGW clock becomes more erratic. Not entirely sure why.
- *
- * (There's a lot of stuff here; it's really just a usleep() call with
- * a bunch of instrumentation.)
- */
- if (sleepTime > 0) {
-#if defined(MONITOR_USLEEP)
- struct timeval before, after;
- long long actual;
-
- gettimeofday(&before, NULL);
- usleep((long) sleepTime);
- gettimeofday(&after, NULL);
-
- /* check usleep() accuracy; default Linux threads are pretty sloppy */
- actual = android::DurationTimer::subtractTimevals(&after, &before);
- if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
- (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
- {
- LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
- (long) actual);
- }
-#else
-#ifdef HAVE_WIN32_THREADS
- Sleep( sleepTime/1000 );
-#else
- usleep((long) sleepTime);
-#endif
-#endif
- }
-
- //printf("slept %d\n", sleepTime);
-
- if (overSlept)
- return 1; // close enough
- else
- return 0;
-}
-
-
/*
* ===========================================================================
* DurationTimer
diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
deleted file mode 100644
index 96f9fc4..0000000
--- a/libs/utils/ZipEntry.cpp
+++ /dev/null
@@ -1,696 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// Access to entries in a Zip archive.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipEntry.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Initialize a new ZipEntry structure from a FILE* positioned at a
- * CentralDirectoryEntry.
- *
- * On exit, the file pointer will be at the start of the next CDE or
- * at the EOCD.
- */
-status_t ZipEntry::initFromCDE(FILE* fp)
-{
- status_t result;
- long posn;
- bool hasDD;
-
- //LOGV("initFromCDE ---\n");
-
- /* read the CDE */
- result = mCDE.read(fp);
- if (result != NO_ERROR) {
- LOGD("mCDE.read failed\n");
- return result;
- }
-
- //mCDE.dump();
-
- /* using the info in the CDE, go load up the LFH */
- posn = ftell(fp);
- if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
- LOGD("local header seek failed (%ld)\n",
- mCDE.mLocalHeaderRelOffset);
- return UNKNOWN_ERROR;
- }
-
- result = mLFH.read(fp);
- if (result != NO_ERROR) {
- LOGD("mLFH.read failed\n");
- return result;
- }
-
- if (fseek(fp, posn, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- //mLFH.dump();
-
- /*
- * We *might* need to read the Data Descriptor at this point and
- * integrate it into the LFH. If this bit is set, the CRC-32,
- * compressed size, and uncompressed size will be zero. In practice
- * these seem to be rare.
- */
- hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
- if (hasDD) {
- // do something clever
- //LOGD("+++ has data descriptor\n");
- }
-
- /*
- * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
- * flag is set, because the LFH is incomplete. (Not a problem, since we
- * prefer the CDE values.)
- */
- if (!hasDD && !compareHeaders()) {
- LOGW("WARNING: header mismatch\n");
- // keep going?
- }
-
- /*
- * If the mVersionToExtract is greater than 20, we may have an
- * issue unpacking the record -- could be encrypted, compressed
- * with something we don't support, or use Zip64 extensions. We
- * can defer worrying about that to when we're extracting data.
- */
-
- return NO_ERROR;
-}
-
-/*
- * Initialize a new entry. Pass in the file name and an optional comment.
- *
- * Initializes the CDE and the LFH.
- */
-void ZipEntry::initNew(const char* fileName, const char* comment)
-{
- assert(fileName != NULL && *fileName != '\0'); // name required
-
- /* most fields are properly initialized by constructor */
- mCDE.mVersionMadeBy = kDefaultMadeBy;
- mCDE.mVersionToExtract = kDefaultVersion;
- mCDE.mCompressionMethod = kCompressStored;
- mCDE.mFileNameLength = strlen(fileName);
- if (comment != NULL)
- mCDE.mFileCommentLength = strlen(comment);
- mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- strcpy((char*) mCDE.mFileName, fileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- /* TODO: stop assuming null-terminated ASCII here? */
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- strcpy((char*) mCDE.mFileComment, comment);
- }
-
- copyCDEtoLFH();
-}
-
-/*
- * Initialize a new entry, starting with the ZipEntry from a different
- * archive.
- *
- * Initializes the CDE and the LFH.
- */
-status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
- const ZipEntry* pEntry)
-{
- /*
- * Copy everything in the CDE over, then fix up the hairy bits.
- */
- memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- if (mCDE.mFileName == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- if (mCDE.mFileComment == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
- }
- if (mCDE.mExtraFieldLength > 0) {
- /* we null-terminate this, though it may not be a string */
- mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
- if (mCDE.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
- mCDE.mExtraFieldLength+1);
- }
-
- /* construct the LFH from the CDE */
- copyCDEtoLFH();
-
- /*
- * The LFH "extra" field is independent of the CDE "extra", so we
- * handle it here.
- */
- assert(mLFH.mExtraField == NULL);
- mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
- if (mLFH.mExtraFieldLength > 0) {
- mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
- if (mLFH.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
- mLFH.mExtraFieldLength+1);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Insert pad bytes in the LFH by tweaking the "extra" field. This will
- * potentially confuse something that put "extra" data in here earlier,
- * but I can't find an actual problem.
- */
-status_t ZipEntry::addPadding(int padding)
-{
- if (padding <= 0)
- return INVALID_OPERATION;
-
- //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
- // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
-
- if (mLFH.mExtraFieldLength > 0) {
- /* extend existing field */
- unsigned char* newExtra;
-
- newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
- if (newExtra == NULL)
- return NO_MEMORY;
- memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
- memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
-
- delete[] mLFH.mExtraField;
- mLFH.mExtraField = newExtra;
- mLFH.mExtraFieldLength += padding;
- } else {
- /* create new field */
- mLFH.mExtraField = new unsigned char[padding];
- memset(mLFH.mExtraField, 0, padding);
- mLFH.mExtraFieldLength = padding;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Set the fields in the LFH equal to the corresponding fields in the CDE.
- *
- * This does not touch the LFH "extra" field.
- */
-void ZipEntry::copyCDEtoLFH(void)
-{
- mLFH.mVersionToExtract = mCDE.mVersionToExtract;
- mLFH.mGPBitFlag = mCDE.mGPBitFlag;
- mLFH.mCompressionMethod = mCDE.mCompressionMethod;
- mLFH.mLastModFileTime = mCDE.mLastModFileTime;
- mLFH.mLastModFileDate = mCDE.mLastModFileDate;
- mLFH.mCRC32 = mCDE.mCRC32;
- mLFH.mCompressedSize = mCDE.mCompressedSize;
- mLFH.mUncompressedSize = mCDE.mUncompressedSize;
- mLFH.mFileNameLength = mCDE.mFileNameLength;
- // the "extra field" is independent
-
- delete[] mLFH.mFileName;
- if (mLFH.mFileNameLength > 0) {
- mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
- strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
- } else {
- mLFH.mFileName = NULL;
- }
-}
-
-/*
- * Set some information about a file after we add it.
- */
-void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod)
-{
- mCDE.mCompressionMethod = compressionMethod;
- mCDE.mCRC32 = crc32;
- mCDE.mCompressedSize = compLen;
- mCDE.mUncompressedSize = uncompLen;
- mCDE.mCompressionMethod = compressionMethod;
- if (compressionMethod == kCompressDeflated) {
- mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
- }
- copyCDEtoLFH();
-}
-
-/*
- * See if the data in mCDE and mLFH match up. This is mostly useful for
- * debugging these classes, but it can be used to identify damaged
- * archives.
- *
- * Returns "false" if they differ.
- */
-bool ZipEntry::compareHeaders(void) const
-{
- if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
- LOGV("cmp: VersionToExtract\n");
- return false;
- }
- if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
- LOGV("cmp: GPBitFlag\n");
- return false;
- }
- if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
- LOGV("cmp: CompressionMethod\n");
- return false;
- }
- if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
- LOGV("cmp: LastModFileTime\n");
- return false;
- }
- if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
- LOGV("cmp: LastModFileDate\n");
- return false;
- }
- if (mCDE.mCRC32 != mLFH.mCRC32) {
- LOGV("cmp: CRC32\n");
- return false;
- }
- if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
- LOGV("cmp: CompressedSize\n");
- return false;
- }
- if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
- LOGV("cmp: UncompressedSize\n");
- return false;
- }
- if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
- LOGV("cmp: FileNameLength\n");
- return false;
- }
-#if 0 // this seems to be used for padding, not real data
- if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
- LOGV("cmp: ExtraFieldLength\n");
- return false;
- }
-#endif
- if (mCDE.mFileName != NULL) {
- if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
- LOGV("cmp: FileName\n");
- return false;
- }
- }
-
- return true;
-}
-
-
-/*
- * Convert the DOS date/time stamp into a UNIX time stamp.
- */
-time_t ZipEntry::getModWhen(void) const
-{
- struct tm parts;
-
- parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
- parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
- parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
- parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
- parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
- parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
- parts.tm_wday = parts.tm_yday = 0;
- parts.tm_isdst = -1; // DST info "not available"
-
- return mktime(&parts);
-}
-
-/*
- * Set the CDE/LFH timestamp from UNIX time.
- */
-void ZipEntry::setModWhen(time_t when)
-{
-#ifdef HAVE_LOCALTIME_R
- struct tm tmResult;
-#endif
- time_t even;
- unsigned short zdate, ztime;
-
- struct tm* ptm;
-
- /* round up to an even number of seconds */
- even = (time_t)(((unsigned long)(when) + 1) & (~1));
-
- /* expand */
-#ifdef HAVE_LOCALTIME_R
- ptm = localtime_r(&even, &tmResult);
-#else
- ptm = localtime(&even);
-#endif
-
- int year;
- year = ptm->tm_year;
- if (year < 80)
- year = 80;
-
- zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
- ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
-
- mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
- mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::LocalFileHeader
- * ===========================================================================
- */
-
-/*
- * Read a local file header.
- *
- * On entry, "fp" points to the signature at the start of the header.
- * On exit, "fp" points to the start of data.
- */
-status_t ZipEntry::LocalFileHeader::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kLFHLen];
-
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
-
- if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
-
- // TODO: validate sizes
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* grab extra field */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a local file header.
- */
-status_t ZipEntry::LocalFileHeader::write(FILE* fp)
-{
- unsigned char buf[kLFHLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x0e], mCRC32);
- ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
-
- if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Dump the contents of a LocalFileHeader object.
- */
-void ZipEntry::LocalFileHeader::dump(void) const
-{
- LOGD(" LocalFileHeader contents:\n");
- LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u\n",
- mFileNameLength, mExtraFieldLength);
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::CentralDirEntry
- * ===========================================================================
- */
-
-/*
- * Read the central dir entry that appears next in the file.
- *
- * On entry, "fp" should be positioned on the signature bytes for the
- * entry. On exit, "fp" will point at the signature word for the next
- * entry or for the EOCD.
- */
-status_t ZipEntry::CentralDirEntry::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kCDELen];
-
- /* no re-use */
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
- assert(mFileComment == NULL);
-
- if (fread(buf, 1, kCDELen, fp) != kCDELen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("Whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
- mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
- mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
- mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
- mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
- mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
-
- // TODO: validate sizes and offsets
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* read "extra field" */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-
- /* grab comment, if any */
- if (mFileCommentLength != 0) {
- mFileComment = new unsigned char[mFileCommentLength+1];
- if (mFileComment == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileComment[mFileCommentLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a central dir entry.
- */
-status_t ZipEntry::CentralDirEntry::write(FILE* fp)
-{
- unsigned char buf[kCDELen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
- ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x10], mCRC32);
- ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
- ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
- ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
- ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
- ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
- ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
-
- if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- /* write comment */
- if (mFileCommentLength != 0) {
- if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of a CentralDirEntry object.
- */
-void ZipEntry::CentralDirEntry::dump(void) const
-{
- LOGD(" CentralDirEntry contents:\n");
- LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
- mFileNameLength, mExtraFieldLength, mFileCommentLength);
- LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
- mDiskNumberStart, mInternalAttrs, mExternalAttrs,
- mLocalHeaderRelOffset);
-
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
- if (mFileComment != NULL)
- LOGD(" comment: '%s'\n", mFileComment);
-}
-
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
deleted file mode 100644
index 6f27d17..0000000
--- a/libs/utils/ZipFile.cpp
+++ /dev/null
@@ -1,1296 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// Access to Zip archives.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipFile.h>
-#include <utils/ZipUtils.h>
-#include <utils/Log.h>
-
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8 // normally in zutil.h?
-
-#include <memory.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Some environments require the "b", some choke on it.
- */
-#define FILE_OPEN_RO "rb"
-#define FILE_OPEN_RW "r+b"
-#define FILE_OPEN_RW_CREATE "w+b"
-
-/* should live somewhere else? */
-static status_t errnoToStatus(int err)
-{
- if (err == ENOENT)
- return NAME_NOT_FOUND;
- else if (err == EACCES)
- return PERMISSION_DENIED;
- else
- return UNKNOWN_ERROR;
-}
-
-/*
- * Open a file and parse its guts.
- */
-status_t ZipFile::open(const char* zipFileName, int flags)
-{
- bool newArchive = false;
-
- assert(mZipFp == NULL); // no reopen
-
- if ((flags & kOpenTruncate))
- flags |= kOpenCreate; // trunc implies create
-
- if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
- return INVALID_OPERATION; // not both
- if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
- return INVALID_OPERATION; // not neither
- if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
- return INVALID_OPERATION; // create requires write
-
- if (flags & kOpenTruncate) {
- newArchive = true;
- } else {
- newArchive = (access(zipFileName, F_OK) != 0);
- if (!(flags & kOpenCreate) && newArchive) {
- /* not creating, must already exist */
- LOGD("File %s does not exist", zipFileName);
- return NAME_NOT_FOUND;
- }
- }
-
- /* open the file */
- const char* openflags;
- if (flags & kOpenReadWrite) {
- if (newArchive)
- openflags = FILE_OPEN_RW_CREATE;
- else
- openflags = FILE_OPEN_RW;
- } else {
- openflags = FILE_OPEN_RO;
- }
- mZipFp = fopen(zipFileName, openflags);
- if (mZipFp == NULL) {
- int err = errno;
- LOGD("fopen failed: %d\n", err);
- return errnoToStatus(err);
- }
-
- status_t result;
- if (!newArchive) {
- /*
- * Load the central directory. If that fails, then this probably
- * isn't a Zip archive.
- */
- result = readCentralDir();
- } else {
- /*
- * Newly-created. The EndOfCentralDir constructor actually
- * sets everything to be the way we want it (all zeroes). We
- * set mNeedCDRewrite so that we create *something* if the
- * caller doesn't add any files. (We could also just unlink
- * the file if it's brand new and nothing was added, but that's
- * probably doing more than we really should -- the user might
- * have a need for empty zip files.)
- */
- mNeedCDRewrite = true;
- result = NO_ERROR;
- }
-
- if (flags & kOpenReadOnly)
- mReadOnly = true;
- else
- assert(!mReadOnly);
-
- return result;
-}
-
-/*
- * Return the Nth entry in the archive.
- */
-ZipEntry* ZipFile::getEntryByIndex(int idx) const
-{
- if (idx < 0 || idx >= (int) mEntries.size())
- return NULL;
-
- return mEntries[idx];
-}
-
-/*
- * Find an entry by name.
- */
-ZipEntry* ZipFile::getEntryByName(const char* fileName) const
-{
- /*
- * Do a stupid linear string-compare search.
- *
- * There are various ways to speed this up, especially since it's rare
- * to intermingle changes to the archive with "get by name" calls. We
- * don't want to sort the mEntries vector itself, however, because
- * it's used to recreate the Central Directory.
- *
- * (Hash table works, parallel list of pointers in sorted order is good.)
- */
- int idx;
-
- for (idx = mEntries.size()-1; idx >= 0; idx--) {
- ZipEntry* pEntry = mEntries[idx];
- if (!pEntry->getDeleted() &&
- strcmp(fileName, pEntry->getFileName()) == 0)
- {
- return pEntry;
- }
- }
-
- return NULL;
-}
-
-/*
- * Empty the mEntries vector.
- */
-void ZipFile::discardEntries(void)
-{
- int count = mEntries.size();
-
- while (--count >= 0)
- delete mEntries[count];
-
- mEntries.clear();
-}
-
-
-/*
- * Find the central directory and read the contents.
- *
- * The fun thing about ZIP archives is that they may or may not be
- * readable from start to end. In some cases, notably for archives
- * that were written to stdout, the only length information is in the
- * central directory at the end of the file.
- *
- * Of course, the central directory can be followed by a variable-length
- * comment field, so we have to scan through it backwards. The comment
- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
- * itself, plus apparently sometimes people throw random junk on the end
- * just for the fun of it.
- *
- * This is all a little wobbly. If the wrong value ends up in the EOCD
- * area, we're hosed. This appears to be the way that everbody handles
- * it though, so we're in pretty good company if this fails.
- */
-status_t ZipFile::readCentralDir(void)
-{
- status_t result = NO_ERROR;
- unsigned char* buf = NULL;
- off_t fileLength, seekStart;
- long readAmount;
- int i;
-
- fseek(mZipFp, 0, SEEK_END);
- fileLength = ftell(mZipFp);
- rewind(mZipFp);
-
- /* too small to be a ZIP archive? */
- if (fileLength < EndOfCentralDir::kEOCDLen) {
- LOGD("Length is %ld -- too small\n", (long)fileLength);
- result = INVALID_OPERATION;
- goto bail;
- }
-
- buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
- if (buf == NULL) {
- LOGD("Failure allocating %d bytes for EOCD search",
- EndOfCentralDir::kMaxEOCDSearch);
- result = NO_MEMORY;
- goto bail;
- }
-
- if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
- seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
- readAmount = EndOfCentralDir::kMaxEOCDSearch;
- } else {
- seekStart = 0;
- readAmount = (long) fileLength;
- }
- if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
- LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* read the last part of the file into the buffer */
- if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
- LOGD("short file? wanted %ld\n", readAmount);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* find the end-of-central-dir magic */
- for (i = readAmount - 4; i >= 0; i--) {
- if (buf[i] == 0x50 &&
- ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
- {
- LOGV("+++ Found EOCD at buf+%d\n", i);
- break;
- }
- }
- if (i < 0) {
- LOGD("EOCD not found, not Zip\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /* extract eocd values */
- result = mEOCD.readBuf(buf + i, readAmount - i);
- if (result != NO_ERROR) {
- LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
- goto bail;
- }
- //mEOCD.dump();
-
- if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
- mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
- {
- LOGD("Archive spanning not supported\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /*
- * So far so good. "mCentralDirSize" is the size in bytes of the
- * central directory, so we can just seek back that far to find it.
- * We can also seek forward mCentralDirOffset bytes from the
- * start of the file.
- *
- * We're not guaranteed to have the rest of the central dir in the
- * buffer, nor are we guaranteed that the central dir will have any
- * sort of convenient size. We need to skip to the start of it and
- * read the header, then the other goodies.
- *
- * The only thing we really need right now is the file comment, which
- * we're hoping to preserve.
- */
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- LOGD("Failure seeking to central dir offset %ld\n",
- mEOCD.mCentralDirOffset);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Loop through and read the central dir entries.
- */
- LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
- int entry;
- for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
- ZipEntry* pEntry = new ZipEntry;
-
- result = pEntry->initFromCDE(mZipFp);
- if (result != NO_ERROR) {
- LOGD("initFromCDE failed\n");
- delete pEntry;
- goto bail;
- }
-
- mEntries.add(pEntry);
- }
-
-
- /*
- * If all went well, we should now be back at the EOCD.
- */
- {
- unsigned char checkBuf[4];
- if (fread(checkBuf, 1, 4, mZipFp) != 4) {
- LOGD("EOCD check read failed\n");
- result = INVALID_OPERATION;
- goto bail;
- }
- if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
- LOGD("EOCD read check failed\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
- LOGV("+++ EOCD read check passed\n");
- }
-
-bail:
- delete[] buf;
- return result;
-}
-
-
-/*
- * Add a new file to the archive.
- *
- * This requires creating and populating a ZipEntry structure, and copying
- * the data into the file at the appropriate position. The "appropriate
- * position" is the current location of the central directory, which we
- * casually overwrite (we can put it back later).
- *
- * If we were concerned about safety, we would want to make all changes
- * in a temp file and then overwrite the original after everything was
- * safely written. Not really a concern for us.
- */
-status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result = NO_ERROR;
- long lfhPosn, startPosn, endPosn, uncompressedLen;
- FILE* inputFp = NULL;
- unsigned long crc;
- time_t modWhen;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- assert(compressionMethod == ZipEntry::kCompressDeflated ||
- compressionMethod == ZipEntry::kCompressStored);
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- /* make sure it doesn't already exist */
- if (getEntryByName(storageName) != NULL)
- return ALREADY_EXISTS;
-
- if (!data) {
- inputFp = fopen(fileName, FILE_OPEN_RO);
- if (inputFp == NULL)
- return errnoToStatus(errno);
- }
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- pEntry->initNew(storageName, NULL);
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH, even though it's still mostly blank. We need it
- * as a place-holder. In theory the LFH isn't necessary, but in
- * practice some utilities demand it.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
- startPosn = ftell(mZipFp);
-
- /*
- * Copy the data in, possibly compressing it as we go.
- */
- if (sourceType == ZipEntry::kCompressStored) {
- if (compressionMethod == ZipEntry::kCompressDeflated) {
- bool failed = false;
- result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
- if (result != NO_ERROR) {
- LOGD("compression failed, storing\n");
- failed = true;
- } else {
- /*
- * Make sure it has compressed "enough". This probably ought
- * to be set through an API call, but I don't expect our
- * criteria to change over time.
- */
- long src = inputFp ? ftell(inputFp) : size;
- long dst = ftell(mZipFp) - startPosn;
- if (dst + (dst / 10) > src) {
- LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
- src, dst);
- failed = true;
- }
- }
-
- if (failed) {
- compressionMethod = ZipEntry::kCompressStored;
- if (inputFp) rewind(inputFp);
- fseek(mZipFp, startPosn, SEEK_SET);
- /* fall through to kCompressStored case */
- }
- }
- /* handle "no compression" request, or failed compression from above */
- if (compressionMethod == ZipEntry::kCompressStored) {
- if (inputFp) {
- result = copyFpToFp(mZipFp, inputFp, &crc);
- } else {
- result = copyDataToFp(mZipFp, data, size, &crc);
- }
- if (result != NO_ERROR) {
- // don't need to truncate; happens in CDE rewrite
- LOGD("failed copying data in\n");
- goto bail;
- }
- }
-
- // currently seeked to end of file
- uncompressedLen = inputFp ? ftell(inputFp) : size;
- } else if (sourceType == ZipEntry::kCompressDeflated) {
- /* we should support uncompressed-from-compressed, but it's not
- * important right now */
- assert(compressionMethod == ZipEntry::kCompressDeflated);
-
- bool scanResult;
- int method;
- long compressedLen;
-
- scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
- &compressedLen, &crc);
- if (!scanResult || method != ZipEntry::kCompressDeflated) {
- LOGD("this isn't a deflated gzip file?");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
- if (result != NO_ERROR) {
- LOGD("failed copying gzip data in\n");
- goto bail;
- }
- } else {
- assert(false);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * We could write the "Data Descriptor", but there doesn't seem to
- * be any point since we're going to go back and write the LFH.
- *
- * Update file offsets.
- */
- endPosn = ftell(mZipFp); // seeked to end of compressed data
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
- compressionMethod);
- modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
- pEntry->setModWhen(modWhen);
- pEntry->setLFHOffset(lfhPosn);
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Go back and write the LFH.
- */
- if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
-bail:
- if (inputFp != NULL)
- fclose(inputFp);
- delete pEntry;
- return result;
-}
-
-/*
- * Add an entry by copying it from another zip file. If "padding" is
- * nonzero, the specified number of bytes will be added to the "extra"
- * field in the header.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
-status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result;
- long lfhPosn, endPosn;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- if (pEntry == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
- if (result != NO_ERROR)
- goto bail;
- if (padding != 0) {
- result = pEntry->addPadding(padding);
- if (result != NO_ERROR)
- goto bail;
- }
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH. Since we're not recompressing the data, we already
- * have all of the fields filled out.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Copy the data over.
- *
- * If the "has data descriptor" flag is set, we want to copy the DD
- * fields as well. This is a fixed-size area immediately following
- * the data.
- */
- if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- off_t copyLen;
- copyLen = pSourceEntry->getCompressedLen();
- if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
- copyLen += ZipEntry::kDataDescriptorLen;
-
- if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
- != NO_ERROR)
- {
- LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Update file offsets.
- */
- endPosn = ftell(mZipFp);
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
- result = NO_ERROR;
-
-bail:
- delete pEntry;
- return result;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data.
- */
-status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (1) {
- count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
- if (ferror(srcFp) || ferror(dstFp))
- return errnoToStatus(errno);
- if (count == 0)
- break;
-
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "dstFp" will be seeked immediately past the data.
- */
-status_t ZipFile::copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32)
-{
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
- if (size > 0) {
- *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
- if (fwrite(data, 1, size, dstFp) != size) {
- LOGD("fwrite %d bytes failed\n", (int) size);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy some of the bytes in "src" to "dst".
- *
- * If "pCRC32" is NULL, the CRC will not be computed.
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data just written.
- */
-status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (length) {
- long readSize;
-
- readSize = sizeof(tmpBuf);
- if (readSize > length)
- readSize = length;
-
- count = fread(tmpBuf, 1, readSize, srcFp);
- if ((long) count != readSize) { // error or unexpected EOF
- LOGD("fread %d bytes failed\n", (int) readSize);
- return UNKNOWN_ERROR;
- }
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
-
- length -= readSize;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Compress all of the data in "srcFp" and write it to "dstFp".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the compressed data.
- */
-status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
- const void* data, size_t size, unsigned long* pCRC32)
-{
- status_t result = NO_ERROR;
- const size_t kBufSize = 32768;
- unsigned char* inBuf = NULL;
- unsigned char* outBuf = NULL;
- z_stream zstream;
- bool atEof = false; // no feof() aviailable yet
- unsigned long crc;
- int zerr;
-
- /*
- * Create an input buffer and an output buffer.
- */
- inBuf = new unsigned char[kBufSize];
- outBuf = new unsigned char[kBufSize];
- if (inBuf == NULL || outBuf == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- zstream.data_type = Z_UNKNOWN;
-
- zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
- Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
- if (zerr != Z_OK) {
- result = UNKNOWN_ERROR;
- if (zerr == Z_VERSION_ERROR) {
- LOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
- }
-
- crc = crc32(0L, Z_NULL, 0);
-
- /*
- * Loop while we have data.
- */
- do {
- size_t getSize;
- int flush;
-
- /* only read if the input buffer is empty */
- if (zstream.avail_in == 0 && !atEof) {
- LOGV("+++ reading %d bytes\n", (int)kBufSize);
- if (data) {
- getSize = size > kBufSize ? kBufSize : size;
- memcpy(inBuf, data, getSize);
- data = ((const char*)data) + getSize;
- size -= getSize;
- } else {
- getSize = fread(inBuf, 1, kBufSize, srcFp);
- if (ferror(srcFp)) {
- LOGD("deflate read failed (errno=%d)\n", errno);
- goto z_bail;
- }
- }
- if (getSize < kBufSize) {
- LOGV("+++ got %d bytes, EOF reached\n",
- (int)getSize);
- atEof = true;
- }
-
- crc = crc32(crc, inBuf, getSize);
-
- zstream.next_in = inBuf;
- zstream.avail_in = getSize;
- }
-
- if (atEof)
- flush = Z_FINISH; /* tell zlib that we're done */
- else
- flush = Z_NO_FLUSH; /* more to come! */
-
- zerr = deflate(&zstream, flush);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
- result = UNKNOWN_ERROR;
- goto z_bail;
- }
-
- /* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
- {
- LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
- if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
- (size_t)(zstream.next_out - outBuf))
- {
- LOGD("write %d failed in deflate\n",
- (int) (zstream.next_out - outBuf));
- goto z_bail;
- }
-
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- *pCRC32 = crc;
-
-z_bail:
- deflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- delete[] inBuf;
- delete[] outBuf;
-
- return result;
-}
-
-/*
- * Mark an entry as deleted.
- *
- * We will eventually need to crunch the file down, but if several files
- * are being removed (perhaps as part of an "update" process) we can make
- * things considerably faster by deferring the removal to "flush" time.
- */
-status_t ZipFile::remove(ZipEntry* pEntry)
-{
- /*
- * Should verify that pEntry is actually part of this archive, and
- * not some stray ZipEntry from a different file.
- */
-
- /* mark entry as deleted, and mark archive as dirty */
- pEntry->setDeleted();
- mNeedCDRewrite = true;
- return NO_ERROR;
-}
-
-/*
- * Flush any pending writes.
- *
- * In particular, this will crunch out deleted entries, and write the
- * Central Directory and EOCD if we have stomped on them.
- */
-status_t ZipFile::flush(void)
-{
- status_t result = NO_ERROR;
- long eocdPosn;
- int i, count;
-
- if (mReadOnly)
- return INVALID_OPERATION;
- if (!mNeedCDRewrite)
- return NO_ERROR;
-
- assert(mZipFp != NULL);
-
- result = crunchArchive();
- if (result != NO_ERROR)
- return result;
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- count = mEntries.size();
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- pEntry->mCDE.write(mZipFp);
- }
-
- eocdPosn = ftell(mZipFp);
- mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
-
- mEOCD.write(mZipFp);
-
- /*
- * If we had some stuff bloat up during compression and get replaced
- * with plain files, or if we deleted some entries, there's a lot
- * of wasted space at the end of the file. Remove it now.
- */
- if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
- LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
- // not fatal
- }
-
- /* should we clear the "newly added" flag in all entries now? */
-
- mNeedCDRewrite = false;
- return NO_ERROR;
-}
-
-/*
- * Crunch deleted files out of an archive by shifting the later files down.
- *
- * Because we're not using a temp file, we do the operation inside the
- * current file.
- */
-status_t ZipFile::crunchArchive(void)
-{
- status_t result = NO_ERROR;
- int i, count;
- long delCount, adjust;
-
-#if 0
- printf("CONTENTS:\n");
- for (i = 0; i < (int) mEntries.size(); i++) {
- printf(" %d: lfhOff=%ld del=%d\n",
- i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
- }
- printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
-#endif
-
- /*
- * Roll through the set of files, shifting them as appropriate. We
- * could probably get a slight performance improvement by sliding
- * multiple files down at once (because we could use larger reads
- * when operating on batches of small files), but it's not that useful.
- */
- count = mEntries.size();
- delCount = adjust = 0;
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- long span;
-
- if (pEntry->getLFHOffset() != 0) {
- long nextOffset;
-
- /* Get the length of this entry by finding the offset
- * of the next entry. Directory entries don't have
- * file offsets, so we need to find the next non-directory
- * entry.
- */
- nextOffset = 0;
- for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
- nextOffset = mEntries[ii]->getLFHOffset();
- if (nextOffset == 0)
- nextOffset = mEOCD.mCentralDirOffset;
- span = nextOffset - pEntry->getLFHOffset();
-
- assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
- } else {
- /* This is a directory entry. It doesn't have
- * any actual file contents, so there's no need to
- * move anything.
- */
- span = 0;
- }
-
- //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
- // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
-
- if (pEntry->getDeleted()) {
- adjust += span;
- delCount++;
-
- delete pEntry;
- mEntries.removeAt(i);
-
- /* adjust loop control */
- count--;
- i--;
- } else if (span != 0 && adjust > 0) {
- /* shuffle this entry back */
- //printf("+++ Shuffling '%s' back %ld\n",
- // pEntry->getFileName(), adjust);
- result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
- pEntry->getLFHOffset(), span);
- if (result != NO_ERROR) {
- /* this is why you use a temp file */
- LOGE("error during crunch - archive is toast\n");
- return result;
- }
-
- pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
- }
- }
-
- /*
- * Fix EOCD info. We have to wait until the end to do some of this
- * because we use mCentralDirOffset to determine "span" for the
- * last entry.
- */
- mEOCD.mCentralDirOffset -= adjust;
- mEOCD.mNumEntries -= delCount;
- mEOCD.mTotalNumEntries -= delCount;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
-
- assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
- assert(mEOCD.mNumEntries == count);
-
- return result;
-}
-
-/*
- * Works like memmove(), but on pieces of a file.
- */
-status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
-{
- if (dst == src || n <= 0)
- return NO_ERROR;
-
- unsigned char readBuf[32768];
-
- if (dst < src) {
- /* shift stuff toward start of file; must read from start */
- while (n != 0) {
- size_t getSize = sizeof(readBuf);
- if (getSize > n)
- getSize = n;
-
- if (fseek(fp, (long) src, SEEK_SET) != 0) {
- LOGD("filemove src seek %ld failed\n", (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fread(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove read %ld off=%ld failed\n",
- (long) getSize, (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fseek(fp, (long) dst, SEEK_SET) != 0) {
- LOGD("filemove dst seek %ld failed\n", (long) dst);
- return UNKNOWN_ERROR;
- }
-
- if (fwrite(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove write %ld off=%ld failed\n",
- (long) getSize, (long) dst);
- return UNKNOWN_ERROR;
- }
-
- src += getSize;
- dst += getSize;
- n -= getSize;
- }
- } else {
- /* shift stuff toward end of file; must read from end */
- assert(false); // write this someday, maybe
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Get the modification time from a file descriptor.
- */
-time_t ZipFile::getModTime(int fd)
-{
- struct stat sb;
-
- if (fstat(fd, &sb) < 0) {
- LOGD("HEY: fstat on fd %d failed\n", fd);
- return (time_t) -1;
- }
-
- return sb.st_mtime;
-}
-
-
-#if 0 /* this is a bad idea */
-/*
- * Get a copy of the Zip file descriptor.
- *
- * We don't allow this if the file was opened read-write because we tend
- * to leave the file contents in an uncertain state between calls to
- * flush(). The duplicated file descriptor should only be valid for reads.
- */
-int ZipFile::getZipFd(void) const
-{
- if (!mReadOnly)
- return INVALID_OPERATION;
- assert(mZipFp != NULL);
-
- int fd;
- fd = dup(fileno(mZipFp));
- if (fd < 0) {
- LOGD("didn't work, errno=%d\n", errno);
- }
-
- return fd;
-}
-#endif
-
-
-#if 0
-/*
- * Expand data.
- */
-bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
-{
- return false;
-}
-#endif
-
-// free the memory when you're done
-void* ZipFile::uncompress(const ZipEntry* entry)
-{
- size_t unlen = entry->getUncompressedLen();
- size_t clen = entry->getCompressedLen();
-
- void* buf = malloc(unlen);
- if (buf == NULL) {
- return NULL;
- }
-
- fseek(mZipFp, 0, SEEK_SET);
-
- off_t offset = entry->getFileOffset();
- if (fseek(mZipFp, offset, SEEK_SET) != 0) {
- goto bail;
- }
-
- switch (entry->getCompressionMethod())
- {
- case ZipEntry::kCompressStored: {
- ssize_t amt = fread(buf, 1, unlen, mZipFp);
- if (amt != (ssize_t)unlen) {
- goto bail;
- }
-#if 0
- printf("data...\n");
- const unsigned char* p = (unsigned char*)buf;
- const unsigned char* end = p+unlen;
- for (int i=0; i<32 && p < end; i++) {
- printf("0x%08x ", (int)(offset+(i*0x10)));
- for (int j=0; j<0x10 && p < end; j++) {
- printf(" %02x", *p);
- p++;
- }
- printf("\n");
- }
-#endif
-
- }
- break;
- case ZipEntry::kCompressDeflated: {
- if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
- goto bail;
- }
- }
- break;
- default:
- goto bail;
- }
- return buf;
-
-bail:
- free(buf);
- return NULL;
-}
-
-
-/*
- * ===========================================================================
- * ZipFile::EndOfCentralDir
- * ===========================================================================
- */
-
-/*
- * Read the end-of-central-dir fields.
- *
- * "buf" should be positioned at the EOCD signature, and should contain
- * the entire EOCD area including the comment.
- */
-status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
-{
- /* don't allow re-use */
- assert(mComment == NULL);
-
- if (len < kEOCDLen) {
- /* looks like ZIP file got truncated */
- LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
- kEOCDLen, len);
- return INVALID_OPERATION;
- }
-
- /* this should probably be an assert() */
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
- return UNKNOWN_ERROR;
-
- mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
- mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
- mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
- mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
- mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
- mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
- mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
-
- // TODO: validate mCentralDirOffset
-
- if (mCommentLen > 0) {
- if (kEOCDLen + mCommentLen > len) {
- LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
- kEOCDLen, mCommentLen, len);
- return UNKNOWN_ERROR;
- }
- mComment = new unsigned char[mCommentLen];
- memcpy(mComment, buf + kEOCDLen, mCommentLen);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Write an end-of-central-directory section.
- */
-status_t ZipFile::EndOfCentralDir::write(FILE* fp)
-{
- unsigned char buf[kEOCDLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
- ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
- ZipEntry::putShortLE(&buf[0x08], mNumEntries);
- ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
- ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
- ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
- ZipEntry::putShortLE(&buf[0x14], mCommentLen);
-
- if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
- return UNKNOWN_ERROR;
- if (mCommentLen > 0) {
- assert(mComment != NULL);
- if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of an EndOfCentralDir object.
- */
-void ZipFile::EndOfCentralDir::dump(void) const
-{
- LOGD(" EndOfCentralDir contents:\n");
- LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
- mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
- LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
- mCentralDirSize, mCentralDirOffset, mCommentLen);
-}
-
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
deleted file mode 100644
index 2e3c3a0..0000000
--- a/libs/utils/executablepath_darwin.cpp
+++ /dev/null
@@ -1,31 +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.
- */
-
-#include <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-void executablepath(char s[PATH_MAX])
-{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
-}
-
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
deleted file mode 100644
index b8d2a3d..0000000
--- a/libs/utils/executablepath_linux.cpp
+++ /dev/null
@@ -1,30 +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.
- */
-
-#include <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void executablepath(char exe[PATH_MAX])
-{
- char proc[100];
- sprintf(proc, "/proc/%d/exe", getpid());
-
- int err = readlink(proc, exe, PATH_MAX);
-}
-
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
deleted file mode 100644
index ab48c69..0000000
--- a/libs/utils/futex_synchro.c
+++ /dev/null
@@ -1,176 +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.
- */
-
-#include <stdio.h>
-#include <limits.h>
-
-#include <sys/time.h>
-#include <sched.h>
-
-#include <errno.h>
-
-#include <private/utils/futex_synchro.h>
-
-
-// This futex glue code is need on desktop linux, but is already part of bionic.
-#if !defined(HAVE_FUTEX_WRAPPERS)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-typedef unsigned int u32;
-#define asmlinkage
-#define __user
-#include <linux/futex.h>
-#include <utils/Atomic.h>
-
-
-int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
-{
- int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
- return err == 0 ? 0 : -errno;
-}
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout)
-{
- return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0);
-}
-
-int __futex_wake(volatile void *ftx, int count)
-{
- return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0);
-}
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
-{
- return android_atomic_cmpxchg(old, _new, ptr);
-}
-
-int __atomic_swap(int _new, volatile int *ptr)
-{
- return android_atomic_swap(_new, ptr);
-}
-
-int __atomic_dec(volatile int *ptr)
-{
- return android_atomic_dec(ptr);
-}
-
-#else // !defined(__arm__)
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
-int __futex_wake(volatile void *ftx, int count);
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
-int __atomic_swap(int _new, volatile int *ptr);
-int __atomic_dec(volatile int *ptr);
-
-#endif // !defined(HAVE_FUTEX_WRAPPERS)
-
-
-// lock states
-//
-// 0: unlocked
-// 1: locked, no waiters
-// 2: locked, maybe waiters
-
-void futex_mutex_init(futex_mutex_t *m)
-{
- m->value = 0;
-}
-
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- if(msec == FUTEX_WAIT_INFINITE) {
- while(__atomic_swap(2, &m->value) != 0) {
- __futex_wait(&m->value, 2, 0);
- }
- } else {
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- while(__atomic_swap(2, &m->value) != 0) {
- if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) {
- return -1;
- }
- }
- }
- return 0;
-}
-
-int futex_mutex_trylock(futex_mutex_t *m)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- return -1;
-}
-
-void futex_mutex_unlock(futex_mutex_t *m)
-{
- if(__atomic_dec(&m->value) != 1) {
- m->value = 0;
- __futex_wake(&m->value, 1);
- }
-}
-
-/* XXX *technically* there is a race condition that could allow
- * XXX a signal to be missed. If thread A is preempted in _wait()
- * XXX after unlocking the mutex and before waiting, and if other
- * XXX threads call signal or broadcast UINT_MAX times (exactly),
- * XXX before thread A is scheduled again and calls futex_wait(),
- * XXX then the signal will be lost.
- */
-
-void futex_cond_init(futex_cond_t *c)
-{
- c->value = 0;
-}
-
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec)
-{
- if(msec == FUTEX_WAIT_INFINITE){
- int oldvalue = c->value;
- futex_mutex_unlock(m);
- __futex_wait(&c->value, oldvalue, 0);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return 0;
- } else {
- int oldvalue = c->value;
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- futex_mutex_unlock(m);
- const int err = __futex_wait(&c->value, oldvalue, &ts);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return err;
- }
-}
-
-void futex_cond_signal(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, 1);
-}
-
-void futex_cond_broadcast(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, INT_MAX);
-}
-
diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp
deleted file mode 100644
index 656e46f..0000000
--- a/libs/utils/ported.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Ports of standard functions that don't exist on a specific platform.
-//
-// Note these are NOT in the "android" namespace.
-//
-#include <utils/ported.h>
-
-#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP)
-# include <sys/time.h>
-# include <windows.h>
-#endif
-
-
-#if defined(NEED_GETTIMEOFDAY)
-/*
- * Replacement gettimeofday() for Windows environments (primarily MinGW).
- *
- * Ignores "tz".
- */
-int gettimeofday(struct timeval* ptv, struct timezone* tz)
-{
- long long nsTime; // time in 100ns units since Jan 1 1601
- FILETIME ft;
-
- if (tz != NULL) {
- // oh well
- }
-
- ::GetSystemTimeAsFileTime(&ft);
- nsTime = (long long) ft.dwHighDateTime << 32 |
- (long long) ft.dwLowDateTime;
- // convert to time in usec since Jan 1 1970
- ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL);
- ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL);
-
- return 0;
-}
-#endif
-
-#if defined(NEED_USLEEP)
-//
-// Replacement usleep for Windows environments (primarily MinGW).
-//
-void usleep(unsigned long usec)
-{
- // Win32 API function Sleep() takes milliseconds
- ::Sleep((usec + 500) / 1000);
-}
-#endif
-
-#if 0 //defined(NEED_PIPE)
-//
-// Replacement pipe() command for MinGW
-//
-// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the
-// SecurityAttributes argument to CreatePipe(). This means the handles
-// aren't inherited when a new process is created. The examples I've seen
-// use it, possibly because there's a lot of junk going on behind the
-// scenes. (I'm assuming "process" and "thread" are different here, so
-// we should be okay spinning up a thread.) The recommended practice is
-// to dup() the descriptor you want the child to have.
-//
-// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O.
-// You can't use select() either, since that only works on sockets. The
-// Windows API calls that are useful here all operate on a HANDLE, not
-// an integer file descriptor, and I don't think you can get there from
-// here. The "named pipe" stuff is insane.
-//
-int pipe(int filedes[2])
-{
- return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT);
-}
-#endif
-
-#if defined(NEED_SETENV)
-/*
- * MinGW lacks these. For now, just stub them out so the code compiles.
- */
-int setenv(const char* name, const char* value, int overwrite)
-{
- return 0;
-}
-void unsetenv(const char* name)
-{
-}
-char* getenv(const char* name)
-{
- return NULL;
-}
-#endif
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 53e46b7..2ce1273 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -36,11 +36,11 @@
* coordinate into a (partial) address. The amount of detail in a
* reverse geocoded location description may vary, for example one
* might contain the full street address of the closest building, while
- * another might contain only a city name and postal code.
+ * another might contain only a city name and postal code.
*
* The Geocoder class requires a backend service that is not included in
- * the core android framework. The Geocoder query methods will return an
- * empty list if there no backend service in the platform.
+ * the core android framework. The Geocoder query methods will return an
+ * empty list if there no backend service in the platform.
*/
public final class Geocoder {
private static final String TAG = "Geocoder";
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 2cda7fa..ce69ac1 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -115,6 +115,18 @@
void onGpsStatusChanged(int event);
}
+ /**
+ * Used for receiving NMEA sentences from the GPS.
+ * NMEA 0183 is a standard for communicating with marine electronic devices
+ * and is a common method for receiving data from a GPS, typically over a serial port.
+ * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+ * You can implement this interface and call {@link LocationManager#addNmeaListener}
+ * to receive NMEA data from the GPS engine.
+ */
+ public interface NmeaListener {
+ void onNmeaReceived(long timestamp, String nmea);
+ }
+
GpsStatus() {
for (int i = 0; i < mSatellites.length; i++) {
mSatellites[i] = new GpsSatellite(i + 1);
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl
index 5dc0fe8..62b1c6b 100644
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ b/location/java/android/location/IGpsStatusListener.aidl
@@ -29,4 +29,5 @@
void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs,
in float[] elevations, in float[] azimuths,
int ephemerisMask, int almanacMask, int usedInFixMask);
+ void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 86ea66f..8f0352d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -51,6 +51,8 @@
private ILocationManager mService;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
+ private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
+ new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
private final GpsStatus mGpsStatus = new GpsStatus();
/**
@@ -68,7 +70,7 @@
* satellites. Depending on conditions, this provider may take a while to return
* a location fix.
*
- * Requires the permission android.permissions.ACCESS_FINE_LOCATION.
+ * Requires the permission android.permission.ACCESS_FINE_LOCATION.
*
* <p> The extras Bundle for the GPS location provider can contain the
* following key/value pairs:
@@ -1123,49 +1125,103 @@
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
private final GpsStatus.Listener mListener;
+ private final GpsStatus.NmeaListener mNmeaListener;
+
+ // This must not equal any of the GpsStatus event IDs
+ private static final int NMEA_RECEIVED = 1000;
+
+ private class Nmea {
+ long mTimestamp;
+ String mNmea;
+
+ Nmea(long timestamp, String nmea) {
+ mTimestamp = timestamp;
+ mNmea = nmea;
+ }
+ }
+ private ArrayList<Nmea> mNmeaBuffer;
GpsStatusListenerTransport(GpsStatus.Listener listener) {
mListener = listener;
+ mNmeaListener = null;
+ }
+
+ GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
+ mNmeaListener = listener;
+ mListener = null;
+ mNmeaBuffer = new ArrayList<Nmea>();
}
public void onGpsStarted() {
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_STARTED;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_STARTED;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onGpsStopped() {
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_STOPPED;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_STOPPED;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onFirstFix(int ttff) {
- mGpsStatus.setTimeToFirstFix(ttff);
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ mGpsStatus.setTimeToFirstFix(ttff);
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
float[] elevations, float[] azimuths, int ephemerisMask,
int almanacMask, int usedInFixMask) {
- mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
- ephemerisMask, almanacMask, usedInFixMask);
+ if (mListener != null) {
+ mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
+ ephemerisMask, almanacMask, usedInFixMask);
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
- // remove any SV status messages already in the queue
- mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
- mGpsHandler.sendMessage(msg);
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
+ // remove any SV status messages already in the queue
+ mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+ mGpsHandler.sendMessage(msg);
+ }
+ }
+
+ public void onNmeaReceived(long timestamp, String nmea) {
+ if (mNmeaListener != null) {
+ synchronized (mNmeaBuffer) {
+ mNmeaBuffer.add(new Nmea(timestamp, nmea));
+ }
+ Message msg = Message.obtain();
+ msg.what = NMEA_RECEIVED;
+ // remove any NMEA_RECEIVED messages already in the queue
+ mGpsHandler.removeMessages(NMEA_RECEIVED);
+ mGpsHandler.sendMessage(msg);
+ }
}
private final Handler mGpsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- // synchronize on mGpsStatus to ensure the data is copied atomically.
- synchronized(mGpsStatus) {
- mListener.onGpsStatusChanged(msg.what);
+ if (msg.what == NMEA_RECEIVED) {
+ synchronized (mNmeaBuffer) {
+ int length = mNmeaBuffer.size();
+ for (int i = 0; i < length; i++) {
+ Nmea nmea = mNmeaBuffer.get(i);
+ mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+ }
+ mNmeaBuffer.clear();
+ }
+ } else {
+ // synchronize on mGpsStatus to ensure the data is copied atomically.
+ synchronized(mGpsStatus) {
+ mListener.onGpsStatusChanged(msg.what);
+ }
}
}
};
@@ -1217,6 +1273,52 @@
}
}
+ /**
+ * Adds an NMEA listener.
+ *
+ * @param listener a {#link GpsStatus.NmeaListener} object to register
+ *
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ */
+ public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+ boolean result;
+
+ if (mNmeaListeners.get(listener) != null) {
+ // listener is already registered
+ return true;
+ }
+ try {
+ GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
+ result = mService.addGpsStatusListener(transport);
+ if (result) {
+ mNmeaListeners.put(listener, transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Removes an NMEA listener.
+ *
+ * @param listener a {#link GpsStatus.NmeaListener} object to remove
+ */
+ public void removeNmeaListener(GpsStatus.NmeaListener listener) {
+ try {
+ GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+ if (transport != null) {
+ mService.removeGpsStatusListener(transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+ }
+ }
+
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 4a51e31..bdef01f 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Config;
import android.util.Log;
import android.util.SparseIntArray;
@@ -183,8 +184,6 @@
// number of fixes we have received since we started navigating
private int mFixCount;
- private int mPositionMode = GPS_POSITION_MODE_STANDALONE;
-
// true if we started navigation
private boolean mStarted;
@@ -198,6 +197,10 @@
// properties loaded from PROPERTIES_FILE
private Properties mProperties;
private String mNtpServer;
+ private String mSuplServerHost;
+ private int mSuplServerPort;
+ private String mC2KServerHost;
+ private int mC2KServerPort;
private final Context mContext;
private final ILocationManager mLocationManager;
@@ -349,27 +352,21 @@
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
- String host = mProperties.getProperty("SUPL_HOST");
+ mSuplServerHost = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
- if (host != null && portString != null) {
+ if (mSuplServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_SUPL, host, port);
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ mSuplServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
}
}
- host = mProperties.getProperty("C2K_HOST");
+ mC2KServerHost = mProperties.getProperty("C2K_HOST");
portString = mProperties.getProperty("C2K_PORT");
- if (host != null && portString != null) {
+ if (mC2KServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_C2K, host, port);
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ mC2KServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
@@ -499,6 +496,13 @@
mEnabled = native_init();
if (mEnabled) {
+ if (mSuplServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+ }
+ if (mC2KServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
+ }
+
// run event listener thread while we are enabled
mEventThread = new GpsEventThread();
mEventThread.start();
@@ -722,7 +726,15 @@
if (!mStarted) {
if (DEBUG) Log.d(TAG, "startNavigating");
mStarted = true;
- if (!native_start(mPositionMode, false, mFixInterval)) {
+ int positionMode;
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ASSISTED_GPS_ENABLED, 0) != 0) {
+ positionMode = GPS_POSITION_MODE_MS_BASED;
+ } else {
+ positionMode = GPS_POSITION_MODE_STANDALONE;
+ }
+
+ if (!native_start(positionMode, false, mFixInterval)) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
return;
@@ -1002,6 +1014,32 @@
}
}
+ /**
+ * called from native code to report NMEA data received
+ */
+ private void reportNmea(int index, long timestamp) {
+ synchronized(mListeners) {
+ int size = mListeners.size();
+ if (size > 0) {
+ // don't bother creating the String if we have no listeners
+ int length = native_read_nmea(index, mNmeaBuffer, mNmeaBuffer.length);
+ String nmea = new String(mNmeaBuffer, 0, length);
+
+ for (int i = 0; i < size; i++) {
+ Listener listener = mListeners.get(i);
+ try {
+ listener.mListener.onNmeaReceived(timestamp, nmea);
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException in reportNmea");
+ mListeners.remove(listener);
+ // adjust for size of list changing
+ size--;
+ }
+ }
+ }
+ }
+ }
+
private void xtraDownloadRequest() {
if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
if (mNetworkThread != null) {
@@ -1182,6 +1220,8 @@
private float mSvAzimuths[] = new float[MAX_SVS];
private int mSvMasks[] = new int[3];
private int mSvCount;
+ // preallocated to avoid memory allocation in reportNmea()
+ private byte[] mNmeaBuffer = new byte[120];
static { class_init_native(); }
private static native void class_init_native();
@@ -1199,6 +1239,7 @@
// mask[0] is ephemeris mask and mask[1] is almanac mask
private native int native_read_sv_status(int[] svs, float[] snrs,
float[] elevations, float[] azimuths, int[] masks);
+ private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
// XTRA Support
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java
index 2a8be57..33ebce7 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/location/java/com/android/internal/location/GpsXtraDownloader.java
@@ -64,6 +64,7 @@
if (count == 0) {
Log.e(TAG, "No XTRA servers were specified in the GPS configuration");
+ return;
} else {
mXtraServers = new String[count];
count = 0;
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 0732b61..b3aae72 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -37,15 +37,61 @@
public static final int ENCODING_PCM_8BIT = 3; // accessed by native code
/** Invalid audio channel configuration */
- public static final int CHANNEL_CONFIGURATION_INVALID = 0;
+ /** @deprecated use CHANNEL_INVALID instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0;
/** Default audio channel configuration */
- public static final int CHANNEL_CONFIGURATION_DEFAULT = 1;
+ /** @deprecated use CHANNEL_OUT_DEFAULT or CHANNEL_IN_DEFAULT instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_DEFAULT = 1;
/** Mono audio configuration */
- public static final int CHANNEL_CONFIGURATION_MONO = 2;
+ /** @deprecated use CHANNEL_OUT_MONO or CHANNEL_IN_MONO instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_MONO = 2;
/** Stereo (2 channel) audio configuration */
- public static final int CHANNEL_CONFIGURATION_STEREO = 3;
+ /** @deprecated use CHANNEL_OUT_STEREO or CHANNEL_IN_STEREO instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_STEREO = 3;
+
+ /** Invalid audio channel mask */
+ public static final int CHANNEL_INVALID = 0;
+ /** Default audio channel mask */
+ public static final int CHANNEL_OUT_DEFAULT = 1;
+
+ // Channel mask definitions must be kept in sync with native values in include/media/AudioSystem.h
+ public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
+ public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
+ public static final int CHANNEL_OUT_FRONT_CENTER = 0x10;
+ public static final int CHANNEL_OUT_LOW_FREQUENCY = 0x20;
+ public static final int CHANNEL_OUT_BACK_LEFT = 0x40;
+ public static final int CHANNEL_OUT_BACK_RIGHT = 0x80;
+ public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100;
+ public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200;
+ public static final int CHANNEL_OUT_BACK_CENTER = 0x400;
+ public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
+ public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
+ public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ public static final int CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER);
+ public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER);
+
+ public static final int CHANNEL_IN_DEFAULT = 1;
+ public static final int CHANNEL_IN_LEFT = 0x4;
+ public static final int CHANNEL_IN_RIGHT = 0x8;
+ public static final int CHANNEL_IN_FRONT = 0x10;
+ public static final int CHANNEL_IN_BACK = 0x20;
+ public static final int CHANNEL_IN_LEFT_PROCESSED = 0x40;
+ public static final int CHANNEL_IN_RIGHT_PROCESSED = 0x80;
+ public static final int CHANNEL_IN_FRONT_PROCESSED = 0x100;
+ public static final int CHANNEL_IN_BACK_PROCESSED = 0x200;
+ public static final int CHANNEL_IN_PRESSURE = 0x400;
+ public static final int CHANNEL_IN_X_AXIS = 0x800;
+ public static final int CHANNEL_IN_Y_AXIS = 0x1000;
+ public static final int CHANNEL_IN_Z_AXIS = 0x2000;
+ public static final int CHANNEL_IN_VOICE_UPLINK = 0x4000;
+ public static final int CHANNEL_IN_VOICE_DNLINK = 0x8000;
+ public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;
+ public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
}
-
-
-
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a65a417..16bf8a2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -140,24 +140,19 @@
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide The audio stream for phone calls when connected to bluetooth */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
+ /** @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
+ /** The audio stream for DTMF Tones */
+ public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
+ /** @hide The audio stream for text to speech (TTS) */
+ public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
/** Number of audio streams */
/**
* @deprecated Use AudioSystem.getNumStreamTypes() instead
*/
- public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
+ @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
- /** @hide Maximum volume index values for audio streams */
- public static final 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
- };
-
/** @hide Default volume index values for audio streams */
public static final int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
@@ -166,7 +161,10 @@
11, // STREAM_MUSIC
6, // STREAM_ALARM
5, // STREAM_NOTIFICATION
- 7 // STREAM_BLUETOOTH_SCO
+ 7, // STREAM_BLUETOOTH_SCO
+ 5, // STREAM_SYSTEM_ENFORCED
+ 11, // STREAM_DTMF
+ 11 // STREAM_TTS
};
/**
@@ -637,9 +635,12 @@
* <var>false</var> to turn it off
*/
public void setSpeakerphoneOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_SPEAKER: 0, ROUTE_SPEAKER);
+ IAudioService service = getService();
+ try {
+ service.setSpeakerphoneOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setSpeakerphoneOn", e);
+ }
}
/**
@@ -648,41 +649,52 @@
* @return true if speakerphone is on, false if it's off
*/
public boolean isSpeakerphoneOn() {
- return (getRoutingP(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
+ IAudioService service = getService();
+ try {
+ return service.isSpeakerphoneOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isSpeakerphoneOn", e);
+ return false;
+ }
}
/**
- * Sets audio routing to the Bluetooth headset on or off.
+ * Request use of Bluetooth SCO headset for communications.
*
- * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth
- * headset; <var>false</var> to route audio to/from phone earpiece
+ * @param on set <var>true</var> to use bluetooth SCO for communications;
+ * <var>false</var> to not use bluetooth SCO for communications
*/
public void setBluetoothScoOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_SCO: 0, ROUTE_BLUETOOTH_SCO);
+ IAudioService service = getService();
+ try {
+ service.setBluetoothScoOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setBluetoothScoOn", e);
+ }
}
/**
- * Checks whether audio routing to the Bluetooth headset is on or off.
+ * Checks whether communications use Bluetooth SCO.
*
- * @return true if SCO audio is being routed to/from Bluetooth headset;
+ * @return true if SCO is used for communications;
* false if otherwise
*/
public boolean isBluetoothScoOn() {
- return (getRoutingP(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
+ IAudioService service = getService();
+ try {
+ return service.isBluetoothScoOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isBluetoothScoOn", e);
+ return false;
+ }
}
/**
- * Sets A2DP audio routing to the Bluetooth headset on or off.
- *
* @param on set <var>true</var> to route A2DP audio to/from Bluetooth
* headset; <var>false</var> disable A2DP audio
+ * @deprecated Do not use.
*/
- public void setBluetoothA2dpOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
+ @Deprecated public void setBluetoothA2dpOn(boolean on){
}
/**
@@ -692,7 +704,12 @@
* false if otherwise
*/
public boolean isBluetoothA2dpOn() {
- return (getRoutingP(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
+ if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,"")
+ == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
+ return false;
+ } else {
+ return true;
+ }
}
/**
@@ -700,12 +717,9 @@
*
* @param on set <var>true</var> to route audio to/from wired
* headset; <var>false</var> disable wired headset audio
- * @hide
+ * @deprecated Do not use.
*/
- public void setWiredHeadsetOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_HEADSET: 0, ROUTE_HEADSET);
+ @Deprecated public void setWiredHeadsetOn(boolean on){
}
/**
@@ -713,10 +727,14 @@
*
* @return true if audio is being routed to/from wired headset;
* false if otherwise
- * @hide
*/
public boolean isWiredHeadsetOn() {
- return (getRoutingP(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
+ if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,"")
+ == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
+ return false;
+ } else {
+ return true;
+ }
}
/**
@@ -726,12 +744,7 @@
* <var>false</var> to turn mute off
*/
public void setMicrophoneMute(boolean on){
- IAudioService service = getService();
- try {
- service.setMicrophoneMute(on);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMicrophoneMute", e);
- }
+ AudioSystem.muteMicrophone(on);
}
/**
@@ -740,13 +753,7 @@
* @return true if microphone is muted, false if it's not
*/
public boolean isMicrophoneMute() {
- IAudioService service = getService();
- try {
- return service.isMicrophoneMute();
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMicrophoneMute", e);
- return false;
- }
+ return AudioSystem.isMicrophoneMuted();
}
/**
@@ -809,32 +816,39 @@
/* Routing bits for setRouting/getRouting API */
/**
* Routing audio output to earpiece
+ * @deprecated
*/
- public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
+ @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
/**
* Routing audio output to spaker
+ * @deprecated
*/
- public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
+ @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
/**
* @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
+ * @deprecated
*/
@Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to bluetooth SCO
+ * @deprecated
*/
- public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
+ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to headset
+ * @deprecated
*/
- public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
+ @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
/**
* Routing audio output to bluetooth A2DP
+ * @deprecated
*/
- public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
/**
* Used for mask parameter of {@link #setRouting(int,int,int)}.
+ * @deprecated
*/
- public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
+ @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
/**
* Sets the audio routing for a specified mode
@@ -846,16 +860,10 @@
* ROUTE_xxx types. Unset bits indicate the route should be left unchanged
*
* @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
- * setBluetoothScoOn(), setBluetoothA2dpOn() and setWiredHeadsetOn() methods instead.
+ * setBluetoothScoOn() methods instead.
*/
-
+ @Deprecated
public void setRouting(int mode, int routes, int mask) {
- IAudioService service = getService();
- try {
- service.setRouting(mode, routes, mask);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setRouting", e);
- }
}
/**
@@ -869,13 +877,7 @@
*/
@Deprecated
public int getRouting(int mode) {
- IAudioService service = getService();
- try {
- return service.getRouting(mode);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in getRouting", e);
- return -1;
- }
+ return -1;
}
/**
@@ -884,13 +886,7 @@
* @return true if any music tracks are active.
*/
public boolean isMusicActive() {
- IAudioService service = getService();
- try {
- return service.isMusicActive();
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMusicActive", e);
- return false;
- }
+ return AudioSystem.isMusicActive();
}
/*
@@ -906,14 +902,32 @@
*/
/**
* @hide
+ * @deprecated Use {@link #setPrameters(String)} instead
*/
- public void setParameter(String key, String value) {
- IAudioService service = getService();
- try {
- service.setParameter(key, value);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setParameter", e);
- }
+ @Deprecated public void setParameter(String key, String value) {
+ setParameters(key+"="+value);
+ }
+
+ /**
+ * Sets a variable number of parameter values to audio hardware.
+ *
+ * @param keyValuePairs list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ *
+ */
+ public void setParameters(String keyValuePairs) {
+ AudioSystem.setParameters(keyValuePairs);
+ }
+
+ /**
+ * Sets a varaible number of parameter values to audio hardware.
+ *
+ * @param keys list of parameters
+ * @return list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ */
+ public String getParameters(String keys) {
+ return AudioSystem.getParameters(keys);
}
/* Sound effect identifiers */
@@ -1082,31 +1096,4 @@
* {@hide}
*/
private IBinder mICallBack = new Binder();
-
- /**
- * {@hide}
- */
- private void setRoutingP(int mode, int routes, int mask) {
- IAudioService service = getService();
- try {
- service.setRouting(mode, routes, mask);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setRouting", e);
- }
- }
-
-
- /**
- * {@hide}
- */
- private int getRoutingP(int mode) {
- IAudioService service = getService();
- try {
- return service.getRouting(mode);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in getRouting", e);
- return -1;
- }
- }
-
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4d1535f9..7a47157 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -86,7 +86,7 @@
public static final int ERROR_INVALID_OPERATION = -3;
private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16;
- private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE = -19;
private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20;
@@ -133,9 +133,13 @@
*/
private int mChannelCount = 1;
/**
+ * The audio channel mask
+ */
+ private int mChannels = AudioFormat.CHANNEL_IN_MONO;
+ /**
* The current audio channel configuration
*/
- private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO;
/**
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
@@ -193,8 +197,8 @@
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_IN_MONO} and
+ * {@link AudioFormat#CHANNEL_IN_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -224,7 +228,7 @@
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this),
- mRecordSource, mSampleRate, mChannelCount, mAudioFormat, mNativeBufferSizeInBytes);
+ mRecordSource, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing native AudioRecord object.");
return; // with mState == STATE_UNINITIALIZED
@@ -239,6 +243,7 @@
// postconditions:
// mRecordSource is valid
// mChannelCount is valid
+ // mChannels is valid
// mAudioFormat is valid
// mSampleRate is valid
private void audioParamCheck(int audioSource, int sampleRateInHz,
@@ -264,20 +269,25 @@
//--------------
// channel config
+ mChannelConfiguration = channelConfig;
+
switch (channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ mChannels = AudioFormat.CHANNEL_IN_MONO;
break;
+ case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ mChannels = AudioFormat.CHANNEL_IN_STEREO;
break;
default:
mChannelCount = 0;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
- throw (new IllegalArgumentException("Unsupported channel configuration."));
+ mChannels = AudioFormat.CHANNEL_INVALID;
+ mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
+ throw (new IllegalArgumentException("Unsupported channel configuration."));
}
//--------------
@@ -368,8 +378,8 @@
/**
* Returns the configured channel configuration.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
- * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
+ * See {@link AudioFormat#CHANNEL_IN_MONO}
+ * and {@link AudioFormat#CHANNEL_IN_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -425,8 +435,8 @@
* will be polled for new data.
* @param sampleRateInHz the sample rate expressed in Hertz.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_IN_MONO} and
+ * {@link AudioFormat#CHANNEL_IN_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT}.
* @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
@@ -438,14 +448,16 @@
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
+ case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
- case AudioFormat.CHANNEL_CONFIGURATION_INVALID:
+ case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
return AudioRecord.ERROR_BAD_VALUE;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 58c04f3..05b68d4 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -17,9 +17,17 @@
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.BluetoothA2dp;
+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;
import android.media.MediaPlayer.OnCompletionListener;
@@ -36,11 +44,16 @@
import android.provider.Settings.System;
import android.util.Log;
import android.view.VolumePanel;
+import android.os.SystemProperties;
import com.android.internal.telephony.ITelephony;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
/**
@@ -94,16 +107,10 @@
/** @see VolumeStreamState */
private VolumeStreamState[] mStreamStates;
private SettingsObserver mSettingsObserver;
-
- private boolean mMicMute;
+
private int mMode;
- private int[] mRoutes = new int[AudioSystem.NUM_MODES];
private Object mSettingsLock = new Object();
private boolean mMediaServerOk;
- private boolean mSpeakerIsOn;
- private boolean mBluetoothScoIsConnected;
- private boolean mHeadsetIsConnected;
- private boolean mBluetoothA2dpIsConnected;
private SoundPool mSoundPool;
private Object mSoundEffectsLock = new Object();
@@ -135,6 +142,36 @@
{4, -1} // FX_FOCUS_RETURN
};
+ /** @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
+ };
+ /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings
+ * of another stream: This avoids multiplying the volume settings for hidden
+ * stream types that follow other stream behavior for volume settings
+ * NOTE: do not create loops in aliases! */
+ private int[] STREAM_VOLUME_ALIAS = new int[] {
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
+ AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM
+ AudioSystem.STREAM_RING, // STREAM_RING
+ AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
+ AudioSystem.STREAM_ALARM, // STREAM_ALARM
+ AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_BLUETOOTH_SCO
+ AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
+ AudioSystem.STREAM_MUSIC // STREAM_TTS
+ };
+
private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
@@ -178,6 +215,27 @@
*/
private int mVibrateSetting;
+ /** @see System#NOTIFICATIONS_USE_RING_VOLUME */
+ private int mNotificationsUseRingVolume;
+
+ // Broadcast receiver for device connections intent broadcasts
+ private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
+
+ //TODO: use common definitions with HeadsetObserver
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_TTY = (1 << 2);
+ private static final int BIT_FM_HEADSET = (1 << 3);
+ private static final int BIT_FM_SPEAKER = (1 << 4);
+
+ private int mHeadsetState;
+
+ // Devices currently connected
+ private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+
+ // Forced device usage for communications
+ private int mForcedUseForComm;
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -186,20 +244,31 @@
public AudioService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
+
+ // Intialized volume
+ MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
+ "ro.config.vc_call_vol_steps",
+ MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
+
mVolumePanel = new VolumePanel(context, this);
mSettingsObserver = new SettingsObserver();
-
+ mMode = AudioSystem.MODE_NORMAL;
+ mHeadsetState = 0;
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
createAudioSystemThread();
- createStreamStates();
readPersistedSettings();
- readAudioSettings();
+ createStreamStates();
mMediaServerOk = true;
AudioSystem.setErrorCallback(mAudioSystemCallback);
loadSoundEffects();
- mSpeakerIsOn = false;
- mBluetoothScoIsConnected = false;
- mHeadsetIsConnected = false;
- mBluetoothA2dpIsConnected = false;
+
+ // Register for device connection intent broadcasts.
+ IntentFilter intentFilter =
+ new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
+ context.registerReceiver(mReceiver, intentFilter);
+
}
private void createAudioSystemThread() {
@@ -223,65 +292,25 @@
}
private void createStreamStates() {
- final int[] volumeLevelsPhone =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
- final int[] volumeLevelsCoarse =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
- final int[] volumeLevelsFine =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
- final int[] volumeLevelsBtPhone =
- createVolumeLevels(0,
- AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]);
-
int numStreamTypes = AudioSystem.getNumStreamTypes();
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
- final int[] levels;
+ streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i);
+ }
- switch (i) {
-
- case AudioSystem.STREAM_MUSIC:
- levels = volumeLevelsFine;
- break;
-
- case AudioSystem.STREAM_VOICE_CALL:
- levels = volumeLevelsPhone;
- break;
-
- case AudioSystem.STREAM_BLUETOOTH_SCO:
- levels = volumeLevelsBtPhone;
- break;
-
- default:
- levels = volumeLevelsCoarse;
- break;
- }
-
- if (i == AudioSystem.STREAM_BLUETOOTH_SCO) {
- streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels);
- } else {
- streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
+ // Correct stream index values for streams with aliases
+ for (int i = 0; i < numStreamTypes; i++) {
+ if (STREAM_VOLUME_ALIAS[i] != i) {
+ int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i);
+ streams[i].mIndex = streams[i].getValidIndex(index);
+ setStreamVolumeIndex(i, index);
+ index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i);
+ streams[i].mLastAudibleIndex = streams[i].getValidIndex(index);
}
}
}
- private static int[] createVolumeLevels(int offset, int numlevels) {
- double curve = 1.0f; // 1.4f
- int [] volumes = new int[numlevels + offset];
- for (int i = 0; i < offset; i++) {
- volumes[i] = 0;
- }
-
- double val = 0;
- double max = Math.pow(numlevels - 1, curve);
- for (int i = 0; i < numlevels; i++) {
- val = Math.pow(i, curve) / max;
- volumes[offset + i] = (int) (val * 100.0f);
- }
- return volumes;
- }
-
private void readPersistedSettings() {
final ContentResolver cr = mContentResolver;
@@ -291,12 +320,19 @@
mRingerModeAffectedStreams = Settings.System.getInt(cr,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- ((1 << AudioManager.STREAM_RING)|(1 << AudioManager.STREAM_NOTIFICATION)|(1 << AudioManager.STREAM_SYSTEM)));
+ ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
+ (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
mMuteAffectedStreams = System.getInt(cr,
System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
+ mNotificationsUseRingVolume = System.getInt(cr,
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1);
+
+ if (mNotificationsUseRingVolume == 1) {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+ }
// Each stream will read its own persisted settings
// Broadcast the sticky intent
@@ -307,25 +343,13 @@
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
}
- private void readAudioSettings() {
- synchronized (mSettingsLock) {
- mMicMute = AudioSystem.isMicrophoneMuted();
- mMode = AudioSystem.getMode();
- for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
- mRoutes[mode] = AudioSystem.getRouting(mode);
- }
- }
+ private void setStreamVolumeIndex(int stream, int index) {
+ AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10);
}
- private void applyAudioSettings() {
- synchronized (mSettingsLock) {
- AudioSystem.muteMicrophone(mMicMute);
- AudioSystem.setMode(mMode);
- for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
- AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL);
- }
- }
- }
+ private int rescaleIndex(int index, int srcStream, int dstStream) {
+ return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
+ }
///////////////////////////////////////////////////////////////////////////
// IPC methods
@@ -354,44 +378,26 @@
ensureValidDirection(direction);
ensureValidStreamType(streamType);
- boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
- if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) {
- // Redirect the volume change to the ring stream
- streamType = AudioManager.STREAM_RING;
- }
- VolumeStreamState streamState = mStreamStates[streamType];
+ VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
final int oldIndex = streamState.mIndex;
boolean adjustVolume = true;
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
- || streamType == AudioManager.STREAM_RING) {
+ || streamType == AudioSystem.STREAM_RING) {
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(oldIndex, direction);
}
if (adjustVolume && streamState.adjustIndex(direction)) {
-
- boolean alsoUpdateNotificationVolume = notificationsUseRingVolume &&
- streamType == AudioManager.STREAM_RING;
- if (alsoUpdateNotificationVolume) {
- mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction);
- }
-
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
- sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
+ sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,
streamState, 0);
-
- if (alsoUpdateNotificationVolume) {
- sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION,
- SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0);
- }
}
}
@@ -404,9 +410,8 @@
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags) {
ensureValidStreamType(streamType);
- syncRingerAndNotificationStreamVolume(streamType, index, false);
-
- setStreamVolumeInt(streamType, index, false, true);
+ index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
+ setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
// UI, etc.
mVolumePanel.postVolumeChanged(streamType, flags);
@@ -420,37 +425,12 @@
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
// Currently, sending the intent only when the stream is BLUETOOTH_SCO
- if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
+ if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
mContext.sendBroadcast(intent);
}
}
/**
- * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the
- * value in Settings.
- *
- * @param streamType Type of the stream
- * @param index Volume index for the stream
- * @param force If true, set the volume even if the current and desired
- * volume as same
- */
- private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) {
- boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
- if (notificationsUseRingVolume) {
- if (streamType == AudioManager.STREAM_NOTIFICATION) {
- // Redirect the volume change to the ring stream
- streamType = AudioManager.STREAM_RING;
- }
- if (streamType == AudioManager.STREAM_RING) {
- // One-off to sync notification volume to ringer volume
- setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force, true);
- }
- }
- }
-
-
- /**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
*
@@ -491,13 +471,13 @@
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
- return mStreamStates[streamType].mIndex;
+ return (mStreamStates[streamType].mIndex + 5) / 10;
}
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
- return mStreamStates[streamType].getMaxIndex();
+ return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
/** @see AudioManager#getRingerMode() */
@@ -507,11 +487,12 @@
/** @see AudioManager#setRingerMode(int) */
public void setRingerMode(int ringerMode) {
- if (ringerMode != mRingerMode) {
- setRingerModeInt(ringerMode, true);
-
- // Send sticky broadcast
- broadcastRingerMode();
+ synchronized (mSettingsLock) {
+ if (ringerMode != mRingerMode) {
+ setRingerModeInt(ringerMode, true);
+ // Send sticky broadcast
+ broadcastRingerMode();
+ }
}
}
@@ -541,7 +522,7 @@
}
}
}
-
+
// Post a persist ringer mode msg
if (persist) {
sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
@@ -606,39 +587,28 @@
return existingValue;
}
- /** @see AudioManager#setMicrophoneMute(boolean) */
- public void setMicrophoneMute(boolean on) {
- if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
- return;
- }
- synchronized (mSettingsLock) {
- if (on != mMicMute) {
- AudioSystem.muteMicrophone(on);
- mMicMute = on;
- }
- }
- }
-
- /** @see AudioManager#isMicrophoneMute() */
- public boolean isMicrophoneMute() {
- return mMicMute;
- }
-
/** @see AudioManager#setMode(int) */
public void setMode(int mode) {
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
+
+ if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) {
+ return;
+ }
+
synchronized (mSettingsLock) {
+ if (mode == AudioSystem.MODE_CURRENT) {
+ mode = mMode;
+ }
if (mode != mMode) {
- if (AudioSystem.setMode(mode) == AudioSystem.AUDIO_STATUS_OK) {
+ if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
mMode = mode;
}
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int index = mStreamStates[streamType].mIndex;
- syncRingerAndNotificationStreamVolume(streamType, index, true);
- setStreamVolumeInt(streamType, index, true, true);
+ int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+ setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true);
}
}
@@ -647,187 +617,6 @@
return mMode;
}
- /** @see AudioManager#setRouting(int, int, int) */
- public void setRouting(int mode, int routes, int mask) {
- int incallMask = 0;
- int ringtoneMask = 0;
- int normalMask = 0;
-
- if (!checkAudioSettingsPermission("setRouting()")) {
- return;
- }
- synchronized (mSettingsLock) {
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // mode AudioSystem.MODE_INVALID is used only by the following AudioManager methods:
- // setWiredHeadsetOn(), setBluetoothA2dpOn(), setBluetoothScoOn() and setSpeakerphoneOn().
- // If applications are using AudioManager.setRouting() that is now deprecated, the routing
- // command will be ignored.
- if (mode == AudioSystem.MODE_INVALID) {
- switch (mask) {
- case AudioSystem.ROUTE_SPEAKER:
- // handle setSpeakerphoneOn()
- if (routes != 0 && !mSpeakerIsOn) {
- mSpeakerIsOn = true;
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- incallMask = AudioSystem.ROUTE_ALL;
- } else if (routes == 0 && mSpeakerIsOn) {
- mSpeakerIsOn = false;
- if (mBluetoothScoIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
- } else if (mHeadsetIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- incallMask = AudioSystem.ROUTE_ALL;
- }
- break;
-
- case AudioSystem.ROUTE_BLUETOOTH_SCO:
- // handle setBluetoothScoOn()
- if (routes != 0 && !mBluetoothScoIsConnected) {
- mBluetoothScoIsConnected = true;
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_BLUETOOTH_SCO;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_BLUETOOTH_SCO;
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than SCO headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- } else if (routes == 0 && mBluetoothScoIsConnected) {
- mBluetoothScoIsConnected = false;
- if (mHeadsetIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_HEADSET;
- } else {
- if (mSpeakerIsOn) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- }
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than SCO headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- break;
-
- case AudioSystem.ROUTE_HEADSET:
- // handle setWiredHeadsetOn()
- if (routes != 0 && !mHeadsetIsConnected) {
- mHeadsetIsConnected = true;
- // do not act upon headset connection if bluetooth SCO is connected to match phone app behavior
- if (!mBluetoothScoIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_HEADSET;
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than wired headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- } else if (routes == 0 && mHeadsetIsConnected) {
- mHeadsetIsConnected = false;
- // do not act upon headset disconnection if bluetooth SCO is connected to match phone app behavior
- if (!mBluetoothScoIsConnected) {
- if (mSpeakerIsOn) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
-
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than wired headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- }
- break;
-
- case AudioSystem.ROUTE_BLUETOOTH_A2DP:
- // handle setBluetoothA2dpOn()
- if (routes != 0 && !mBluetoothA2dpIsConnected) {
- mBluetoothA2dpIsConnected = true;
- mRoutes[AudioSystem.MODE_RINGTONE] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
- mRoutes[AudioSystem.MODE_NORMAL] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
- // the audio flinger chooses A2DP as a higher priority,
- // so there is no need to disable other routes.
- ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- } else if (routes == 0 && mBluetoothA2dpIsConnected) {
- mBluetoothA2dpIsConnected = false;
- mRoutes[AudioSystem.MODE_RINGTONE] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- mRoutes[AudioSystem.MODE_NORMAL] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- // the audio flinger chooses A2DP as a higher priority,
- // so there is no need to disable other routes.
- ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- break;
- }
-
- // incallMask is != 0 means we must apply ne routing to MODE_IN_CALL mode
- if (incallMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_IN_CALL,
- mRoutes[AudioSystem.MODE_IN_CALL],
- incallMask);
- }
- // ringtoneMask is != 0 means we must apply ne routing to MODE_RINGTONE mode
- if (ringtoneMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_RINGTONE,
- mRoutes[AudioSystem.MODE_RINGTONE],
- ringtoneMask);
- }
- // normalMask is != 0 means we must apply ne routing to MODE_NORMAL mode
- if (normalMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_NORMAL,
- mRoutes[AudioSystem.MODE_NORMAL],
- normalMask);
- }
-
- int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int index = mStreamStates[streamType].mIndex;
- syncRingerAndNotificationStreamVolume(streamType, index, true);
- setStreamVolumeInt(streamType, index, true, true);
- }
- }
- }
-
- /** @see AudioManager#getRouting(int) */
- public int getRouting(int mode) {
- return mRoutes[mode];
- }
-
- /** @see AudioManager#isMusicActive() */
- public boolean isMusicActive() {
- return AudioSystem.isMusicActive();
- }
-
- /** @see AudioManager#setParameter(String, String) */
- public void setParameter(String key, String value) {
- AudioSystem.setParameter(key, value);
- }
-
/** @see AudioManager#playSoundEffect(int) */
public void playSoundEffect(int effectType) {
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
@@ -926,18 +715,29 @@
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
VolumeStreamState streamState = mStreamStates[streamType];
- // there is no volume setting for STREAM_BLUETOOTH_SCO
- if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
- String settingName = System.VOLUME_SETTINGS[streamType];
- String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
-
- streamState.mIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
- settingName,
- AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
- streamState.mLastAudibleIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
- lastAudibleSettingName,
- streamState.mIndex > 0 ? streamState.mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+ String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]];
+ String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+ int index = Settings.System.getInt(mContentResolver,
+ settingName,
+ AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
+ index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
+ } else {
+ index *= 10;
}
+ streamState.mIndex = streamState.getValidIndex(index);
+
+ index = (index + 5) / 10;
+ index = Settings.System.getInt(mContentResolver,
+ lastAudibleSettingName,
+ (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
+ index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
+ } else {
+ index *= 10;
+ }
+ streamState.mLastAudibleIndex = streamState.getValidIndex(index);
+
// unmute stream that whas muted but is not affect by mute anymore
if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
int size = streamState.mDeathHandlers.size();
@@ -948,7 +748,7 @@
}
// apply stream volume
if (streamState.muteCount() == 0) {
- AudioSystem.setVolume(streamType, streamState.mVolumes[streamState.mIndex]);
+ setStreamVolumeIndex(streamType, streamState.mIndex);
}
}
@@ -956,6 +756,48 @@
setRingerModeInt(getRingerMode(), false);
}
+ /** @see AudioManager#setSpeakerphoneOn() */
+ public void setSpeakerphoneOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
+ mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isSpeakerphoneOn() */
+ public boolean isSpeakerphoneOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** @see AudioManager#setBluetoothScoOn() */
+ public void setBluetoothScoOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
+ mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isBluetoothScoOn() */
+ public boolean isBluetoothScoOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Internal methods
///////////////////////////////////////////////////////////////////////////
@@ -969,7 +811,7 @@
boolean adjustVolumeIndex = true;
int newRingerMode = mRingerMode;
- if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1
+ if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && (oldIndex + 5) / 10 == 1
&& direction == AudioManager.ADJUST_LOWER) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
} else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
@@ -1026,7 +868,7 @@
Log.w(TAG, "Couldn't connect to phone service", e);
}
- if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) {
+ if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else if (isOffhook) {
@@ -1110,47 +952,36 @@
private final String mLastAudibleVolumeIndexSettingName;
private final int mStreamType;
- private final int[] mVolumes;
+ private int mIndexMax;
private int mIndex;
private int mLastAudibleIndex;
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death
- private VolumeStreamState(String settingName, int streamType, int[] volumes) {
+ private VolumeStreamState(String settingName, int streamType) {
mVolumeIndexSettingName = settingName;
mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
mStreamType = streamType;
- mVolumes = volumes;
final ContentResolver cr = mContentResolver;
- mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
- mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr,
- mLastAudibleVolumeIndexSettingName, mIndex > 0 ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
-
- AudioSystem.setVolume(streamType, volumes[mIndex]);
- mDeathHandlers = new ArrayList<VolumeDeathHandler>();
- }
-
- /**
- * Constructor to be used when there is no setting associated with the VolumeStreamState.
- *
- * @param defaultVolume Default volume of the stream to use.
- * @param streamType Type of the stream.
- * @param volumes Volumes levels associated with this stream.
- */
- private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) {
- mVolumeIndexSettingName = null;
- mLastAudibleVolumeIndexSettingName = null;
- mIndex = mLastAudibleIndex = defaultVolume;
- mStreamType = streamType;
- mVolumes = volumes;
- AudioSystem.setVolume(mStreamType, defaultVolume);
+ mIndexMax = MAX_STREAM_VOLUME[streamType];
+ mIndex = Settings.System.getInt(cr,
+ mVolumeIndexSettingName,
+ AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ mLastAudibleIndex = Settings.System.getInt(cr,
+ mLastAudibleVolumeIndexSettingName,
+ (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
+ mIndexMax *= 10;
+ mIndex = getValidIndex(10 * mIndex);
+ mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex);
+ setStreamVolumeIndex(streamType, mIndex);
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
}
public boolean adjustIndex(int deltaIndex) {
- return setIndex(mIndex + deltaIndex, true);
+ return setIndex(mIndex + deltaIndex * 10, true);
}
public boolean setIndex(int index, boolean lastAudible) {
@@ -1161,6 +992,13 @@
if (lastAudible) {
mLastAudibleIndex = mIndex;
}
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) {
+ mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible);
+ }
+ }
return true;
} else {
return false;
@@ -1168,7 +1006,7 @@
}
public int getMaxIndex() {
- return mVolumes.length - 1;
+ return mIndexMax;
}
public void mute(IBinder cb, boolean state) {
@@ -1183,8 +1021,8 @@
private int getValidIndex(int index) {
if (index < 0) {
return 0;
- } else if (index >= mVolumes.length) {
- return mVolumes.length - 1;
+ } else if (index > mIndexMax) {
+ return mIndexMax;
}
return index;
@@ -1318,8 +1156,16 @@
private void setSystemVolume(VolumeStreamState streamState) {
// Adjust volume
- AudioSystem
- .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]);
+ setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex);
+
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != streamState.mStreamType &&
+ STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) {
+ setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex);
+ }
+ }
// Post a persist volume msg
sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
@@ -1327,12 +1173,10 @@
}
private void persistVolume(VolumeStreamState streamState) {
- if (streamState.mStreamType != AudioManager.STREAM_BLUETOOTH_SCO) {
- System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
- streamState.mIndex);
- System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
- streamState.mLastAudibleIndex);
- }
+ System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
+ (streamState.mIndex + 5)/ 10);
+ System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
+ (streamState.mLastAudibleIndex + 5) / 10);
}
private void persistRingerMode() {
@@ -1421,25 +1265,45 @@
Log.e(TAG, "Media server died.");
// Force creation of new IAudioflinger interface
mMediaServerOk = false;
- AudioSystem.getMode();
+ AudioSystem.isMusicActive();
break;
case MSG_MEDIA_SERVER_STARTED:
Log.e(TAG, "Media server started.");
- // Restore audio routing and stream volumes
- applyAudioSettings();
+ // Restore device connection states
+ Set set = mConnectedDevices.entrySet();
+ Iterator i = set.iterator();
+ while(i.hasNext()){
+ Map.Entry device = (Map.Entry)i.next();
+ AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ (String)device.getValue());
+ }
+
+ // Restore call state
+ AudioSystem.setPhoneState(mMode);
+
+ // Restore forced usage for communcations and record
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
+
+ // Restore stream volumes
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- int volume;
+ int index;
VolumeStreamState streamState = mStreamStates[streamType];
+ AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
if (streamState.muteCount() == 0) {
- volume = streamState.mVolumes[streamState.mIndex];
+ index = streamState.mIndex;
} else {
- volume = streamState.mVolumes[0];
+ index = 0;
}
- AudioSystem.setVolume(streamType, volume);
+ setStreamVolumeIndex(streamType, index);
}
- setRingerMode(mRingerMode);
+
+ // Restore ringer mode
+ setRingerModeInt(getRingerMode(), false);
+
mMediaServerOk = true;
break;
@@ -1451,28 +1315,183 @@
}
private class SettingsObserver extends ContentObserver {
-
+
SettingsObserver() {
super(new Handler());
mContentResolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
+ mContentResolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
-
- mRingerModeAffectedStreams = Settings.System.getInt(mContentResolver,
- Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- 0);
+ synchronized (mSettingsLock) {
+ int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ 0);
+ if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
+ /*
+ * Ensure all stream types that should be affected by ringer mode
+ * are in the proper state.
+ */
+ mRingerModeAffectedStreams = ringerModeAffectedStreams;
+ setRingerModeInt(getRingerMode(), false);
+ }
- /*
- * Ensure all stream types that should be affected by ringer mode
- * are in the proper state.
- */
- setRingerModeInt(getRingerMode(), false);
+ int notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
+ 1);
+ if (notificationsUseRingVolume != mNotificationsUseRingVolume) {
+ mNotificationsUseRingVolume = notificationsUseRingVolume;
+ if (mNotificationsUseRingVolume == 1) {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+ } else {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
+ // Persist notification volume volume as it was not persisted while aliased to ring volume
+ sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
+ SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY);
+ }
+ }
+ }
}
-
}
-
+
+ /**
+ * Receiver for misc intent broadcasts the Phone app cares about.
+ */
+ private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
+ BluetoothA2dp.STATE_DISCONNECTED);
+ 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));
+
+ if (isConnected &&
+ state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address);
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ } else if (!isConnected &&
+ (state == BluetoothA2dp.STATE_CONNECTED || state != BluetoothA2dp.STATE_PLAYING)){
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ 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);
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+ String address = btDevice.getAddress();
+ int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ int 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:
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ break;
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ boolean isConnected = (mConnectedDevices.containsKey(device) &&
+ ((String)mConnectedDevices.get(device)).equals(address));
+
+ if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address);
+ mConnectedDevices.remove(device);
+ } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ address);
+ mConnectedDevices.put(new Integer(device), address);
+ }
+ } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
+ int state = intent.getIntExtra("state", 0);
+ if ((state & BIT_HEADSET) == 0 &&
+ (mHeadsetState & BIT_HEADSET) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ } else if ((state & BIT_HEADSET) != 0 &&
+ (mHeadsetState & BIT_HEADSET) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
+ }
+ if ((state & BIT_HEADSET_NO_MIC) == 0 &&
+ (mHeadsetState & BIT_HEADSET_NO_MIC) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ } else if ((state & BIT_HEADSET_NO_MIC) != 0 &&
+ (mHeadsetState & BIT_HEADSET_NO_MIC) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
+ }
+ if ((state & BIT_TTY) == 0 &&
+ (mHeadsetState & BIT_TTY) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY);
+ } else if ((state & BIT_TTY) != 0 &&
+ (mHeadsetState & BIT_TTY) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), "");
+ }
+ if ((state & BIT_FM_HEADSET) == 0 &&
+ (mHeadsetState & BIT_FM_HEADSET) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE);
+ } else if ((state & BIT_FM_HEADSET) != 0 &&
+ (mHeadsetState & BIT_FM_HEADSET) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), "");
+ }
+ if ((state & BIT_FM_SPEAKER) == 0 &&
+ (mHeadsetState & BIT_FM_SPEAKER) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER);
+ } else if ((state & BIT_FM_SPEAKER) != 0 &&
+ (mHeadsetState & BIT_FM_SPEAKER) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), "");
+ }
+ mHeadsetState = state;
+ }
+ }
+ }
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 5917ab90..d587f65 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -45,38 +45,21 @@
public static final int STREAM_NOTIFICATION = 5;
/* @hide The audio stream for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;
+ /* @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ public static final int STREAM_SYSTEM_ENFORCED = 7;
+ /* @hide The audio stream for DTMF tones */
+ public static final int STREAM_DTMF = 8;
+ /* @hide The audio stream for text to speech (TTS) */
+ public static final int STREAM_TTS = 9;
/**
* @deprecated Use {@link #numStreamTypes() instead}
*/
public static final int NUM_STREAMS = 5;
// Expose only the getter method publicly so we can change it in the future
- private static final int NUM_STREAM_TYPES = 7;
+ private static final int NUM_STREAM_TYPES = 10;
public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
- /* max and min volume levels */
- /* Maximum volume setting, for use with setVolume(int,int) */
- public static final int MAX_VOLUME = 100;
- /* Minimum volume setting, for use with setVolume(int,int) */
- public static final int MIN_VOLUME = 0;
-
- /*
- * Sets the volume of a specified audio stream.
- *
- * param type the stream type to set the volume of (e.g. STREAM_MUSIC)
- * param volume the volume level to set (0-100)
- * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
- */
- public static native int setVolume(int type, int volume);
-
- /*
- * Returns the volume of a specified audio stream.
- *
- * param type the stream type to get the volume of (e.g. STREAM_MUSIC)
- * return the current volume (0-100)
- */
- public static native int getVolume(int type);
-
/*
* Sets the microphone mute on or off.
*
@@ -101,17 +84,22 @@
* it can route the audio appropriately.
* return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
*/
- public static native int setMode(int mode);
-
+ /** @deprecated use {@link #setPhoneState(int)} */
+ public static int setMode(int mode) {
+ return AUDIO_STATUS_ERROR;
+ }
/*
* Returns the current audio mode.
*
* return the current audio mode (NORMAL, RINGTONE, or IN_CALL).
* Returns the current current audio state from the HAL.
*/
- public static native int getMode();
+ /** @deprecated */
+ public static int getMode() {
+ return MODE_INVALID;
+ }
- /* modes for setMode/getMode/setRoute/getRoute */
+ /* modes for setPhoneState */
public static final int MODE_INVALID = -2;
public static final int MODE_CURRENT = -1;
public static final int MODE_NORMAL = 0;
@@ -121,15 +109,20 @@
/* Routing bits for setRouting/getRouting API */
- public static final int ROUTE_EARPIECE = (1 << 0);
- public static final int ROUTE_SPEAKER = (1 << 1);
-
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_EARPIECE = (1 << 0);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_SPEAKER = (1 << 1);
/** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
@Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2);
- public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
- public static final int ROUTE_HEADSET = (1 << 3);
- public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
- public static final int ROUTE_ALL = 0xFFFFFFFF;
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_HEADSET = (1 << 3);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_ALL = 0xFFFFFFFF;
/*
* Sets the audio routing for a specified mode
@@ -141,7 +134,10 @@
* ROUTE_xxx types. Unset bits indicate the route should be left unchanged
* return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
*/
- public static native int setRouting(int mode, int routes, int mask);
+ /** @deprecated use {@link #setDeviceConnectionState(int,int,String)} */
+ public static int setRouting(int mode, int routes, int mask) {
+ return AUDIO_STATUS_ERROR;
+ }
/*
* Returns the current audio routing bit vector for a specified mode.
@@ -150,7 +146,10 @@
* return an audio route bit vector that can be compared with ROUTE_xxx
* bits
*/
- public static native int getRouting(int mode);
+ /** @deprecated use {@link #getDeviceConnectionState(int,String)} */
+ public static int getRouting(int mode) {
+ return 0;
+ }
/*
* Checks whether any music is active.
@@ -160,17 +159,23 @@
public static native boolean isMusicActive();
/*
- * Sets a generic audio configuration parameter. The use of these parameters
+ * Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependant, see libaudio
*
- * ** Temporary interface - DO NOT USE
- *
- * TODO: Replace with a more generic key:value get/set mechanism
- *
- * param key name of parameter to set. Must not be null.
- * param value value of parameter. Must not be null.
+ * param keyValuePairs list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
*/
- public static native void setParameter(String key, String value);
+ public static native int setParameters(String keyValuePairs);
+
+ /*
+ * Gets a group generic audio configuration parameters. The use of these parameters
+ * are platform dependant, see libaudio
+ *
+ * param keys list of parameters
+ * return value: list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ */
+ public static native String getParameters(String keys);
/*
private final static String TAG = "audio";
@@ -220,4 +225,68 @@
mErrorCallback.onError(error);
}
}
+
+ /*
+ * AudioPolicyService methods
+ */
+
+ // output devices
+ public static final int DEVICE_OUT_EARPIECE = 0x1;
+ public static final int DEVICE_OUT_SPEAKER = 0x2;
+ public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
+ public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
+ public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+ public static final int DEVICE_OUT_FM_HEADPHONE = 0x800;
+ public static final int DEVICE_OUT_FM_SPEAKER = 0x1000;
+ public static final int DEVICE_OUT_TTY = 0x2000;
+ public static final int DEVICE_OUT_DEFAULT = 0x8000;
+ // input devices
+ public static final int DEVICE_IN_COMMUNICATION = 0x10000;
+ public static final int DEVICE_IN_AMBIENT = 0x20000;
+ public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000;
+ public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000;
+ public static final int DEVICE_IN_MIC_ARRAY = 0x100000;
+ public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
+ public static final int DEVICE_IN_WIRED_HEADSET = 0x400000;
+ public static final int DEVICE_IN_AUX_DIGITAL = 0x800000;
+ public static final int DEVICE_IN_DEFAULT = 0x80000000;
+
+ // device states
+ public static final int DEVICE_STATE_UNAVAILABLE = 0;
+ public static final int DEVICE_STATE_AVAILABLE = 1;
+
+ // phone state
+ public static final int PHONE_STATE_OFFCALL = 0;
+ public static final int PHONE_STATE_RINGING = 1;
+ public static final int PHONE_STATE_INCALL = 2;
+
+ // config for setForceUse
+ public static final int FORCE_NONE = 0;
+ public static final int FORCE_SPEAKER = 1;
+ public static final int FORCE_HEADPHONES = 2;
+ public static final int FORCE_BT_SCO = 3;
+ public static final int FORCE_BT_A2DP = 4;
+ public static final int FORCE_WIRED_ACCESSORY = 5;
+ public static final int FORCE_DEFAULT = FORCE_NONE;
+
+ // usage for serForceUse
+ public static final int FOR_COMMUNICATION = 0;
+ public static final int FOR_MEDIA = 1;
+ public static final int FOR_RECORD = 2;
+
+ public static native int setDeviceConnectionState(int device, int state, String device_address);
+ public static native int getDeviceConnectionState(int device, String device_address);
+ public static native int setPhoneState(int state);
+ public static native int setRingerMode(int mode, int mask);
+ public static native int setForceUse(int usage, int config);
+ public static native int getForceUse(int usage);
+ public static native int initStreamVolume(int stream, int indexMin, int indexMax);
+ public static native int setStreamVolumeIndex(int stream, int index);
+ public static native int getStreamVolumeIndex(int stream);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5f1be9d..1e8d72f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -120,7 +120,7 @@
public static final int ERROR_INVALID_OPERATION = -3;
private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16;
- private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK = -17;
private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18;
private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19;
private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20;
@@ -181,10 +181,15 @@
*/
private int mSampleRate = 22050;
/**
- * The number of input audio channels (1 is mono, 2 is stereo).
+ * The number of audio output channels (1 is mono, 2 is stereo).
*/
private int mChannelCount = 1;
/**
+ * The audio channel mask.
+ */
+ private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
+
+ /**
* The type of the audio stream to play. See
* {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
@@ -198,7 +203,7 @@
/**
* The current audio channel configuration.
*/
- private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
/**
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
@@ -235,8 +240,8 @@
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_OUT_MONO} and
+ * {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -266,7 +271,7 @@
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this),
- mStreamType, mSampleRate, mChannelCount, mAudioFormat,
+ mStreamType, mSampleRate, mChannels, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
@@ -286,6 +291,7 @@
// postconditions:
// mStreamType is valid
// mChannelCount is valid
+ // mChannels is valid
// mAudioFormat is valid
// mSampleRate is valid
// mDataLoadMode is valid
@@ -298,7 +304,8 @@
&& (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
&& (streamType != AudioManager.STREAM_VOICE_CALL)
&& (streamType != AudioManager.STREAM_NOTIFICATION)
- && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) {
+ && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)
+ && (streamType != AudioManager.STREAM_DTMF)) {
throw (new IllegalArgumentException("Invalid stream type."));
} else {
mStreamType = streamType;
@@ -315,18 +322,23 @@
//--------------
// channel config
+ mChannelConfiguration = channelConfig;
+
switch (channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_OUT_DEFAULT: //AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ mChannels = AudioFormat.CHANNEL_OUT_MONO;
break;
+ case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ mChannels = AudioFormat.CHANNEL_OUT_STEREO;
break;
default:
mChannelCount = 0;
+ mChannels = AudioFormat.CHANNEL_INVALID;
mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
throw(new IllegalArgumentException("Unsupported channel configuration."));
}
@@ -452,8 +464,8 @@
/**
* Returns the configured channel configuration.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
- * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
+ * See {@link AudioFormat#CHANNEL_OUT_MONO}
+ * and {@link AudioFormat#CHANNEL_OUT_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -531,8 +543,8 @@
* the expected frequency at which the buffer will be refilled with additional data to play.
* @param sampleRateInHz the sample rate expressed in Hertz.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_OUT_MONO} and
+ * {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -544,9 +556,11 @@
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
+ case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
+ case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
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/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9a8264f..d3d2d29 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -29,9 +29,9 @@
void setStreamVolume(int streamType, int index, int flags);
- void setStreamSolo(int streamType, boolean state, IBinder cb);
+ void setStreamSolo(int streamType, boolean state, IBinder cb);
- void setStreamMute(int streamType, boolean state, IBinder cb);
+ void setStreamMute(int streamType, boolean state, IBinder cb);
int getStreamVolume(int streamType);
@@ -46,23 +46,11 @@
int getVibrateSetting(int vibrateType);
boolean shouldVibrate(int vibrateType);
-
- void setMicrophoneMute(boolean on);
-
- boolean isMicrophoneMute();
void setMode(int mode);
int getMode();
- void setRouting(int mode, int routes, int mask);
-
- int getRouting(int mode);
-
- boolean isMusicActive();
-
- void setParameter(String key, String value);
-
oneway void playSoundEffect(int effectType);
oneway void playSoundEffectVolume(int effectType, float volume);
@@ -72,4 +60,12 @@
oneway void unloadSoundEffects();
oneway void reloadAudioSettings();
+
+ void setSpeakerphoneOn(boolean on);
+
+ boolean isSpeakerphoneOn();
+
+ void setBluetoothScoOn(boolean on);
+
+ boolean isBluetoothScoOn();
}
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index d75d81d..1570db4 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -89,7 +89,7 @@
// Jet rendering audio parameters
private static final int JET_OUTPUT_RATE = 22050; // _SAMPLE_RATE_22050 in Android.mk
private static final int JET_OUTPUT_CHANNEL_CONFIG =
- AudioFormat.CHANNEL_CONFIGURATION_STEREO; // NUM_OUTPUT_CHANNELS=2 in Android.mk
+ AudioFormat.CHANNEL_OUT_STEREO; // NUM_OUTPUT_CHANNELS=2 in Android.mk
//--------------------------------------------
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 8be11df..03ffc67 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -41,8 +41,9 @@
public static final int FILE_TYPE_AWB = 5;
public static final int FILE_TYPE_WMA = 6;
public static final int FILE_TYPE_OGG = 7;
+ public static final int FILE_TYPE_AAC = 8;
private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
- private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG;
+ private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_AAC;
// MIDI file types
public static final int FILE_TYPE_MID = 11;
@@ -57,8 +58,9 @@
public static final int FILE_TYPE_3GPP = 23;
public static final int FILE_TYPE_3GPP2 = 24;
public static final int FILE_TYPE_WMV = 25;
+ public static final int FILE_TYPE_ASF = 26;
private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
- private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV;
+ private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_ASF;
// Image file types
public static final int FILE_TYPE_JPEG = 31;
@@ -104,6 +106,7 @@
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
+ addFileType("AAC", FILE_TYPE_AAC, "audio/aac");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
@@ -121,6 +124,7 @@
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
+ addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 3a49a5f..cecf4f8 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -35,6 +35,7 @@
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
// The field below is accessed by native methods
@@ -211,7 +212,8 @@
* allocated internally.
*/
public native void release();
- private native void native_setup();
+ private native void native_setup();
+ private static native void native_init();
private native final void native_finalize();
@@ -252,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 3b46d69..a8689f2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -23,6 +23,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.util.Log;
@@ -33,7 +34,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
-
+import java.util.Set;
import java.lang.ref.WeakReference;
/**
@@ -430,11 +431,49 @@
*/
public class MediaPlayer
{
+ /**
+ Constant to retrieve only the new metadata since the last
+ call.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_UPDATE_ONLY = true;
+
+ /**
+ Constant to retrieve all the metadata.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_ALL = false;
+
+ /**
+ Constant to enable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean APPLY_METADATA_FILTER = true;
+
+ /**
+ Constant to disable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean BYPASS_METADATA_FILTER = false;
+
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaPlayer";
+ // Name of the remote interface for the media player. Must be kept
+ // in sync with the 2nd parameter of the IMPLEMENT_META_INTERFACE
+ // macro invocation in IMediaPlayer.cpp
+ private final static String IMEDIA_PLAYER = "android.media.IMediaPlayer";
private int mNativeContext; // accessed by native methods
private int mListenerContext; // accessed by native methods
@@ -475,6 +514,43 @@
private native void _setVideoSurface();
/**
+ * Create a request parcel which can be routed to the native media
+ * player using {@link #invoke(Parcel, Parcel)}. The Parcel
+ * returned has the proper InterfaceToken set. The caller should
+ * not overwrite that token, i.e it can only append data to the
+ * Parcel.
+ *
+ * @return A parcel suitable to hold a request for the native
+ * player.
+ */
+ public Parcel newRequest() {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInterfaceToken(IMEDIA_PLAYER);
+ return parcel;
+ }
+
+ /**
+ * Invoke a generic method on the native player using opaque
+ * parcels for the request and reply. Both payloads' format is a
+ * convention between the java caller and the native player.
+ * Must be called after setDataSource to make sure a native player
+ * exists.
+ *
+ * @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
+ * native player.
+ *
+ * @return The status code see utils/Errors.h
+ */
+ public int invoke(Parcel request, Parcel reply) {
+ int retcode = native_invoke(request, reply);
+ reply.setDataPosition(0);
+ return retcode;
+ }
+
+ /**
* Sets the SurfaceHolder to use for displaying the video portion of the media.
* This call is optional. Not calling it when playing back a video will
* result in only the audio track being played.
@@ -838,6 +914,89 @@
public native int getDuration();
/**
+ * Gets the media metadata.
+ *
+ * @param update_only controls whether the full set of available
+ * metadata is returned or just the set that changed since the
+ * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
+ * #METADATA_ALL}.
+ *
+ * @param apply_filter if true only metadata that matches the
+ * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
+ * #BYPASS_METADATA_FILTER}.
+ *
+ * @return The metadata, possibly empty. null if an error occured.
+ // FIXME: unhide.
+ * {@hide}
+ */
+ public Metadata getMetadata(final boolean update_only,
+ final boolean apply_filter) {
+ Parcel reply = Parcel.obtain();
+ Metadata data = new Metadata();
+
+ if (!native_getMetadata(update_only, apply_filter, reply)) {
+ reply.recycle();
+ return null;
+ }
+
+ // Metadata takes over the parcel, don't recycle it unless
+ // there is an error.
+ if (!data.parse(reply)) {
+ reply.recycle();
+ return null;
+ }
+ return data;
+ }
+
+ /**
+ * Set a filter for the metadata update notification and update
+ * retrieval. The caller provides 2 set of metadata keys, allowed
+ * and blocked. The blocked set always takes precedence over the
+ * allowed one.
+ * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
+ * shorthands to allow/block all or no metadata.
+ *
+ * By default, there is no filter set.
+ *
+ * @param allow Is the set of metadata the client is interested
+ * in receiving new notifications for.
+ * @param block Is the set of metadata the client is not interested
+ * in receiving new notifications for.
+ * @return The call status code.
+ *
+ // FIXME: unhide.
+ * {@hide}
+ */
+ public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
+ // Do our serialization manually instead of calling
+ // Parcel.writeArray since the sets are made of the same type
+ // we avoid paying the price of calling writeValue (used by
+ // writeArray) which burns an extra int per element to encode
+ // the type.
+ Parcel request = newRequest();
+
+ // The parcel starts already with an interface token. There
+ // are 2 filters. Each one starts with a 4bytes number to
+ // store the len followed by a number of int (4 bytes as well)
+ // representing the metadata type.
+ int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
+
+ if (request.dataCapacity() < capacity) {
+ request.setDataCapacity(capacity);
+ }
+
+ request.writeInt(allow.size());
+ for(Integer t: allow) {
+ request.writeInt(t);
+ }
+ request.writeInt(block.size());
+ for(Integer t: block) {
+ request.writeInt(t);
+ }
+ return native_setMetadataFilter(request);
+ }
+
+ /**
* Releases resources associated with this MediaPlayer object.
* It is considered good practice to call this method when you're
* done using the MediaPlayer.
@@ -915,8 +1074,46 @@
*/
public native Bitmap getFrameAt(int msec) throws IllegalStateException;
+ /**
+ * @param request Parcel destinated to the media player. The
+ * Interface token must be set to the IMediaPlayer
+ * one to be routed correctly through the system.
+ * @param reply[out] Parcel that will contain the reply.
+ * @return The status code.
+ */
+ private native final int native_invoke(Parcel request, Parcel reply);
+
+
+ /**
+ * @param update_only If true fetch only the set of metadata that have
+ * changed since the last invocation of getMetadata.
+ * The set is built using the unfiltered
+ * notifications the native player sent to the
+ * MediaPlayerService during that period of
+ * time. If false, all the metadatas are considered.
+ * @param apply_filter If true, once the metadata set has been built based on
+ * the value update_only, the current filter is applied.
+ * @param reply[out] On return contains the serialized
+ * metadata. Valid only if the call was successful.
+ * @return The status code.
+ */
+ private native final boolean native_getMetadata(boolean update_only,
+ boolean apply_filter,
+ Parcel reply);
+
+ /**
+ * @param request Parcel with the 2 serialized lists of allowed
+ * metadata types followed by the one to be
+ * dropped. Each list starts with an integer
+ * indicating the number of metadata type elements.
+ * @return The status code.
+ */
+ private native final int native_setMetadataFilter(Parcel request);
+
+ private static native final void native_init();
private native final void native_setup(Object mediaplayer_this);
private native final void native_finalize();
+
@Override
protected void finalize() { native_finalize(); }
@@ -1254,6 +1451,11 @@
*/
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
+ /** A new set of metadata is available.
+ * @see android.media.MediaPlayer.OnInfoListener
+ */
+ public static final int MEDIA_INFO_METADATA_UPDATE = 802;
+
/**
* Interface definition of a callback to be invoked to communicate some
* info and/or warning about the media or its playback.
@@ -1270,6 +1472,7 @@
* <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
* <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
* <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
+ * <li>{@link #MEDIA_INFO_METADATA_UPDATE}
* </ul>
* @param extra an extra code, specific to the info. Typically
* implementation dependant.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index be4b489..46ede7f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -57,6 +57,7 @@
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaRecorder";
@@ -655,6 +656,8 @@
*/
public native void release();
+ private static native final void native_init();
+
private native final void native_setup(Object mediarecorder_this) throws IllegalStateException;
private native final void native_finalize();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8db874a..3d5aae3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -99,6 +99,7 @@
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaScanner";
@@ -307,10 +308,14 @@
private boolean mDefaultRingtoneSet;
/** Whether the scanner has set a default sound for the notification ringtone. */
private boolean mDefaultNotificationSet;
+ /** Whether the scanner has set a default sound for the alarm ringtone. */
+ private boolean mDefaultAlarmSet;
/** The filename for the default sound for the ringer ringtone. */
private String mDefaultRingtoneFilename;
/** The filename for the default sound for the notification ringtone. */
private String mDefaultNotificationFilename;
+ /** The filename for the default sound for the alarm ringtone. */
+ private String mDefaultAlarmAlertFilename;
/**
* The prefix for system properties that define the default sound for
* ringtones. Concatenate the name of the setting from Settings
@@ -369,6 +374,8 @@
+ Settings.System.RINGTONE);
mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.NOTIFICATION_SOUND);
+ mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ + Settings.System.ALARM_ALERT);
}
private MyMediaScannerClient mClient = new MyMediaScannerClient();
@@ -389,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) {
@@ -472,6 +480,7 @@
mDuration = 0;
mPath = path;
mLastModified = lastModified;
+ mWriter = null;
return entry;
}
@@ -586,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();
}
}
@@ -709,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);
+ }
}
}
@@ -779,6 +795,12 @@
setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
}
+ } else if (alarms && !mDefaultAlarmSet) {
+ if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+ setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+ mDefaultAlarmSet = true;
+ }
}
return result;
@@ -1412,6 +1434,7 @@
public native byte[] extractAlbumArt(FileDescriptor fd);
+ private static native final void native_init();
private native final void native_setup();
private native final void native_finalize();
@Override
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
new file mode 100644
index 0000000..bd25da2
--- /dev/null
+++ b/media/java/android/media/Metadata.java
@@ -0,0 +1,418 @@
+/*
+ * 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.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.TimeZone;
+
+
+/**
+ Class to hold the media's metadata. Metadata are used
+ for human consumption and can be embedded in the media (e.g
+ shoutcast) or available from an external source. The source can be
+ local (e.g thumbnail stored in the DB) or remote (e.g caption
+ server).
+
+ Metadata is like a Bundle. It is sparse and each key can occur at
+ most once. The key is an integer and the value is the actual metadata.
+
+ The caller is expected to know the type of the metadata and call
+ the right get* method to fetch its value.
+
+ // FIXME: unhide.
+ {@hide}
+ */
+public class Metadata
+{
+ // The metadata are keyed using integers rather than more heavy
+ // weight strings. We considered using Bundle to ship the metadata
+ // between the native layer and the java layer but dropped that
+ // option since keeping in sync a native implementation of Bundle
+ // and the java one would be too burdensome. Besides Bundle uses
+ // String for its keys.
+ // The key range [0 8192) is reserved for the system.
+ //
+ // We manually serialize the data in Parcels. For large memory
+ // blob (bitmaps, raw pictures) we use MemoryFile which allow the
+ // client to make the data purge-able once it is done with it.
+ //
+
+ public static final int ANY = 0; // Never used for metadata returned, only for filtering.
+ // Keep in sync with kAny in MediaPlayerService.cpp
+
+ // TODO: Should we use numbers compatible with the metadata retriever?
+ public static final int TITLE = 1; // String
+ public static final int COMMENT = 2; // String
+ public static final int COPYRIGHT = 3; // String
+ public static final int ALBUM = 4; // String
+ public static final int ARTIST = 5; // String
+ public static final int AUTHOR = 6; // String
+ public static final int COMPOSER = 7; // String
+ public static final int GENRE = 8; // String
+ public static final int DATE = 9; // Date
+ public static final int DURATION = 10; // Integer(millisec)
+ public static final int CD_TRACK_NUM = 11; // Integer 1-based
+ public static final int CD_TRACK_MAX = 12; // Integer
+ public static final int RATING = 13; // String
+ public static final int ALBUM_ART = 14; // byte[]
+ public static final int VIDEO_FRAME = 15; // Bitmap
+ public static final int CAPTION = 16; // TimedText
+
+ public static final int BIT_RATE = 17; // Integer, Aggregate rate of
+ // all the streams in bps.
+
+ public static final int AUDIO_BIT_RATE = 18; // Integer, bps
+ public static final int VIDEO_BIT_RATE = 19; // Integer, bps
+ public static final int AUDIO_SAMPLE_RATE = 20; // Integer, Hz
+ public static final int VIDEO_FRAME_RATE = 21; // Integer, Hz
+
+ // See RFC2046 and RFC4281.
+ public static final int MIME_TYPE = 22; // String
+ public static final int AUDIO_CODEC = 23; // String
+ public static final int VIDEO_CODEC = 24; // String
+
+ public static final int VIDEO_HEIGHT = 25; // Integer
+ public static final int VIDEO_WIDTH = 26; // Integer
+ public static final int NUM_TRACKS = 27; // Integer
+ public static final int DRM_CRIPPLED = 28; // Boolean
+
+ // Playback capabilities.
+ public static final int PAUSE_AVAILABLE = 29; // Boolean
+ public static final int SEEK_BACKWARD_AVAILABLE = 30; // Boolean
+ public static final int SEEK_FORWARD_AVAILABLE = 31; // Boolean
+
+ private static final int LAST_SYSTEM = 31;
+ private static final int FIRST_CUSTOM = 8192;
+
+ // Shorthands to set the MediaPlayer's metadata filter.
+ public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
+ public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
+
+ public static final int STRING_VAL = 1;
+ public static final int INTEGER_VAL = 2;
+ public static final int BOOLEAN_VAL = 3;
+ public static final int LONG_VAL = 4;
+ public static final int DOUBLE_VAL = 5;
+ public static final int TIMED_TEXT_VAL = 6;
+ public static final int DATE_VAL = 7;
+ public static final int BYTE_ARRAY_VAL = 8;
+ // FIXME: misses a type for shared heap is missing (MemoryFile).
+ // FIXME: misses a type for bitmaps.
+ private static final int LAST_TYPE = 8;
+
+ private static final String TAG = "media.Metadata";
+ private static final int kInt32Size = 4;
+ private static final int kMetaHeaderSize = 2 * kInt32Size; // size + marker
+ private static final int kRecordHeaderSize = 3 * kInt32Size; // size + id + type
+
+ private static final int kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+
+ // After a successful parsing, set the parcel with the serialized metadata.
+ private Parcel mParcel;
+
+ // Map to associate a Metadata key (e.g TITLE) with the offset of
+ // the record's payload in the parcel.
+ // Used to look up if a key was present too.
+ // Key: Metadata ID
+ // Value: Offset of the metadata type field in the record.
+ private final HashMap<Integer, Integer> mKeyToPosMap =
+ new HashMap<Integer, Integer>();
+
+ /**
+ * Helper class to hold a triple (time, duration, text). Can be used to
+ * implement caption.
+ */
+ public class TimedText {
+ private Date mTime;
+ private int mDuration; // millisec
+ private String mText;
+
+ public TimedText(Date time, int duration, String text) {
+ mTime = time;
+ mDuration = duration;
+ mText = text;
+ }
+
+ public String toString() {
+ StringBuilder res = new StringBuilder(80);
+ res.append(mTime).append("-").append(mDuration)
+ .append(":").append(mText);
+ return res.toString();
+ }
+ }
+
+ public Metadata() { }
+
+ /**
+ * Go over all the records, collecting metadata keys and records'
+ * type field offset in the Parcel. These are stored in
+ * mKeyToPosMap for latter retrieval.
+ * Format of a metadata record:
+ <pre>
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | record size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata key | // TITLE
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata type | // STRING_VAL
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | .... metadata payload .... |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ </pre>
+ * @param parcel With the serialized records.
+ * @param bytesLeft How many bytes in the parcel should be processed.
+ * @return false if an error occurred during parsing.
+ */
+ private boolean scanAllRecords(Parcel parcel, int bytesLeft) {
+ int recCount = 0;
+ boolean error = false;
+
+ mKeyToPosMap.clear();
+ while (bytesLeft > kRecordHeaderSize) {
+ final int start = parcel.dataPosition();
+ // Check the size.
+ final int size = parcel.readInt();
+
+ if (size <= kRecordHeaderSize) { // at least 1 byte should be present.
+ Log.e(TAG, "Record is too short");
+ error = true;
+ break;
+ }
+
+ // Check the metadata key.
+ final int metadataId = parcel.readInt();
+ if (!checkMetadataId(metadataId)) {
+ error = true;
+ break;
+ }
+
+ // Store the record offset which points to the type
+ // field so we can later on read/unmarshall the record
+ // payload.
+ if (mKeyToPosMap.containsKey(metadataId)) {
+ Log.e(TAG, "Duplicate metadata ID found");
+ error = true;
+ break;
+ }
+
+ mKeyToPosMap.put(metadataId, parcel.dataPosition());
+
+ // Check the metadata type.
+ final int metadataType = parcel.readInt();
+ if (metadataType <= 0 || metadataType > LAST_TYPE) {
+ Log.e(TAG, "Invalid metadata type " + metadataType);
+ error = true;
+ break;
+ }
+
+ // Skip to the next one.
+ parcel.setDataPosition(start + size);
+ bytesLeft -= size;
+ ++recCount;
+ }
+
+ if (0 != bytesLeft || error) {
+ Log.e(TAG, "Ran out of data or error on record " + recCount);
+ mKeyToPosMap.clear();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Check a parcel containing metadata is well formed. The header
+ * is checked as well as the individual records format. However, the
+ * data inside the record is not checked because we do lazy access
+ * (we check/unmarshall only data the user asks for.)
+ *
+ * Format of a metadata parcel:
+ <pre>
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata total size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 'M' | 'E' | 'T' | 'A' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | .... metadata records .... |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ </pre>
+ *
+ * @param parcel With the serialized data. Metadata keeps a
+ * reference on it to access it later on. The caller
+ * should not modify the parcel after this call (and
+ * not call recycle on it.)
+ * @return false if an error occurred.
+ */
+ public boolean parse(Parcel parcel) {
+ if (parcel.dataAvail() < kMetaHeaderSize) {
+ Log.e(TAG, "Not enough data " + parcel.dataAvail());
+ return false;
+ }
+
+ final int pin = parcel.dataPosition(); // to roll back in case of errors.
+ final int size = parcel.readInt();
+
+ // The extra kInt32Size below is to account for the int32 'size' just read.
+ if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
+ Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
+ parcel.setDataPosition(pin);
+ return false;
+ }
+
+ // Checks if the 'M' 'E' 'T' 'A' marker is present.
+ final int kShouldBeMetaMarker = parcel.readInt();
+ if (kShouldBeMetaMarker != kMetaMarker ) {
+ Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
+ parcel.setDataPosition(pin);
+ return false;
+ }
+
+ // Scan the records to collect metadata ids and offsets.
+ if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
+ parcel.setDataPosition(pin);
+ return false;
+ }
+ mParcel = parcel;
+ return true;
+ }
+
+ /**
+ * @return The set of metadata ID found.
+ */
+ public Set<Integer> keySet() {
+ return mKeyToPosMap.keySet();
+ }
+
+ /**
+ * @return true if a value is present for the given key.
+ */
+ public boolean has(final int metadataId) {
+ if (!checkMetadataId(metadataId)) {
+ throw new IllegalArgumentException("Invalid key: " + metadataId);
+ }
+ return mKeyToPosMap.containsKey(metadataId);
+ }
+
+ // Accessors.
+ // Caller must make sure the key is present using the {@code has}
+ // method otherwise a RuntimeException will occur.
+
+ public String getString(final int key) {
+ checkType(key, STRING_VAL);
+ return mParcel.readString();
+ }
+
+ public int getInt(final int key) {
+ checkType(key, INTEGER_VAL);
+ return mParcel.readInt();
+ }
+
+ public boolean getBoolean(final int key) {
+ checkType(key, BOOLEAN_VAL);
+ return mParcel.readInt() == 1;
+ }
+
+ public long getLong(final int key) {
+ checkType(key, LONG_VAL);
+ return mParcel.readLong();
+ }
+
+ public double getDouble(final int key) {
+ checkType(key, DOUBLE_VAL);
+ return mParcel.readDouble();
+ }
+
+ public byte[] getByteArray(final int key) {
+ checkType(key, BYTE_ARRAY_VAL);
+ return mParcel.createByteArray();
+ }
+
+ public Date getDate(final int key) {
+ checkType(key, DATE_VAL);
+ final long timeSinceEpoch = mParcel.readLong();
+ final String timeZone = mParcel.readString();
+
+ if (timeZone.length() == 0) {
+ return new Date(timeSinceEpoch);
+ } else {
+ TimeZone tz = TimeZone.getTimeZone(timeZone);
+ Calendar cal = Calendar.getInstance(tz);
+
+ cal.setTimeInMillis(timeSinceEpoch);
+ return cal.getTime();
+ }
+ }
+
+ public TimedText getTimedText(final int key) {
+ checkType(key, TIMED_TEXT_VAL);
+ final Date startTime = new Date(mParcel.readLong()); // epoch
+ final int duration = mParcel.readInt(); // millisec
+
+ return new TimedText(startTime,
+ duration,
+ mParcel.readString());
+ }
+
+ // @return the last available system metadata id. Ids are
+ // 1-indexed.
+ public static int lastSytemId() { return LAST_SYSTEM; }
+
+ // @return the first available cutom metadata id.
+ public static int firstCustomId() { return FIRST_CUSTOM; }
+
+ // @return the last value of known type. Types are 1-indexed.
+ public static int lastType() { return LAST_TYPE; }
+
+ // Check val is either a system id or a custom one.
+ // @param val Metadata key to test.
+ // @return true if it is in a valid range.
+ private boolean checkMetadataId(final int val) {
+ if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
+ Log.e(TAG, "Invalid metadata ID " + val);
+ return false;
+ }
+ return true;
+ }
+
+ // Check the type of the data match what is expected.
+ private void checkType(final int key, final int expectedType) {
+ final int pos = mKeyToPosMap.get(key);
+
+ mParcel.setDataPosition(pos);
+
+ final int type = mParcel.readInt();
+ if (type != expectedType) {
+ throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
+ }
+ }
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 42edae6..8481410 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -122,8 +122,9 @@
* current ringtone, which will be used to show a checkmark next to the item
* for this {@link Uri}. If showing an item for "Default" (@see
* {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" item
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" item
* checked.
*
* @see #ACTION_RINGTONE_PICKER
@@ -134,8 +135,9 @@
/**
* Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
* ringtone to play when the user attempts to preview the "Default"
- * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" point to
+ * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" point to
* the current sound for the given default sound type. If you are showing a
* ringtone picker for some other type of sound, you are free to provide any
* {@link Uri} here.
@@ -163,8 +165,9 @@
* <p>
* It will be one of:
* <li> the picked ringtone,
- * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} if the default was chosen,
+ * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} if the default was chosen,
* <li> null if the "Silent" item was picked.
*
* @see #ACTION_RINGTONE_PICKER
@@ -602,21 +605,6 @@
Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
}
- // Ringtone doesn't exist, use the fallback ringtone.
- try {
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(
- com.android.internal.R.raw.fallbackring);
- if (afd != null) {
- Ringtone r = new Ringtone(context);
- r.open(afd);
- afd.close();
- return r;
- }
- } catch (Exception ex) {
- }
-
- // we should never get here
- Log.e(TAG, "unable to find a usable ringtone");
return null;
}
@@ -627,15 +615,16 @@
*
* @param context A context used for querying.
* @param type The type whose default sound should be returned. One of
- * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+ * {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+ * {@link #TYPE_ALARM}.
* @return A {@link Uri} pointing to the default sound for the sound type.
* @see #setActualDefaultRingtoneUri(Context, int, Uri)
*/
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
- final String uriString = Settings.System.getString(context.getContentResolver(), setting);
- return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context);
+ final String uriString = Settings.System.getString(context.getContentResolver(), setting);
+ return uriString != null ? Uri.parse(uriString) : null;
}
/**
@@ -643,14 +632,16 @@
*
* @param context A context used for querying.
* @param type The type whose default sound should be set. One of
- * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+ * {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+ * {@link #TYPE_ALARM}.
* @param ringtoneUri A {@link Uri} pointing to the default sound to set.
* @see #getActualDefaultRingtoneUri(Context, int)
*/
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
String setting = getSettingForType(type);
if (setting == null) return;
- Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString());
+ Settings.System.putString(context.getContentResolver(), setting,
+ ringtoneUri != null ? ringtoneUri.toString() : null);
}
private static String getSettingForType(int type) {
@@ -658,6 +649,8 @@
return Settings.System.RINGTONE;
} else if ((type & TYPE_NOTIFICATION) != 0) {
return Settings.System.NOTIFICATION_SOUND;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.ALARM_ALERT;
} else {
return null;
}
@@ -677,8 +670,9 @@
* Returns the type of a default {@link Uri}.
*
* @param defaultRingtoneUri The default {@link Uri}. For example,
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI}.
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI}.
* @return The type of the defaultRingtoneUri, or -1.
*/
public static int getDefaultType(Uri defaultRingtoneUri) {
@@ -688,6 +682,8 @@
return TYPE_RINGTONE;
} else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
return TYPE_NOTIFICATION;
+ } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_ALARM_ALERT_URI)) {
+ return TYPE_ALARM;
} else {
return -1;
}
@@ -707,6 +703,8 @@
return Settings.System.DEFAULT_RINGTONE_URI;
} else if ((type & TYPE_NOTIFICATION) != 0) {
return Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.DEFAULT_ALARM_ALERT_URI;
} else {
return null;
}
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index e5ee9a3..c60a1ac 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -724,9 +724,9 @@
public static final int TONE_CDMA_SIGNAL_OFF = 98;
/** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
- public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
+ public static final int MAX_VOLUME = 100;
/** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */
- public static final int MIN_VOLUME = AudioSystem.MIN_VOLUME;
+ public static final int MIN_VOLUME = 0;
/**
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 8ee0cbd..49a82e6 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -12,20 +12,20 @@
LOCAL_SHARED_LIBRARIES := \
libopencore_player \
- libopencore_author \
libomx_amrenc_sharedlibrary \
libandroid_runtime \
libnativehelper \
- libcutils \
libutils \
+ libbinder \
libmedia \
- libsgl \
+ libskia \
libui
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES += \
external/tremor/Tremor \
+ frameworks/base/core/jni \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE) \
$(call include-path-for, corecg graphics)
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index 51cb6c7..c4dd07e 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -169,13 +169,6 @@
int register_android_media_AmrInputStream(JNIEnv *env)
{
const char* const kClassPathName = "android/media/AmrInputStream";
- jclass clazz;
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- return -1;
- }
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 4624a18..49f8cdd 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -40,6 +40,7 @@
static fields_t fields;
static Mutex sLock;
+static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
static void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message)
{
@@ -269,6 +270,36 @@
android_media_MediaMetadataRetriever_release(env, thiz);
}
+// This function gets a field ID, which in turn causes class initialization.
+// It is called from a static block in MediaMetadataRetriever, which won't run until the
+// first time an instance of this class is used.
+static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
+{
+ jclass clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaMetadataRetriever");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaMetadataRetriever.mNativeContext");
+ return;
+ }
+
+ fields.bitmapClazz = env->FindClass("android/graphics/Bitmap");
+ if (fields.bitmapClazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/graphics/Bitmap");
+ return;
+ }
+
+ fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V");
+ if (fields.bitmapConstructor == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Bitmap constructor");
+ return;
+ }
+}
+
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
{
LOGV("native_setup");
@@ -292,36 +323,13 @@
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
+ {"native_init", "()V", (void *)android_media_MediaMetadataRetriever_native_init},
};
-// Register native mehtods with Android runtime environment
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaMetadataRetriever(JNIEnv *env)
{
- static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
- jclass clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find class: %s", kClassPathName);
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaMetadataRetriever.mNativeContext");
- return -1;
- }
-
- fields.bitmapClazz = env->FindClass("android/graphics/Bitmap");
- if (fields.bitmapClazz == NULL) {
- LOGE("Bitmap class is not found");
- return -1;
- }
-
- fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V");
- if (fields.bitmapConstructor == NULL) {
- LOGE("Bitmap constructor is not found");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods
- (env, kClassPathName, nativeMethods, NELEM(nativeMethods));
+ (env, kClassPathName, nativeMethods, NELEM(nativeMethods));
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6317fe2..df98de5 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -20,6 +20,7 @@
#include "utils/Log.h"
#include <media/mediaplayer.h>
+#include <media/MediaPlayerInterface.h>
#include <stdio.h>
#include <assert.h>
#include <limits.h>
@@ -30,6 +31,8 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "utils/Errors.h" // for status_t
+#include "android_util_Binder.h"
+#include <binder/Parcel.h>
// ----------------------------------------------------------------------------
@@ -98,10 +101,9 @@
// ----------------------------------------------------------------------------
-static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
+static Surface* get_surface(JNIEnv* env, jobject clazz)
{
- Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native);
- return sp<Surface>(p);
+ return (Surface*)env->GetIntField(clazz, fields.surface_native);
}
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
@@ -202,7 +204,7 @@
{
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
- const sp<Surface>& native_surface = get_surface(env, surface);
+ const sp<Surface> native_surface = get_surface(env, surface);
LOGV("prepare: surface=%p (id=%d)",
native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
@@ -242,7 +244,7 @@
}
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
- const sp<Surface>& native_surface = get_surface(env, surface);
+ const sp<Surface> native_surface = get_surface(env, surface);
LOGV("prepareAsync: surface=%p (id=%d)",
native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
@@ -442,6 +444,119 @@
return NULL;
}
+
+// Sends the request and reply parcels to the media player via the
+// binder interface.
+static jint
+android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
+ jobject java_request, jobject java_reply)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return UNKNOWN_ERROR;
+ }
+
+
+ Parcel *request = parcelForJavaObject(env, java_request);
+ Parcel *reply = parcelForJavaObject(env, java_reply);
+
+ // Don't use process_media_player_call which use the async loop to
+ // report errors, instead returns the status.
+ return media_player->invoke(*request, reply);
+}
+
+// Sends the new filter to the client.
+static jint
+android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return UNKNOWN_ERROR;
+ }
+
+ Parcel *filter = parcelForJavaObject(env, request);
+
+ if (filter == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
+ return UNKNOWN_ERROR;
+ }
+
+ return media_player->setMetadataFilter(*filter);
+}
+
+static jboolean
+android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
+ jboolean apply_filter, jobject reply)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ Parcel *metadata = parcelForJavaObject(env, reply);
+
+ if (metadata == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
+ return false;
+ }
+
+ metadata->freeData();
+ // On return metadata is positioned at the beginning of the
+ // metadata. Note however that the parcel actually starts with the
+ // return code so you should not rewind the parcel using
+ // setDataPosition(0).
+ return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
+}
+
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in MediaPlayer, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaPlayer_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaPlayer");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext");
+ return;
+ }
+
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative");
+ return;
+ }
+
+ fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
+ if (fields.surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface");
+ return;
+ }
+
+ jclass surface = env->FindClass("android/view/Surface");
+ if (surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
+ return;
+ }
+
+ fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
+ if (fields.surface_native == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
+ return;
+ }
+}
+
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -503,53 +618,19 @@
{"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
+ {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
+ {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
+ {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
+ {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaPlayer";
+// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaPlayer");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaPlayer");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaPlayer.mNativeContext");
- return -1;
- }
-
- fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
- if (fields.post_event == NULL) {
- LOGE("Can't find MediaPlayer.postEventFromNative");
- return -1;
- }
-
- fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
- if (fields.surface == NULL) {
- LOGE("Can't find MediaPlayer.mSurface");
- return -1;
- }
-
- jclass surface = env->FindClass("android/view/Surface");
- if (surface == NULL) {
- LOGE("Can't find android/view/Surface");
- return -1;
- }
-
- fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
- if (fields.surface_native == NULL) {
- LOGE("Can't find Surface fields");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 0273a5a..cad65b3 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -276,7 +276,7 @@
android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
{
LOGV("setVideoFrameRate(%d)", rate);
- if (rate <= 0 || rate > MEDIA_RECORDER_MAX_FRAME_RATE) {
+ if (rate <= 0) {
jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
return;
}
@@ -371,6 +371,53 @@
}
}
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in MediaRecorder, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaRecorder_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaRecorder");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaRecorder");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mNativeContext");
+ return;
+ }
+
+ fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
+ if (fields.surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mSurface");
+ return;
+ }
+
+ jclass surface = env->FindClass("android/view/Surface");
+ if (surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
+ return;
+ }
+
+ fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
+ if (fields.surface_native == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
+ return;
+ }
+
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "MediaRecorder.postEventFromNative");
+ return;
+ }
+}
+
+
static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -418,55 +465,19 @@
{"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
{"start", "()V", (void *)android_media_MediaRecorder_start},
{"stop", "()V", (void *)android_media_MediaRecorder_stop},
- {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
+ {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
{"release", "()V", (void *)android_media_MediaRecorder_release},
+ {"native_init", "()V", (void *)android_media_MediaRecorder_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaRecorder_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaRecorder";
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaRecorder(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaRecorder");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaRecorder");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaRecorder.mNativeContext");
- return -1;
- }
-
- fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
- if (fields.surface == NULL) {
- LOGE("Can't find MediaRecorder.mSurface");
- return -1;
- }
-
- jclass surface = env->FindClass("android/view/Surface");
- if (surface == NULL) {
- LOGE("Can't find android/view/Surface");
- return -1;
- }
-
- fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
- if (fields.surface_native == NULL) {
- LOGE("Can't find Surface fields");
- return -1;
- }
-
- fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
- if (fields.post_event == NULL) {
- LOGE("Can't find MediaRecorder.postEventFromNative");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaRecorder", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 8764a70..97de486 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -241,6 +241,27 @@
return array;
}
+// This function gets a field ID, which in turn causes class initialization.
+// It is called from a static block in MediaScanner, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaScanner_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaScanner");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
+ return;
+ }
+}
+
static void
android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
{
@@ -275,28 +296,17 @@
(void *)android_media_MediaScanner_processFile},
{"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
{"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
+ {"native_init", "()V", (void *)android_media_MediaScanner_native_init},
{"native_setup", "()V", (void *)android_media_MediaScanner_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaScanner";
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaScanner(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaScanner");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaScanner");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaScanner.mNativeContext");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaScanner", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index 0247cdb..f248557 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -128,13 +128,6 @@
int register_android_media_ResampleInputStream(JNIEnv *env)
{
const char* const kClassPathName = "android/media/ResampleInputStream";
- jclass clazz;
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- return -1;
- }
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 374ddeb..9ff2e24 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -9,6 +9,7 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libandroid_runtime \
libnativehelper \
libmedia
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 00a121b..b17e31b 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -524,13 +524,14 @@
// wrong audio audio buffer size (mAudioBufferSize)
unsigned long toggle = mToggle ^ 1;
void *userData = (void *)((unsigned long)this | toggle);
+ uint32_t channels = (numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO;
#ifdef USE_SHARED_MEM_BUFFER
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- numChannels, sample->getIMemory(), 0, callback, userData);
+ channels, sample->getIMemory(), 0, callback, userData);
#else
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- numChannels, frameCount, 0, callback, userData, bufferFrames);
+ channels, frameCount, 0, callback, userData, bufferFrames);
#endif
if (newTrack->initCheck() != NO_ERROR) {
LOGE("Error creating AudioTrack");
diff --git a/media/libdrm/mobile2/include/rights/RoManager.h b/media/libdrm/mobile2/include/rights/RoManager.h
index cf398b3..71e9eef 100644
--- a/media/libdrm/mobile2/include/rights/RoManager.h
+++ b/media/libdrm/mobile2/include/rights/RoManager.h
@@ -64,12 +64,6 @@
vector<Ro*> getAllRo();
/**
- * Get the private key of the device.
- * @return the private key.
- */
- const string& getDevicePrivateKey() const;
-
- /**
* Get ro which contained rights of specific content.
* @param contentID the specific id of content.
* @return NULL if not fount otherwise the related ro.
diff --git a/media/libdrm/mobile2/src/rights/RoManager.cpp b/media/libdrm/mobile2/src/rights/RoManager.cpp
index 848c2ba..a115d21 100644
--- a/media/libdrm/mobile2/src/rights/RoManager.cpp
+++ b/media/libdrm/mobile2/src/rights/RoManager.cpp
@@ -121,9 +121,3 @@
return true;
}
-/** see RoManager.h */
-const string& RoManager::getDevicePrivateKey() const
-{
- string pk;
- return pk;
-}
diff --git a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
index f076cda..fe13669 100644
--- a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
+++ b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
@@ -88,7 +88,7 @@
node = node->getLastChild();
} else {
if (node == scopeNode)
- node == NULL;
+ node = NULL;
else
node = node->getParentNode();
}
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 8020da2..9d442c3 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -2,31 +2,34 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- AudioTrack.cpp \
- IAudioFlinger.cpp \
- IAudioFlingerClient.cpp \
- IAudioTrack.cpp \
- IAudioRecord.cpp \
- AudioRecord.cpp \
- AudioSystem.cpp \
- mediaplayer.cpp \
- IMediaPlayerService.cpp \
- IMediaPlayerClient.cpp \
- IMediaPlayer.cpp \
- IMediaRecorder.cpp \
- mediarecorder.cpp \
- IMediaMetadataRetriever.cpp \
- mediametadataretriever.cpp \
- ToneGenerator.cpp \
- JetPlayer.cpp
+ AudioTrack.cpp \
+ IAudioFlinger.cpp \
+ IAudioFlingerClient.cpp \
+ IAudioTrack.cpp \
+ IAudioRecord.cpp \
+ AudioRecord.cpp \
+ AudioSystem.cpp \
+ mediaplayer.cpp \
+ IMediaPlayerService.cpp \
+ IMediaPlayerClient.cpp \
+ IMediaPlayer.cpp \
+ IMediaRecorder.cpp \
+ Metadata.cpp \
+ mediarecorder.cpp \
+ IMediaMetadataRetriever.cpp \
+ mediametadataretriever.cpp \
+ ToneGenerator.cpp \
+ JetPlayer.cpp \
+ IOMX.cpp \
+ IAudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
- libui libcutils libutils libsonivox
+ libui libcutils libutils libbinder libsonivox
LOCAL_MODULE:= libmedia
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
+LOCAL_LDLIBS += -ldl -lpthread
endif
ifneq ($(TARGET_SIMULATOR),true)
@@ -34,6 +37,7 @@
endif
LOCAL_C_INCLUDES := \
- $(call include-path-for, graphics corecg)
+ $(call include-path-for, graphics corecg) \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index e56efbb..5e35564 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -28,12 +28,13 @@
#include <media/AudioSystem.h>
#include <media/AudioRecord.h>
+#include <media/mediarecorder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/Timers.h>
#include <cutils/atomic.h>
@@ -45,7 +46,7 @@
// ---------------------------------------------------------------------------
AudioRecord::AudioRecord()
- : mStatus(NO_INIT)
+ : mStatus(NO_INIT), mInput(0)
{
}
@@ -53,15 +54,15 @@
int inputSource,
uint32_t sampleRate,
int format,
- int channelCount,
+ uint32_t channels,
int frameCount,
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
- : mStatus(NO_INIT)
+ : mStatus(NO_INIT), mInput(0)
{
- mStatus = set(inputSource, sampleRate, format, channelCount,
+ mStatus = set(inputSource, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames);
}
@@ -78,6 +79,7 @@
}
mAudioRecord.clear();
IPCThreadState::self()->flushCommands();
+ AudioSystem::releaseInput(mInput);
}
}
@@ -85,7 +87,7 @@
int inputSource,
uint32_t sampleRate,
int format,
- int channelCount,
+ uint32_t channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -94,7 +96,7 @@
bool threadCanCallJava)
{
- LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
+ LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
if (mAudioRecord != 0) {
return INVALID_OPERATION;
}
@@ -104,8 +106,8 @@
return NO_INIT;
}
- if (inputSource == DEFAULT_INPUT) {
- inputSource = MIC_INPUT;
+ if (inputSource == AUDIO_SOURCE_DEFAULT) {
+ inputSource = AUDIO_SOURCE_MIC;
}
if (sampleRate == 0) {
@@ -115,15 +117,21 @@
if (format == 0) {
format = AudioSystem::PCM_16_BIT;
}
- if (channelCount == 0) {
- channelCount = 1;
- }
-
// validate parameters
- if (format != AudioSystem::PCM_16_BIT) {
+ if (!AudioSystem::isValidFormat(format)) {
+ LOGE("Invalid format");
return BAD_VALUE;
}
- if (channelCount != 1 && channelCount != 2) {
+
+ if (!AudioSystem::isInputChannel(channels)) {
+ return BAD_VALUE;
+ }
+ int channelCount = AudioSystem::popCount(channels);
+
+ mInput = AudioSystem::getInput(inputSource,
+ sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
+ if (mInput == 0) {
+ LOGE("Could not get audio output for stream type %d", inputSource);
return BAD_VALUE;
}
@@ -132,14 +140,22 @@
if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
!= NO_ERROR) {
LOGE("AudioSystem could not query the input buffer size.");
- return NO_INIT;
+ return NO_INIT;
}
+
if (inputBuffSizeInBytes == 0) {
LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
sampleRate, channelCount, format);
return BAD_VALUE;
}
+
int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
+ if (AudioSystem::isLinearPCM(format)) {
+ frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t));
+ } else {
+ frameSizeInBytes = sizeof(int8_t);
+ }
+
// We use 2* size of input buffer for ping pong use of record buffer.
int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
@@ -157,11 +173,11 @@
// open record channel
status_t status;
- sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), inputSource,
+ sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
sampleRate, format,
channelCount,
frameCount,
- ((uint16_t)flags) << 16,
+ ((uint16_t)flags) << 16,
&status);
if (record == 0) {
LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -188,7 +204,7 @@
mFormat = format;
// Update buffer size in case it has been limited by AudioFlinger during track creation
mFrameCount = mCblk->frameCount;
- mChannelCount = channelCount;
+ mChannelCount = (uint8_t)channelCount;
mActive = 0;
mCbf = cbf;
mNotificationFrames = notificationFrames;
@@ -234,7 +250,11 @@
int AudioRecord::frameSize() const
{
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ } else {
+ return sizeof(uint8_t);
+ }
}
int AudioRecord::inputSource() const
@@ -262,15 +282,18 @@
}
if (android_atomic_or(1, &mActive) == 0) {
- mNewPosition = mCblk->user + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
- if (t != 0) {
- t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
- } else {
- setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ ret = AudioSystem::startInput(mInput);
+ if (ret == NO_ERROR) {
+ mNewPosition = mCblk->user + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
+ if (t != 0) {
+ t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ } else {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ ret = mAudioRecord->start();
}
- ret = mAudioRecord->start();
}
if (t != 0) {
@@ -301,6 +324,7 @@
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
+ AudioSystem::stopInput(mInput);
}
if (t != 0) {
@@ -421,7 +445,7 @@
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
cblk->waitTimeMs = 0;
-
+
if (framesReq > framesReady) {
framesReq = framesReady;
}
@@ -437,7 +461,7 @@
audioBuffer->channelCount= mChannelCount;
audioBuffer->format = mFormat;
audioBuffer->frameCount = framesReq;
- audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+ audioBuffer->size = framesReq*cblk->frameSize;
audioBuffer->raw = (int8_t*)cblk->buffer(u);
active = mActive;
return active ? status_t(NO_ERROR) : status_t(STOPPED);
@@ -468,7 +492,7 @@
do {
- audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+ audioBuffer.frameCount = userSize/frameSize();
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
@@ -519,8 +543,8 @@
do {
audioBuffer.frameCount = frames;
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
// stuck here not being able to handle timed events (position, markers).
status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
@@ -548,14 +572,14 @@
if (readSize > reqSize) readSize = reqSize;
audioBuffer.size = readSize;
- audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+ audioBuffer.frameCount = readSize/frameSize();
frames -= audioBuffer.frameCount;
releaseBuffer(&audioBuffer);
} while (frames);
-
+
// Manage overrun callback
if (mActive && (mCblk->framesAvailable_l() == 0)) {
LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a21a7a4..98b55e9 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -18,10 +18,20 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <media/AudioSystem.h>
+#include <media/IAudioPolicyService.h>
#include <math.h>
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
namespace android {
// client singleton for AudioFlinger binder interface
@@ -30,10 +40,9 @@
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
// Cached values
-int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
-int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
-uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
-bool AudioSystem::gA2dpEnabled;
+DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
+
// Cached values for recording queries
uint32_t AudioSystem::gPrevInSamplingRate = 16000;
int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
@@ -65,44 +74,12 @@
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
gAudioFlinger->registerClient(gAudioFlingerClient);
- // Cache frequently accessed parameters
- for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
- gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
- gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
- gOutLatency[output] = gAudioFlinger->latency(output);
- }
- gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
}
LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
+
return gAudioFlinger;
}
-// routing helper functions
-status_t AudioSystem::speakerphone(bool state) {
- uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
- return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isSpeakerphoneOn(bool* state) {
- uint32_t routes = 0;
- status_t s = getRouting(MODE_IN_CALL, &routes);
- *state = !!(routes & ROUTE_SPEAKER);
- return s;
-}
-
-status_t AudioSystem::bluetoothSco(bool state) {
- uint32_t mask = ROUTE_BLUETOOTH_SCO;
- uint32_t routes = state ? mask : ROUTE_EARPIECE;
- return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isBluetoothScoOn(bool* state) {
- uint32_t routes = 0;
- status_t s = getRouting(MODE_IN_CALL, &routes);
- *state = !!(routes & ROUTE_BLUETOOTH_SCO);
- return s;
-}
-
status_t AudioSystem::muteMicrophone(bool state) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
@@ -148,12 +125,12 @@
return NO_ERROR;
}
-status_t AudioSystem::setStreamVolume(int stream, float value)
+status_t AudioSystem::setStreamVolume(int stream, float value, int output)
{
if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- af->setStreamVolume(stream, value);
+ af->setStreamVolume(stream, value, output);
return NO_ERROR;
}
@@ -166,12 +143,12 @@
return NO_ERROR;
}
-status_t AudioSystem::getStreamVolume(int stream, float* volume)
+status_t AudioSystem::getStreamVolume(int stream, float* volume, int output)
{
if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- *volume = af->streamVolume(stream);
+ *volume = af->streamVolume(stream, output);
return NO_ERROR;
}
@@ -192,29 +169,6 @@
return af->setMode(mode);
}
-status_t AudioSystem::getMode(int* mode)
-{
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- *mode = af->getMode();
- return NO_ERROR;
-}
-
-status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- return af->setRouting(mode, routes, mask);
-}
-
-status_t AudioSystem::getRouting(int mode, uint32_t* routes)
-{
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- uint32_t r = af->getRouting(mode);
- *routes = r;
- return NO_ERROR;
-}
status_t AudioSystem::isMusicActive(bool* state) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -223,12 +177,20 @@
return NO_ERROR;
}
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-status_t AudioSystem::setParameter(const char* key, const char* value) {
+
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- return af->setParameter(key, value);
+ return af->setParameters(ioHandle, keyValuePairs);
+}
+
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ String8 result = String8("");
+ if (af == 0) return result;
+
+ result = af->getParameters(ioHandle, keys);
+ return result;
}
// convert volume steps to natural log scale
@@ -257,55 +219,108 @@
status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
{
- int output = getOutput(streamType);
-
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
- // gOutSamplingRate[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
-
- *samplingRate = gOutSamplingRate[output];
-
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
+
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ LOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *samplingRate = af->sampleRate(output);
+ } else {
+ LOGV("getOutputSamplingRate() reading from output desc");
+ *samplingRate = outputDesc->samplingRate;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);
+
return NO_ERROR;
}
status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
{
- int output = getOutput(streamType);
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
- // gOutFrameCount[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
- *frameCount = gOutFrameCount[output];
-
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *frameCount = af->frameCount(output);
+ } else {
+ *frameCount = outputDesc->frameCount;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount);
+
return NO_ERROR;
}
status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
{
- int output = getOutput(streamType);
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
- // gOutLatency[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
- *latency = gOutLatency[output];
-
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *latency = af->latency(output);
+ } else {
+ *latency = outputDesc->latency;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
+
return NO_ERROR;
}
-status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
size_t* buffSize)
{
// Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
- if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
+ if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
|| (channelCount != gPrevInChannelCount)) {
// save the request params
gPrevInSamplingRate = sampleRate;
- gPrevInFormat = format;
+ gPrevInFormat = format;
gPrevInChannelCount = channelCount;
gInBuffSize = 0;
@@ -314,24 +329,18 @@
return PERMISSION_DENIED;
}
gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
- }
+ }
*buffSize = gInBuffSize;
-
+
return NO_ERROR;
}
// ---------------------------------------------------------------------------
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(AudioSystem::gLock);
- AudioSystem::gAudioFlinger.clear();
- for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
- gOutFrameCount[output] = 0;
- gOutSamplingRate[output] = 0;
- gOutLatency[output] = 0;
- }
- AudioSystem::gInBuffSize = 0;
+ AudioSystem::gAudioFlinger.clear();
if (gAudioErrorCallback) {
gAudioErrorCallback(DEAD_OBJECT);
@@ -339,33 +348,82 @@
LOGW("AudioFlinger server died!");
}
-void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
- gA2dpEnabled = enabled;
- LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
+ LOGV("ioConfigChanged() event %d", event);
+ OutputDescriptor *desc;
+ uint32_t stream;
+
+ if (ioHandle == 0) return;
+
+ Mutex::Autolock _l(AudioSystem::gLock);
+
+ switch (event) {
+ case STREAM_CONFIG_CHANGED:
+ if (param2 == 0) break;
+ stream = *(uint32_t *)param2;
+ LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
+ if (gStreamOutputMap.indexOfKey(stream) >= 0) {
+ gStreamOutputMap.replaceValueFor(stream, ioHandle);
+ }
+ break;
+ case OUTPUT_OPENED: {
+ if (gOutputs.indexOfKey(ioHandle) >= 0) {
+ LOGV("ioConfigChanged() opening already existing output! %d", ioHandle);
+ break;
+ }
+ if (param2 == 0) break;
+ desc = (OutputDescriptor *)param2;
+
+ OutputDescriptor *outputDesc = new OutputDescriptor(*desc);
+ gOutputs.add(ioHandle, outputDesc);
+ LOGV("ioConfigChanged() new output samplingRate %d, format %d channels %d frameCount %d latency %d",
+ outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency);
+ } break;
+ case OUTPUT_CLOSED: {
+ if (gOutputs.indexOfKey(ioHandle) < 0) {
+ LOGW("ioConfigChanged() closing unknow output! %d", ioHandle);
+ break;
+ }
+ LOGV("ioConfigChanged() output %d closed", ioHandle);
+
+ gOutputs.removeItem(ioHandle);
+ for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) {
+ if (gStreamOutputMap.valueAt(i) == ioHandle) {
+ gStreamOutputMap.removeItemsAt(i);
+ }
+ }
+ } break;
+
+ case OUTPUT_CONFIG_CHANGED: {
+ int index = gOutputs.indexOfKey(ioHandle);
+ if (index < 0) {
+ LOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
+ break;
+ }
+ if (param2 == 0) break;
+ desc = (OutputDescriptor *)param2;
+
+ LOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d",
+ ioHandle, desc->samplingRate, desc->format,
+ desc->channels, desc->frameCount, desc->latency);
+ OutputDescriptor *outputDesc = gOutputs.valueAt(index);
+ delete outputDesc;
+ outputDesc = new OutputDescriptor(*desc);
+ gOutputs.replaceValueFor(ioHandle, outputDesc);
+ } break;
+ case INPUT_OPENED:
+ case INPUT_CLOSED:
+ case INPUT_CONFIG_CHANGED:
+ break;
+
+ }
}
void AudioSystem::setErrorCallback(audio_error_callback cb) {
- Mutex::Autolock _l(AudioSystem::gLock);
+ Mutex::Autolock _l(gLock);
gAudioErrorCallback = cb;
}
-int AudioSystem::getOutput(int streamType)
-{
- // make sure that gA2dpEnabled is valid by calling get_audio_flinger() which in turn
- // will call gAudioFlinger->isA2dpEnabled()
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return NUM_AUDIO_OUTPUT_TYPES;
-
- if (streamType == DEFAULT) {
- streamType = MUSIC;
- }
- if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
- return AUDIO_OUTPUT_A2DP;
- } else {
- return AUDIO_OUTPUT_HARDWARE;
- }
-}
-
bool AudioSystem::routedToA2dpOutput(int streamType) {
switch(streamType) {
case MUSIC:
@@ -379,6 +437,451 @@
}
+// client singleton for AudioPolicyService binder interface
+sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
+sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient;
+
+
+// establish binder interface to AudioFlinger service
+const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service()
+{
+ gLock.lock();
+ if (gAudioPolicyService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_policy"));
+ if (binder != 0)
+ break;
+ LOGW("AudioPolicyService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (gAudioPolicyServiceClient == NULL) {
+ gAudioPolicyServiceClient = new AudioPolicyServiceClient();
+ }
+ binder->linkToDeath(gAudioPolicyServiceClient);
+ gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
+ gLock.unlock();
+ } else {
+ gLock.unlock();
+ }
+ return gAudioPolicyService;
+}
+
+status_t AudioSystem::setDeviceConnectionState(audio_devices device,
+ device_connection_state state,
+ const char *device_address)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ return aps->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioSystem::getDeviceConnectionState(audio_devices device,
+ const char *device_address)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return DEVICE_STATE_UNAVAILABLE;
+
+ return aps->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioSystem::setPhoneState(int state)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ return aps->setPhoneState(state);
+}
+
+status_t AudioSystem::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setRingerMode(mode, mask);
+}
+
+status_t AudioSystem::setForceUse(force_use usage, forced_config config)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setForceUse(usage, config);
+}
+
+AudioSystem::forced_config AudioSystem::getForceUse(force_use usage)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return FORCE_NONE;
+ return aps->getForceUse(usage);
+}
+
+
+audio_io_handle_t AudioSystem::getOutput(stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ output_flags flags)
+{
+ audio_io_handle_t output = 0;
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+ Mutex::Autolock _l(gLock);
+ output = AudioSystem::gStreamOutputMap.valueFor(stream);
+ LOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream);
+ }
+ if (output == 0) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return 0;
+ output = aps->getOutput(stream, samplingRate, format, channels, flags);
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+ Mutex::Autolock _l(gLock);
+ AudioSystem::gStreamOutputMap.add(stream, output);
+ }
+ }
+ return output;
+}
+
+status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->startOutput(output, stream);
+}
+
+status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->stopOutput(output, stream);
+}
+
+void AudioSystem::releaseOutput(audio_io_handle_t output)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->releaseOutput(output);
+}
+
+audio_io_handle_t AudioSystem::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ audio_in_acoustics acoustics)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return 0;
+ return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+
+status_t AudioSystem::startInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->startInput(input);
+}
+
+status_t AudioSystem::stopInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->stopInput(input);
+}
+
+void AudioSystem::releaseInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->releaseInput(input);
+}
+
+status_t AudioSystem::initStreamVolume(stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->initStreamVolume(stream, indexMin, indexMax);
+}
+
+status_t AudioSystem::setStreamVolumeIndex(stream_type stream, int index)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getStreamVolumeIndex(stream, index);
+}
+
+// ---------------------------------------------------------------------------
+
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ AudioSystem::gAudioPolicyService.clear();
+
+ LOGW("AudioPolicyService server died!");
+}
+
+// ---------------------------------------------------------------------------
+
+
+// use emulated popcount optimization
+// http://www.df.lth.se/~john_e/gems/gem002d.html
+uint32_t AudioSystem::popCount(uint32_t u)
+{
+ u = ((u&0x55555555) + ((u>>1)&0x55555555));
+ u = ((u&0x33333333) + ((u>>2)&0x33333333));
+ u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
+ u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
+ u = ( u&0x0000ffff) + (u>>16);
+ return u;
+}
+
+bool AudioSystem::isOutputDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ ((device & ~AudioSystem::DEVICE_OUT_ALL) == 0)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isInputDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ ((device & ~AudioSystem::DEVICE_IN_ALL) == 0)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isA2dpDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isBluetoothScoDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isLowVisibility(stream_type stream)
+{
+ if (stream == AudioSystem::SYSTEM || stream == AudioSystem::NOTIFICATION) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isInputChannel(uint32_t channel)
+{
+ if ((channel & ~AudioSystem::CHANNEL_IN_ALL) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isOutputChannel(uint32_t channel)
+{
+ if ((channel & ~AudioSystem::CHANNEL_OUT_ALL) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isValidFormat(uint32_t format)
+{
+ switch (format & MAIN_FORMAT_MASK) {
+ case PCM:
+ case MP3:
+ case AMR_NB:
+ case AMR_WB:
+ case AAC:
+ case HE_AAC_V1:
+ case HE_AAC_V2:
+ case VORBIS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AudioSystem::isLinearPCM(uint32_t format)
+{
+ switch (format) {
+ case PCM_16_BIT:
+ case PCM_8_BIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//------------------------- AudioParameter class implementation ---------------
+
+const char *AudioParameter::keyRouting = "routing";
+const char *AudioParameter::keySamplingRate = "sampling_rate";
+const char *AudioParameter::keyFormat = "format";
+const char *AudioParameter::keyChannels = "channels";
+const char *AudioParameter::keyFrameCount = "frame_count";
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+ char *str = new char[keyValuePairs.length()+1];
+ mKeyValuePairs = keyValuePairs;
+
+ strcpy(str, keyValuePairs.string());
+ char *pair = strtok(str, ";");
+ while (pair != NULL) {
+ if (strlen(pair) != 0) {
+ size_t eqIdx = strcspn(pair, "=");
+ String8 key = String8(pair, eqIdx);
+ String8 value;
+ if (eqIdx == strlen(pair)) {
+ value = String8("");
+ } else {
+ value = String8(pair + eqIdx + 1);
+ }
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ } else {
+ mParameters.replaceValueFor(key, value);
+ }
+ } else {
+ LOGV("AudioParameter() cstor empty key value pair");
+ }
+ pair = strtok(NULL, ";");
+ }
+
+ delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+ mParameters.clear();
+}
+
+String8 AudioParameter::toString()
+{
+ String8 str = String8("");
+
+ size_t size = mParameters.size();
+ for (size_t i = 0; i < size; i++) {
+ str += mParameters.keyAt(i);
+ str += "=";
+ str += mParameters.valueAt(i);
+ if (i < (size - 1)) str += ";";
+ }
+ return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ return NO_ERROR;
+ } else {
+ mParameters.replaceValueFor(key, value);
+ return ALREADY_EXISTS;
+ }
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+ char str[12];
+ if (snprintf(str, 12, "%d", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+ char str[23];
+ if (snprintf(str, 23, "%.10f", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ mParameters.removeItem(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ value = mParameters.valueFor(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value)
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ int val;
+ if (sscanf(str8.string(), "%d", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value)
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ float val;
+ if (sscanf(str8.string(), "%f", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index b2c067b..4b9d272 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -32,9 +32,9 @@
#include <media/AudioTrack.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/Timers.h>
#include <cutils/atomic.h>
@@ -54,7 +54,7 @@
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -62,7 +62,7 @@
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames, 0);
}
@@ -70,7 +70,7 @@
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
const sp<IMemory>& sharedBuffer,
uint32_t flags,
callback_t cbf,
@@ -78,7 +78,7 @@
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
0, flags, cbf, user, notificationFrames, sharedBuffer);
}
@@ -97,6 +97,7 @@
}
mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
+ AudioSystem::releaseOutput(getOutput());
}
}
@@ -104,7 +105,7 @@
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -150,63 +151,84 @@
if (format == 0) {
format = AudioSystem::PCM_16_BIT;
}
- if (channelCount == 0) {
- channelCount = 2;
+ if (channels == 0) {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
}
// validate parameters
- if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
- (format != AudioSystem::PCM_16_BIT)) {
+ if (!AudioSystem::isValidFormat(format)) {
LOGE("Invalid format");
return BAD_VALUE;
}
- if (channelCount != 1 && channelCount != 2) {
- LOGE("Invalid channel number");
+
+ // force direct flag if format is not linear PCM
+ if (!AudioSystem::isLinearPCM(format)) {
+ flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
+ }
+
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Invalid channel mask");
+ return BAD_VALUE;
+ }
+ uint32_t channelCount = AudioSystem::popCount(channels);
+
+ audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
+ sampleRate, format, channels, (AudioSystem::output_flags)flags);
+
+ if (output == 0) {
+ LOGE("Could not get audio output for stream type %d", streamType);
return BAD_VALUE;
}
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
-
- // When playing from shared buffer, playback will start even if last audioflinger
- // block is partly filled.
- if (sharedBuffer != 0 && minBufCount > 1) {
- minBufCount--;
- }
-
- int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
-
- if (sharedBuffer == 0) {
- if (frameCount == 0) {
- frameCount = minFrameCount;
- }
- if (notificationFrames == 0) {
- notificationFrames = frameCount/2;
- }
- // Make sure that application is notified with sufficient margin
- // before underrun
- if (notificationFrames > frameCount/2) {
- notificationFrames = frameCount/2;
+ if (!AudioSystem::isLinearPCM(format)) {
+ if (sharedBuffer != 0) {
+ frameCount = sharedBuffer->size();
}
} else {
- // Ensure that buffer alignment matches channelcount
- if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
- LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
- return BAD_VALUE;
- }
- frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
- }
+ // Ensure that buffer depth covers at least audio hardware latency
+ uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+ if (minBufCount < 2) minBufCount = 2;
- if (frameCount < minFrameCount) {
- LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
- return BAD_VALUE;
+ int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+ if (sharedBuffer == 0) {
+ if (frameCount == 0) {
+ frameCount = minFrameCount;
+ }
+ if (notificationFrames == 0) {
+ notificationFrames = frameCount/2;
+ }
+ // Make sure that application is notified with sufficient margin
+ // before underrun
+ if (notificationFrames > frameCount/2) {
+ notificationFrames = frameCount/2;
+ }
+ if (frameCount < minFrameCount) {
+ LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+ return BAD_VALUE;
+ }
+ } else {
+ // Ensure that buffer alignment matches channelcount
+ if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+ LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+ return BAD_VALUE;
+ }
+ frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+ }
}
// create the track
status_t status;
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
- streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+ streamType,
+ sampleRate,
+ format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ sharedBuffer,
+ output,
+ &status);
if (track == 0) {
LOGE("AudioFlinger could not create track, status: %d", status);
@@ -245,6 +267,7 @@
mVolume[RIGHT] = 1.0f;
mStreamType = streamType;
mFormat = format;
+ mChannels = channels;
mChannelCount = channelCount;
mSharedBuffer = sharedBuffer;
mMuted = false;
@@ -259,6 +282,7 @@
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
+ mFlags = flags;
return NO_ERROR;
}
@@ -297,7 +321,11 @@
int AudioTrack::frameSize() const
{
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ } else {
+ return sizeof(uint8_t);
+ }
}
sp<IMemory>& AudioTrack::sharedBuffer()
@@ -323,6 +351,7 @@
}
if (android_atomic_or(1, &mActive) == 0) {
+ AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
@@ -367,6 +396,7 @@
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
if (t != 0) {
@@ -382,12 +412,12 @@
void AudioTrack::flush()
{
LOGV("flush");
-
+
// clear playback marker and periodic update counter
mMarkerPosition = 0;
mMarkerReached = false;
mUpdatePeriod = 0;
-
+
if (!mActive) {
mAudioTrack->flush();
@@ -403,6 +433,7 @@
if (android_atomic_and(~1, &mActive) == 1) {
mActive = 0;
mAudioTrack->pause();
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
}
@@ -455,7 +486,6 @@
{
audio_track_cblk_t* cblk = mCblk;
-
Mutex::Autolock _l(cblk->lock);
if (loopCount == 0) {
@@ -476,7 +506,7 @@
LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
loopStart, loopEnd, mFrameCount);
return BAD_VALUE;
- }
+ }
cblk->loopStart = loopStart;
cblk->loopEnd = loopEnd;
@@ -555,7 +585,7 @@
mCblk->server = position;
mCblk->forceReady = 1;
-
+
return NO_ERROR;
}
@@ -571,7 +601,7 @@
status_t AudioTrack::reload()
{
if (!stopped()) return INVALID_OPERATION;
-
+
flush();
mCblk->stepUser(mFrameCount);
@@ -579,6 +609,12 @@
return NO_ERROR;
}
+audio_io_handle_t AudioTrack::getOutput()
+{
+ return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
+ mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
+}
+
// -------------------------------------------------------------------------
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -608,7 +644,7 @@
return WOULD_BLOCK;
timeout = 0;
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
- if (__builtin_expect(result!=NO_ERROR, false)) {
+ if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += waitTimeMs;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
// timing out when a loop has been set and we have already written upto loop end
@@ -616,7 +652,7 @@
if (cblk->user < cblk->loopEnd) {
LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
"user=%08x, server=%08x", this, cblk->user, cblk->server);
- //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
+ //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
mAudioTrack->start();
cblk->lock.lock();
@@ -624,7 +660,7 @@
}
cblk->waitTimeMs = 0;
}
-
+
if (--waitCount == 0) {
return TIMED_OUT;
}
@@ -636,7 +672,7 @@
}
cblk->waitTimeMs = 0;
-
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -653,12 +689,16 @@
"but didn't need to be locked. We recovered, but "
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
- audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
- audioBuffer->channelCount= mChannelCount;
- audioBuffer->format = AudioSystem::PCM_16_BIT;
- audioBuffer->frameCount = framesReq;
- audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
- audioBuffer->raw = (int8_t *)cblk->buffer(u);
+ audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+ audioBuffer->channelCount = mChannelCount;
+ audioBuffer->frameCount = framesReq;
+ audioBuffer->size = framesReq * cblk->frameSize;
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ audioBuffer->format = AudioSystem::PCM_16_BIT;
+ } else {
+ audioBuffer->format = mFormat;
+ }
+ audioBuffer->raw = (int8_t *)cblk->buffer(u);
active = mActive;
return active ? status_t(NO_ERROR) : status_t(STOPPED);
}
@@ -690,10 +730,8 @@
Buffer audioBuffer;
do {
- audioBuffer.frameCount = userSize/mChannelCount;
- if (mFormat == AudioSystem::PCM_16_BIT) {
- audioBuffer.frameCount >>= 1;
- }
+ audioBuffer.frameCount = userSize/frameSize();
+
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
status_t err = obtainBuffer(&audioBuffer, -1);
@@ -705,7 +743,8 @@
}
size_t toWrite;
- if (mFormat == AudioSystem::PCM_8_BIT) {
+
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
// Divide capacity by 2 to take expansion into account
toWrite = audioBuffer.size>>1;
// 8 to 16 bit conversion
@@ -714,7 +753,7 @@
while(count--) {
*dst++ = (int16_t)(*src++^0x80) << 8;
}
- }else {
+ } else {
toWrite = audioBuffer.size;
memcpy(audioBuffer.i8, src, toWrite);
src += toWrite;
@@ -742,13 +781,13 @@
if (mCblk->flowControlFlag == 0) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
if (mCblk->server == mCblk->frameCount) {
- mCbf(EVENT_BUFFER_END, mUserData, 0);
+ mCbf(EVENT_BUFFER_END, mUserData, 0);
}
mCblk->flowControlFlag = 1;
if (mSharedBuffer != 0) return false;
}
}
-
+
// Manage loop end callback
while (mLoopCount > mCblk->loopCount) {
int loopCount = -1;
@@ -767,7 +806,7 @@
}
// Manage new position callback
- if(mUpdatePeriod > 0) {
+ if (mUpdatePeriod > 0) {
while (mCblk->server >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
@@ -784,10 +823,10 @@
do {
audioBuffer.frameCount = frames;
-
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
- // stuck here not being able to handle timed events (position, markers, loops).
+
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // stuck here not being able to handle timed events (position, markers, loops).
status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
@@ -801,7 +840,7 @@
// Divide buffer size by 2 to take into account the expansion
// due to 8 to 16 bit conversion: the callback must fill only half
// of the destination buffer
- if (mFormat == AudioSystem::PCM_8_BIT) {
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
audioBuffer.size >>= 1;
}
@@ -820,7 +859,7 @@
}
if (writtenSize > reqSize) writtenSize = reqSize;
- if (mFormat == AudioSystem::PCM_8_BIT) {
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
// 8 to 16 bit conversion
const int8_t *src = audioBuffer.i8 + writtenSize-1;
int count = writtenSize;
@@ -832,7 +871,11 @@
}
audioBuffer.size = writtenSize;
- audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+ // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
+ // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of
+ // 16 bit.
+ audioBuffer.frameCount = writtenSize/mCblk->frameSize;
+
frames -= audioBuffer.frameCount;
releaseBuffer(&audioBuffer);
@@ -891,7 +934,7 @@
// =========================================================================
audio_track_cblk_t::audio_track_cblk_t()
- : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+ : lock(Mutex::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
{
}
@@ -949,7 +992,7 @@
// we switch to normal obtainBuffer() timeout period
if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
- }
+ }
// It is possible that we receive a flush()
// while the mixer is processing a block: in this case,
// stepServer() is called After the flush() has reset u & s and
@@ -981,7 +1024,7 @@
void* audio_track_cblk_t::buffer(uint32_t offset) const
{
- return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+ return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
}
uint32_t audio_track_cblk_t::framesAvailable()
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index eeaa54f..fc39a46 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -16,12 +16,13 @@
*/
#define LOG_TAG "IAudioFlinger"
+//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlinger.h>
@@ -44,17 +45,21 @@
STREAM_VOLUME,
STREAM_MUTE,
SET_MODE,
- GET_MODE,
- SET_ROUTING,
- GET_ROUTING,
SET_MIC_MUTE,
GET_MIC_MUTE,
IS_MUSIC_ACTIVE,
- SET_PARAMETER,
+ SET_PARAMETERS,
+ GET_PARAMETERS,
REGISTER_CLIENT,
GET_INPUTBUFFERSIZE,
- WAKE_UP,
- IS_A2DP_ENABLED
+ OPEN_OUTPUT,
+ OPEN_DUPLICATE_OUTPUT,
+ CLOSE_OUTPUT,
+ SUSPEND_OUTPUT,
+ RESTORE_OUTPUT,
+ OPEN_INPUT,
+ CLOSE_INPUT,
+ SET_STREAM_OUTPUT
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -74,6 +79,7 @@
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status)
{
Parcel data, reply;
@@ -86,6 +92,7 @@
data.writeInt32(frameCount);
data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder());
+ data.writeInt32(output);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) {
LOGE("createTrack error: %s", strerror(-lStatus));
@@ -99,7 +106,7 @@
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -110,7 +117,7 @@
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(pid);
- data.writeInt32(inputSource);
+ data.writeInt32(input);
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelCount);
@@ -203,12 +210,13 @@
return reply.readInt32();
}
- virtual status_t setStreamVolume(int stream, float value)
+ virtual status_t setStreamVolume(int stream, float value, int output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(stream);
data.writeFloat(value);
+ data.writeInt32(output);
remote()->transact(SET_STREAM_VOLUME, data, &reply);
return reply.readInt32();
}
@@ -223,11 +231,12 @@
return reply.readInt32();
}
- virtual float streamVolume(int stream) const
+ virtual float streamVolume(int stream, int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(stream);
+ data.writeInt32(output);
remote()->transact(STREAM_VOLUME, data, &reply);
return reply.readFloat();
}
@@ -241,26 +250,6 @@
return reply.readInt32();
}
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- data.writeInt32(routes);
- data.writeInt32(mask);
- remote()->transact(SET_ROUTING, data, &reply);
- return reply.readInt32();
- }
-
- virtual uint32_t getRouting(int mode) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(GET_ROUTING, data, &reply);
- return reply.readInt32();
- }
-
virtual status_t setMode(int mode)
{
Parcel data, reply;
@@ -270,14 +259,6 @@
return reply.readInt32();
}
- virtual int getMode() const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(GET_MODE, data, &reply);
- return reply.readInt32();
- }
-
virtual status_t setMicMute(bool state)
{
Parcel data, reply;
@@ -303,16 +284,26 @@
return reply.readInt32();
}
- virtual status_t setParameter(const char* key, const char* value)
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeCString(key);
- data.writeCString(value);
- remote()->transact(SET_PARAMETER, data, &reply);
+ data.writeInt32(ioHandle);
+ data.writeString8(keyValuePairs);
+ remote()->transact(SET_PARAMETERS, data, &reply);
return reply.readInt32();
}
-
+
+ virtual String8 getParameters(int ioHandle, const String8& keys)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(ioHandle);
+ data.writeString8(keys);
+ remote()->transact(GET_PARAMETERS, data, &reply);
+ return reply.readString8();
+ }
+
virtual void registerClient(const sp<IAudioFlingerClient>& client)
{
Parcel data, reply;
@@ -320,7 +311,7 @@
data.writeStrongBinder(client->asBinder());
remote()->transact(REGISTER_CLIENT, data, &reply);
}
-
+
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
Parcel data, reply;
@@ -331,21 +322,129 @@
remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
return reply.readInt32();
}
-
- virtual void wakeUp()
+
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags)
{
Parcel data, reply;
+ uint32_t devices = pDevices ? *pDevices : 0;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(WAKE_UP, data, &reply, IBinder::FLAG_ONEWAY);
- return;
+ data.writeInt32(devices);
+ data.writeInt32(samplingRate);
+ data.writeInt32(format);
+ data.writeInt32(channels);
+ data.writeInt32(latency);
+ data.writeInt32(flags);
+ remote()->transact(OPEN_OUTPUT, data, &reply);
+ int output = reply.readInt32();
+ LOGV("openOutput() returned output, %p", output);
+ devices = reply.readInt32();
+ if (pDevices) *pDevices = devices;
+ samplingRate = reply.readInt32();
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ format = reply.readInt32();
+ if (pFormat) *pFormat = format;
+ channels = reply.readInt32();
+ if (pChannels) *pChannels = channels;
+ latency = reply.readInt32();
+ if (pLatencyMs) *pLatencyMs = latency;
+ return output;
}
- virtual bool isA2dpEnabled() const
+ virtual int openDuplicateOutput(int output1, int output2)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(IS_A2DP_ENABLED, data, &reply);
- return (bool)reply.readInt32();
+ data.writeInt32(output1);
+ data.writeInt32(output2);
+ remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t closeOutput(int output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(CLOSE_OUTPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t suspendOutput(int output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(SUSPEND_OUTPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t restoreOutput(int output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(RESTORE_OUTPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+ {
+ Parcel data, reply;
+ uint32_t devices = pDevices ? *pDevices : 0;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(devices);
+ data.writeInt32(samplingRate);
+ data.writeInt32(format);
+ data.writeInt32(channels);
+ data.writeInt32(acoustics);
+ remote()->transact(OPEN_INPUT, data, &reply);
+ int input = reply.readInt32();
+ devices = reply.readInt32();
+ if (pDevices) *pDevices = devices;
+ samplingRate = reply.readInt32();
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ format = reply.readInt32();
+ if (pFormat) *pFormat = format;
+ channels = reply.readInt32();
+ if (pChannels) *pChannels = channels;
+ return input;
+ }
+
+ virtual status_t closeInput(int input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(CLOSE_INPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamOutput(uint32_t stream, int output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeInt32(output);
+ remote()->transact(SET_STREAM_OUTPUT, data, &reply);
+ return reply.readInt32();
}
};
@@ -353,12 +452,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -373,10 +466,11 @@
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+ int output = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
streamType, sampleRate, format,
- channelCount, bufferCount, flags, buffer, &status);
+ channelCount, bufferCount, flags, buffer, output, &status);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
return NO_ERROR;
@@ -384,14 +478,14 @@
case OPEN_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
pid_t pid = data.readInt32();
- int inputSource = data.readInt32();
+ int input = data.readInt32();
uint32_t sampleRate = data.readInt32();
int format = data.readInt32();
int channelCount = data.readInt32();
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
status_t status;
- sp<IAudioRecord> record = openRecord(pid, inputSource,
+ sp<IAudioRecord> record = openRecord(pid, input,
sampleRate, format, channelCount, bufferCount, flags, &status);
reply->writeInt32(status);
reply->writeStrongBinder(record->asBinder());
@@ -399,32 +493,27 @@
} break;
case SAMPLE_RATE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( sampleRate(output) );
+ reply->writeInt32( sampleRate(data.readInt32()) );
return NO_ERROR;
} break;
case CHANNEL_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( channelCount(output) );
+ reply->writeInt32( channelCount(data.readInt32()) );
return NO_ERROR;
} break;
case FORMAT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( format(output) );
+ reply->writeInt32( format(data.readInt32()) );
return NO_ERROR;
} break;
case FRAME_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( frameCount(output) );
+ reply->writeInt32( frameCount(data.readInt32()) );
return NO_ERROR;
} break;
case LATENCY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( latency(output) );
+ reply->writeInt32( latency(data.readInt32()) );
return NO_ERROR;
} break;
case SET_MASTER_VOLUME: {
@@ -450,7 +539,9 @@
case SET_STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
- reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+ float volume = data.readFloat();
+ int output = data.readInt32();
+ reply->writeInt32( setStreamVolume(stream, volume, output) );
return NO_ERROR;
} break;
case SET_STREAM_MUTE: {
@@ -462,7 +553,8 @@
case STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
- reply->writeFloat( streamVolume(stream) );
+ int output = data.readInt32();
+ reply->writeFloat( streamVolume(stream, output) );
return NO_ERROR;
} break;
case STREAM_MUTE: {
@@ -471,31 +563,12 @@
reply->writeInt32( streamMute(stream) );
return NO_ERROR;
} break;
- case SET_ROUTING: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- uint32_t routes = data.readInt32();
- uint32_t mask = data.readInt32();
- reply->writeInt32( setRouting(mode, routes, mask) );
- return NO_ERROR;
- } break;
- case GET_ROUTING: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( getRouting(mode) );
- return NO_ERROR;
- } break;
case SET_MODE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int mode = data.readInt32();
reply->writeInt32( setMode(mode) );
return NO_ERROR;
} break;
- case GET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( getMode() );
- return NO_ERROR;
- } break;
case SET_MIC_MUTE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int state = data.readInt32();
@@ -512,13 +585,21 @@
reply->writeInt32( isMusicActive() );
return NO_ERROR;
} break;
- case SET_PARAMETER: {
+ case SET_PARAMETERS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- const char *key = data.readCString();
- const char *value = data.readCString();
- reply->writeInt32( setParameter(key, value) );
+ int ioHandle = data.readInt32();
+ String8 keyValuePairs(data.readString8());
+ reply->writeInt32(setParameters(ioHandle, keyValuePairs));
return NO_ERROR;
- } break;
+ } break;
+ case GET_PARAMETERS: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int ioHandle = data.readInt32();
+ String8 keys(data.readString8());
+ reply->writeString8(getParameters(ioHandle, keys));
+ return NO_ERROR;
+ } break;
+
case REGISTER_CLIENT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
@@ -533,14 +614,81 @@
reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
return NO_ERROR;
} break;
- case WAKE_UP: {
+ case OPEN_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- wakeUp();
+ uint32_t devices = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ uint32_t latency = data.readInt32();
+ uint32_t flags = data.readInt32();
+ int output = openOutput(&devices,
+ &samplingRate,
+ &format,
+ &channels,
+ &latency,
+ flags);
+ LOGV("OPEN_OUTPUT output, %p", output);
+ reply->writeInt32(output);
+ reply->writeInt32(devices);
+ reply->writeInt32(samplingRate);
+ reply->writeInt32(format);
+ reply->writeInt32(channels);
+ reply->writeInt32(latency);
return NO_ERROR;
} break;
- case IS_A2DP_ENABLED: {
+ case OPEN_DUPLICATE_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( (int)isA2dpEnabled() );
+ int output1 = data.readInt32();
+ int output2 = data.readInt32();
+ reply->writeInt32(openDuplicateOutput(output1, output2));
+ return NO_ERROR;
+ } break;
+ case CLOSE_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(closeOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SUSPEND_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(suspendOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case RESTORE_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(restoreOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case OPEN_INPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t devices = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ uint32_t acoutics = data.readInt32();
+
+ int input = openInput(&devices,
+ &samplingRate,
+ &format,
+ &channels,
+ acoutics);
+ reply->writeInt32(input);
+ reply->writeInt32(devices);
+ reply->writeInt32(samplingRate);
+ reply->writeInt32(format);
+ reply->writeInt32(channels);
+ return NO_ERROR;
+ } break;
+ case CLOSE_INPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(closeInput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t stream = data.readInt32();
+ int output = data.readInt32();
+ reply->writeInt32(setStreamOutput(stream, output));
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 9d00aefb..3900de4 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -20,14 +20,15 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlingerClient.h>
+#include <media/AudioSystem.h>
namespace android {
enum {
- AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+ IO_CONFIG_CHANGED = IBinder::FIRST_CALL_TRANSACTION
};
class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
@@ -38,12 +39,25 @@
{
}
- void a2dpEnabledChanged(bool enabled)
+ void ioConfigChanged(int event, int ioHandle, void *param2)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
- data.writeInt32((int)enabled);
- remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+ data.writeInt32(event);
+ data.writeInt32(ioHandle);
+ if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+ uint32_t stream = *(uint32_t *)param2;
+ LOGV("ioConfigChanged stream %d", stream);
+ data.writeInt32(stream);
+ } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+ AudioSystem::OutputDescriptor *desc = (AudioSystem::OutputDescriptor *)param2;
+ data.writeInt32(desc->samplingRate);
+ data.writeInt32(desc->format);
+ data.writeInt32(desc->channels);
+ data.writeInt32(desc->frameCount);
+ data.writeInt32(desc->latency);
+ }
+ remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -51,20 +65,30 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
- case AUDIO_OUTPUT_CHANGED: {
+ case IO_CONFIG_CHANGED: {
CHECK_INTERFACE(IAudioFlingerClient, data, reply);
- bool enabled = (bool)data.readInt32();
- a2dpEnabledChanged(enabled);
+ int event = data.readInt32();
+ int ioHandle = data.readInt32();
+ void *param2 = 0;
+ AudioSystem::OutputDescriptor desc;
+ uint32_t stream;
+ if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+ stream = data.readInt32();
+ param2 = &stream;
+ LOGV("STREAM_CONFIG_CHANGED stream %d", stream);
+ } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+ desc.samplingRate = data.readInt32();
+ desc.format = data.readInt32();
+ desc.channels = data.readInt32();
+ desc.frameCount = data.readInt32();
+ desc.latency = data.readInt32();
+ param2 = &desc;
+ }
+ ioConfigChanged(event, ioHandle, param2);
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
new file mode 100644
index 0000000..18dd173
--- /dev/null
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -0,0 +1,413 @@
+/*
+**
+** Copyright 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_TAG "IAudioPolicyService"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <media/IAudioPolicyService.h>
+
+namespace android {
+
+enum {
+ SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION,
+ GET_DEVICE_CONNECTION_STATE,
+ SET_PHONE_STATE,
+ SET_RINGER_MODE,
+ SET_FORCE_USE,
+ GET_FORCE_USE,
+ GET_OUTPUT,
+ START_OUTPUT,
+ STOP_OUTPUT,
+ RELEASE_OUTPUT,
+ GET_INPUT,
+ START_INPUT,
+ STOP_INPUT,
+ RELEASE_INPUT,
+ INIT_STREAM_VOLUME,
+ SET_STREAM_VOLUME,
+ GET_STREAM_VOLUME
+};
+
+class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
+{
+public:
+ BpAudioPolicyService(const sp<IBinder>& impl)
+ : BpInterface<IAudioPolicyService>(impl)
+ {
+ }
+
+ virtual status_t setDeviceConnectionState(
+ AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(device));
+ data.writeInt32(static_cast <uint32_t>(state));
+ data.writeCString(device_address);
+ remote()->transact(SET_DEVICE_CONNECTION_STATE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(
+ AudioSystem::audio_devices device,
+ const char *device_address)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(device));
+ data.writeCString(device_address);
+ remote()->transact(GET_DEVICE_CONNECTION_STATE, data, &reply);
+ return static_cast <AudioSystem::device_connection_state>(reply.readInt32());
+ }
+
+ virtual status_t setPhoneState(int state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(state);
+ remote()->transact(SET_PHONE_STATE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ data.writeInt32(mask);
+ remote()->transact(SET_RINGER_MODE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(usage));
+ data.writeInt32(static_cast <uint32_t>(config));
+ remote()->transact(SET_FORCE_USE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(usage));
+ remote()->transact(GET_FORCE_USE, data, &reply);
+ return static_cast <AudioSystem::forced_config> (reply.readInt32());
+ }
+
+ virtual audio_io_handle_t getOutput(
+ AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(samplingRate);
+ data.writeInt32(static_cast <uint32_t>(format));
+ data.writeInt32(channels);
+ data.writeInt32(static_cast <uint32_t>(flags));
+ remote()->transact(GET_OUTPUT, data, &reply);
+ return static_cast <audio_io_handle_t> (reply.readInt32());
+ }
+
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ data.writeInt32(stream);
+ remote()->transact(START_OUTPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ data.writeInt32(stream);
+ remote()->transact(STOP_OUTPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual void releaseOutput(audio_io_handle_t output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(RELEASE_OUTPUT, data, &reply);
+ }
+
+ virtual audio_io_handle_t getInput(
+ int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(inputSource);
+ data.writeInt32(samplingRate);
+ data.writeInt32(static_cast <uint32_t>(format));
+ data.writeInt32(channels);
+ data.writeInt32(static_cast <uint32_t>(acoustics));
+ remote()->transact(GET_INPUT, data, &reply);
+ return static_cast <audio_io_handle_t> (reply.readInt32());
+ }
+
+ virtual status_t startInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(START_INPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t stopInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(STOP_INPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual void releaseInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(RELEASE_INPUT, data, &reply);
+ }
+
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(indexMin);
+ data.writeInt32(indexMax);
+ remote()->transact(INIT_STREAM_VOLUME, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(index);
+ remote()->transact(SET_STREAM_VOLUME, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ remote()->transact(GET_STREAM_VOLUME, data, &reply);
+ int lIndex = reply.readInt32();
+ if (index) *index = lIndex;
+ return static_cast <status_t> (reply.readInt32());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
+
+// ----------------------------------------------------------------------
+
+
+status_t BnAudioPolicyService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case SET_DEVICE_CONNECTION_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+ AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32());
+ const char *device_address = data.readCString();
+ reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));
+ return NO_ERROR;
+ } break;
+
+ case GET_DEVICE_CONNECTION_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+ const char *device_address = data.readCString();
+ reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address)));
+ return NO_ERROR;
+ } break;
+
+ case SET_PHONE_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ reply->writeInt32(static_cast <uint32_t>(setPhoneState(data.readInt32())));
+ return NO_ERROR;
+ } break;
+
+ case SET_RINGER_MODE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ uint32_t mode = data.readInt32();
+ uint32_t mask = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(setRingerMode(mode, mask)));
+ return NO_ERROR;
+ } break;
+
+ case SET_FORCE_USE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+ AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config)));
+ return NO_ERROR;
+ } break;
+
+ case GET_FORCE_USE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(getForceUse(usage)));
+ return NO_ERROR;
+ } break;
+
+ case GET_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32());
+
+ audio_io_handle_t output = getOutput(stream,
+ samplingRate,
+ format,
+ channels,
+ flags);
+ reply->writeInt32(static_cast <int>(output));
+ return NO_ERROR;
+ } break;
+
+ case START_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ uint32_t stream = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
+ return NO_ERROR;
+ } break;
+
+ case STOP_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ uint32_t stream = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
+ return NO_ERROR;
+ } break;
+
+ case RELEASE_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ releaseOutput(output);
+ return NO_ERROR;
+ } break;
+
+ case GET_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ int inputSource = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
+ audio_io_handle_t input = getInput(inputSource,
+ samplingRate,
+ format,
+ channels,
+ acoustics);
+ reply->writeInt32(static_cast <int>(input));
+ return NO_ERROR;
+ } break;
+
+ case START_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(startInput(input)));
+ return NO_ERROR;
+ } break;
+
+ case STOP_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(stopInput(input)));
+ return NO_ERROR;
+ } break;
+
+ case RELEASE_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ releaseInput(input);
+ return NO_ERROR;
+ } break;
+
+ case INIT_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int indexMin = data.readInt32();
+ int indexMax = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax)));
+ return NO_ERROR;
+ } break;
+
+ case SET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int index = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index)));
+ return NO_ERROR;
+ } break;
+
+ case GET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int index;
+ status_t status = getStreamVolumeIndex(stream, &index);
+ reply->writeInt32(index);
+ reply->writeInt32(static_cast <uint32_t>(status));
+ return NO_ERROR;
+ } break;
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 6e42dac..8fb5d3d 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioRecord.h>
@@ -66,12 +66,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioRecord::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index abc202d..75b861b 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioTrack.h>
@@ -91,12 +91,6 @@
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioTrack::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 85b5944..397a55b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -17,7 +17,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <SkBitmap.h>
#include <media/IMediaMetadataRetriever.h>
@@ -126,16 +126,10 @@
}
};
-IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaMetadataRetriever::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -215,4 +209,3 @@
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index f18765a..5d9db10 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayer.h>
#include <ui/ISurface.h>
@@ -39,7 +39,10 @@
RESET,
SET_AUDIO_STREAM_TYPE,
SET_LOOPING,
- SET_VOLUME
+ SET_VOLUME,
+ INVOKE,
+ SET_METADATA_FILTER,
+ GET_METADATA,
};
class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -170,18 +173,38 @@
remote()->transact(SET_VOLUME, data, &reply);
return reply.readInt32();
}
+
+ status_t invoke(const Parcel& request, Parcel *reply)
+ { // Avoid doing any extra copy. The interface descriptor should
+ // have been set by MediaPlayer.java.
+ return remote()->transact(INVOKE, request, reply);
+ }
+
+ status_t setMetadataFilter(const Parcel& request)
+ {
+ Parcel reply;
+ // Avoid doing any extra copy of the request. The interface
+ // descriptor should have been set by MediaPlayer.java.
+ remote()->transact(SET_METADATA_FILTER, request, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
+ {
+ Parcel request;
+ request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
+ request.writeInt32(update_only);
+ request.writeInt32(apply_filter);
+ remote()->transact(GET_METADATA, request, reply);
+ return reply->readInt32();
+ }
};
-IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -266,6 +289,24 @@
reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
return NO_ERROR;
} break;
+ case INVOKE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ invoke(data, reply);
+ return NO_ERROR;
+ } break;
+ case SET_METADATA_FILTER: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setMetadataFilter(data));
+ return NO_ERROR;
+ } break;
+ case GET_METADATA: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
+ reply->setDataPosition(0);
+ reply->writeInt32(retcode);
+ reply->setDataPosition(0);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
@@ -274,4 +315,3 @@
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index 65022cd..bf51829 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -16,8 +16,8 @@
*/
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayerClient.h>
@@ -46,16 +46,10 @@
}
};
-IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.IMediaPlayerClient");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -74,4 +68,3 @@
}
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 01cdb6c..8d2c360 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -17,11 +17,14 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+
+#include <utils/Errors.h> // for status_t
namespace android {
@@ -32,6 +35,7 @@
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
+ CREATE_OMX,
};
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -109,18 +113,19 @@
*pFormat = reply.readInt32();
return interface_cast<IMemory>(reply.readStrongBinder());
}
+
+ virtual sp<IOMX> createOMX() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ remote()->transact(CREATE_OMX, data, &reply);
+ return interface_cast<IOMX>(reply.readStrongBinder());
+ }
};
-IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -187,6 +192,12 @@
reply->writeStrongBinder(retriever->asBinder());
return NO_ERROR;
} break;
+ case CREATE_OMX: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ sp<IOMX> omx = createOMX();
+ reply->writeStrongBinder(omx->asBinder());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 84d08c4..df7d301 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaRecorder"
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ISurface.h>
#include <ui/ICamera.h>
#include <media/IMediaPlayerClient.h>
@@ -264,16 +264,10 @@
}
};
-IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.IMediaRecorder");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaRecorder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
new file mode 100644
index 0000000..10bebd0
--- /dev/null
+++ b/media/libmedia/IOMX.cpp
@@ -0,0 +1,733 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IOMX"
+#include <utils/Log.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IOMX.h>
+#include <ui/ISurface.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+enum {
+ CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ LIST_NODES,
+ ALLOCATE_NODE,
+ FREE_NODE,
+ SEND_COMMAND,
+ GET_PARAMETER,
+ SET_PARAMETER,
+ GET_CONFIG,
+ SET_CONFIG,
+ USE_BUFFER,
+ ALLOC_BUFFER,
+ ALLOC_BUFFER_WITH_BACKUP,
+ FREE_BUFFER,
+ OBSERVE_NODE,
+ FILL_BUFFER,
+ EMPTY_BUFFER,
+ GET_EXTENSION_INDEX,
+ CREATE_RENDERER,
+ OBSERVER_ON_MSG,
+ RENDERER_RENDER,
+};
+
+sp<IOMXRenderer> IOMX::createRenderer(
+ const sp<Surface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ return createRenderer(
+ surface->getISurface(),
+ componentName, colorFormat, encodedWidth, encodedHeight,
+ displayWidth, displayHeight);
+}
+
+class BpOMX : public BpInterface<IOMX> {
+public:
+ BpOMX(const sp<IBinder> &impl)
+ : BpInterface<IOMX>(impl) {
+ }
+
+ virtual status_t list_nodes(List<String8> *list) {
+ list->clear();
+
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ remote()->transact(LIST_NODES, data, &reply);
+
+ int32_t n = reply.readInt32();
+ for (int32_t i = 0; i < n; ++i) {
+ String8 s = reply.readString8();
+
+ list->push_back(s);
+ }
+
+ return OK;
+ }
+
+ virtual status_t allocate_node(const char *name, node_id *node) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeCString(name);
+ remote()->transact(ALLOCATE_NODE, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ *node = (void*)reply.readIntPtr();
+ } else {
+ *node = 0;
+ }
+
+ return err;
+ }
+
+ virtual status_t free_node(node_id node) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ remote()->transact(FREE_NODE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(cmd);
+ data.writeInt32(param);
+ remote()->transact(SEND_COMMAND, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t get_parameter(
+ 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_PARAMETER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ return err;
+ }
+
+ reply.read(params, size);
+
+ return OK;
+ }
+
+ virtual status_t set_parameter(
+ 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_PARAMETER, data, &reply);
+
+ 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());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeStrongBinder(params->asBinder());
+ remote()->transact(USE_BUFFER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeInt32(size);
+ remote()->transact(ALLOC_BUFFER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeStrongBinder(params->asBinder());
+ remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeIntPtr((intptr_t)buffer);
+ remote()->transact(FREE_BUFFER, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeStrongBinder(observer->asBinder());
+ remote()->transact(OBSERVE_NODE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual void fill_buffer(node_id node, buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
+ remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
+ data.writeInt32(range_offset);
+ data.writeInt32(range_length);
+ data.writeInt32(flags);
+ data.writeInt64(timestamp);
+ 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,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+
+ data.writeStrongBinder(surface->asBinder());
+ data.writeCString(componentName);
+ data.writeInt32(colorFormat);
+ data.writeInt32(encodedWidth);
+ data.writeInt32(encodedHeight);
+ data.writeInt32(displayWidth);
+ data.writeInt32(displayHeight);
+
+ remote()->transact(CREATE_RENDERER, data, &reply);
+
+ return interface_cast<IOMXRenderer>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnOMX::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case LIST_NODES:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ List<String8> list;
+ list_nodes(&list);
+
+ reply->writeInt32(list.size());
+ for (List<String8>::iterator it = list.begin();
+ it != list.end(); ++it) {
+ reply->writeString8(*it);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOCATE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node;
+ status_t err = allocate_node(data.readCString(), &node);
+ reply->writeInt32(err);
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)node);
+ }
+
+ return NO_ERROR;
+ }
+
+ case FREE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+
+ reply->writeInt32(free_node(node));
+
+ return NO_ERROR;
+ }
+
+ case SEND_COMMAND:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+
+ OMX_COMMANDTYPE cmd =
+ static_cast<OMX_COMMANDTYPE>(data.readInt32());
+
+ OMX_S32 param = data.readInt32();
+ reply->writeInt32(send_command(node, cmd, param));
+
+ return NO_ERROR;
+ }
+
+ case GET_PARAMETER:
+ {
+ 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_parameter(node, index, params, size);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->write(params, size);
+ }
+
+ free(params);
+ params = NULL;
+
+ return NO_ERROR;
+ }
+
+ case SET_PARAMETER:
+ {
+ 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_parameter(node, index, params, size));
+
+ 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 = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ sp<IMemory> params =
+ interface_cast<IMemory>(data.readStrongBinder());
+
+ buffer_id buffer;
+ status_t err = use_buffer(node, port_index, params, &buffer);
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOC_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ size_t size = data.readInt32();
+
+ buffer_id buffer;
+ status_t err = allocate_buffer(node, port_index, size, &buffer);
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOC_BUFFER_WITH_BACKUP:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ sp<IMemory> params =
+ interface_cast<IMemory>(data.readStrongBinder());
+
+ buffer_id buffer;
+ status_t err = allocate_buffer_with_backup(
+ node, port_index, params, &buffer);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case FREE_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ buffer_id buffer = (void*)data.readIntPtr();
+ reply->writeInt32(free_buffer(node, port_index, buffer));
+
+ return NO_ERROR;
+ }
+
+ case OBSERVE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ sp<IOMXObserver> observer =
+ interface_cast<IOMXObserver>(data.readStrongBinder());
+ reply->writeInt32(observe_node(node, observer));
+
+ return NO_ERROR;
+ }
+
+ case FILL_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ buffer_id buffer = (void*)data.readIntPtr();
+ fill_buffer(node, buffer);
+
+ return NO_ERROR;
+ }
+
+ case EMPTY_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ 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();
+ OMX_TICKS timestamp = data.readInt64();
+
+ empty_buffer(
+ node, buffer, range_offset, range_length,
+ flags, timestamp);
+
+ 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);
+
+ sp<ISurface> isurface =
+ interface_cast<ISurface>(data.readStrongBinder());
+
+ const char *componentName = data.readCString();
+
+ OMX_COLOR_FORMATTYPE colorFormat =
+ static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
+
+ size_t encodedWidth = (size_t)data.readInt32();
+ size_t encodedHeight = (size_t)data.readInt32();
+ size_t displayWidth = (size_t)data.readInt32();
+ size_t displayHeight = (size_t)data.readInt32();
+
+ sp<IOMXRenderer> renderer =
+ createRenderer(isurface, componentName, colorFormat,
+ encodedWidth, encodedHeight,
+ displayWidth, displayHeight);
+
+ reply->writeStrongBinder(renderer->asBinder());
+
+ return OK;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXObserver : public BpInterface<IOMXObserver> {
+public:
+ BpOMXObserver(const sp<IBinder> &impl)
+ : BpInterface<IOMXObserver>(impl) {
+ }
+
+ virtual void on_message(const omx_message &msg) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
+ data.write(&msg, sizeof(msg));
+
+ remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
+
+status_t BnOMXObserver::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case OBSERVER_ON_MSG:
+ {
+ CHECK_INTERFACE(IOMXObserver, data, reply);
+
+ omx_message msg;
+ data.read(&msg, sizeof(msg));
+
+ // XXX Could use readInplace maybe?
+ on_message(msg);
+
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXRenderer : public BpInterface<IOMXRenderer> {
+public:
+ BpOMXRenderer(const sp<IBinder> &impl)
+ : BpInterface<IOMXRenderer>(impl) {
+ }
+
+ virtual void render(IOMX::buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
+ 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.
+ remote()->transact(RENDERER_RENDER, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
+
+status_t BnOMXRenderer::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case RENDERER_RENDER:
+ {
+ CHECK_INTERFACE(IOMXRenderer, data, reply);
+
+ IOMX::buffer_id buffer = (void*)data.readIntPtr();
+
+ render(buffer);
+
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 586aacb..ee9e1d8 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -99,7 +99,7 @@
mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this
pLibConfig->sampleRate,
1, // format = PCM 16bits per sample,
- pLibConfig->numChannels,
+ (pLibConfig->numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
mTrackBufferSize,
0);
diff --git a/media/libmedia/Metadata.cpp b/media/libmedia/Metadata.cpp
new file mode 100644
index 0000000..35ec6b3
--- /dev/null
+++ b/media/libmedia/Metadata.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 "Metadata"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <media/Metadata.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// This file contains code to serialize Metadata triples (key, type,
+// value) into a parcel. The Parcel is destinated to be decoded by the
+// Metadata.java class.
+
+namespace {
+// All these constants below must be kept in sync with Metadata.java.
+enum MetadataId {
+ FIRST_SYSTEM_ID = 1,
+ LAST_SYSTEM_ID = 31,
+ FIRST_CUSTOM_ID = 8192
+};
+
+// Types
+enum Types {
+ STRING_VAL = 1,
+ INTEGER_VAL,
+ BOOLEAN_VAL,
+ LONG_VAL,
+ DOUBLE_VAL,
+ TIMED_TEXT_VAL,
+ DATE_VAL,
+ BYTE_ARRAY_VAL,
+};
+
+const size_t kRecordHeaderSize = 3 * sizeof(int32_t);
+const int32_t kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+
+} // anonymous namespace
+
+namespace android {
+namespace media {
+
+Metadata::Metadata(Parcel *p)
+ :mData(p),
+ mBegin(p->dataPosition()) { }
+
+Metadata::~Metadata() { }
+
+void Metadata::resetParcel()
+{
+ mData->setDataPosition(mBegin);
+}
+
+// Update the 4 bytes int at the beginning of the parcel which holds
+// the number of bytes written so far.
+void Metadata::updateLength()
+{
+ const size_t end = mData->dataPosition();
+
+ mData->setDataPosition(mBegin);
+ mData->writeInt32(end - mBegin);
+ mData->setDataPosition(end);
+}
+
+// Write the header. The java layer will look for the marker.
+bool Metadata::appendHeader()
+{
+ bool ok = true;
+
+ // Placeholder for the length of the metadata
+ ok = ok && mData->writeInt32(-1) == OK;
+ ok = ok && mData->writeInt32(kMetaMarker) == OK;
+ return ok;
+}
+
+bool Metadata::appendBool(int key, bool val)
+{
+ if (!checkKey(key)) {
+ return false;
+ }
+
+ const size_t begin = mData->dataPosition();
+ bool ok = true;
+
+ // 4 int32s: size, key, type, value.
+ ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+ ok = ok && mData->writeInt32(key) == OK;
+ ok = ok && mData->writeInt32(BOOLEAN_VAL) == OK;
+ ok = ok && mData->writeInt32(val ? 1 : 0) == OK;
+ if (!ok) {
+ mData->setDataPosition(begin);
+ }
+ return ok;
+}
+
+bool Metadata::appendInt32(int key, int32_t val)
+{
+ if (!checkKey(key)) {
+ return false;
+ }
+
+ const size_t begin = mData->dataPosition();
+ bool ok = true;
+
+ // 4 int32s: size, key, type, value.
+ ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+ ok = ok && mData->writeInt32(key) == OK;
+ ok = ok && mData->writeInt32(INTEGER_VAL) == OK;
+ ok = ok && mData->writeInt32(val) == OK;
+ if (!ok) {
+ mData->setDataPosition(begin);
+ }
+ return ok;
+}
+
+// Check the key (i.e metadata id) is valid if it is a system one.
+// Loop over all the exiting ones in the Parcel to check for duplicate
+// (not allowed).
+bool Metadata::checkKey(int key)
+{
+ if (key < FIRST_SYSTEM_ID ||
+ (LAST_SYSTEM_ID < key && key < FIRST_CUSTOM_ID)) {
+ LOGE("Bad key %d", key);
+ return false;
+ }
+ size_t curr = mData->dataPosition();
+ // Loop over the keys to check if it has been used already.
+ mData->setDataPosition(mBegin);
+
+ bool error = false;
+ size_t left = curr - mBegin;
+ while (left > 0) {
+ size_t pos = mData->dataPosition();
+ size_t size = mData->readInt32();
+ if (size < kRecordHeaderSize || size > left) {
+ error = true;
+ break;
+ }
+ if (mData->readInt32() == key) {
+ LOGE("Key exists already %d", key);
+ error = true;
+ break;
+ }
+ mData->setDataPosition(pos + size);
+ left -= size;
+ }
+ mData->setDataPosition(curr);
+ return !error;
+}
+
+} // namespace android::media
+} // namespace android
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 5435da7..799c349 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -914,7 +914,7 @@
}
}
} else {
- mState == TONE_IDLE;
+ mState = TONE_IDLE;
}
} else {
LOGV("Delayed start\n");
@@ -1001,7 +1001,7 @@
// Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack
- = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
+ = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this, 0);
if (mpAudioTrack == 0) {
LOGE("AudioTrack allocation failed");
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 09afc6c..d34a8ed 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -18,8 +18,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaMetadataRetriever"
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <media/mediametadataretriever.h>
#include <media/IMediaPlayerService.h>
#include <utils/Log.h>
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 24e3e6f..aeb43c5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -24,13 +24,13 @@
#include <unistd.h>
#include <fcntl.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <media/mediaplayer.h>
#include <media/AudioTrack.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
namespace android {
@@ -196,12 +196,47 @@
return err;
}
+status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
+{
+ Mutex::Autolock _l(mLock);
+ if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
+ {
+ LOGV("invoke %d", request.dataSize());
+ return mPlayer->invoke(request, reply);
+ }
+ LOGE("invoke failed: wrong state %X", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
+{
+ LOGD("setMetadataFilter");
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+ return mPlayer->setMetadataFilter(filter);
+}
+
+status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+ LOGD("getMetadata");
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+ return mPlayer->getMetadata(update_only, apply_filter, metadata);
+}
+
status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
- return mPlayer->setVideoSurface(surface->getISurface());
+ if (surface != NULL)
+ return mPlayer->setVideoSurface(surface->getISurface());
+ else
+ return mPlayer->setVideoSurface(NULL);
}
// must call with lock held
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 5093f0e..6b63931 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <ui/Surface.h>
#include <media/mediarecorder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f7f2490..84f858c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,28 +7,39 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- MediaRecorderClient.cpp \
- MediaPlayerService.cpp \
+ MediaRecorderClient.cpp \
+ MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
- VorbisPlayer.cpp \
+ StagefrightPlayer.cpp \
+ TestPlayerStub.cpp \
+ VorbisPlayer.cpp \
MidiFile.cpp
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
LOCAL_LDLIBS += -ldl -lpthread
endif
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libvorbisidec \
- libsonivox \
- libopencore_player \
- libopencore_author \
- libmedia \
- libandroid_runtime
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libbinder \
+ libvorbisidec \
+ libsonivox \
+ libopencore_player \
+ libopencore_author \
+ libmedia \
+ libandroid_runtime \
+ libstagefright \
+ libstagefright_omx
-LOCAL_C_INCLUDES := external/tremor/Tremor \
- $(call include-path-for, graphics corecg)
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := external/tremor/Tremor \
+ $(call include-path-for, graphics corecg) \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/frameworks/base/media/libstagefright/omx
LOCAL_MODULE:= libmediaplayerservice
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 31eecac..eeb4e49 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -27,18 +27,27 @@
#include <unistd.h>
#include <string.h>
+
#include <cutils/atomic.h>
+#include <cutils/properties.h> // for property_get
+
+#include <utils/misc.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <utils/Errors.h> // for status_t
+#include <utils/String8.h>
+#include <utils/Vector.h>
#include <cutils/properties.h>
#include <media/MediaPlayerInterface.h>
#include <media/mediarecorder.h>
#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/Metadata.h>
#include <media/AudioTrack.h>
#include "MediaRecorderClient.h"
@@ -48,6 +57,10 @@
#include "MidiFile.h"
#include "VorbisPlayer.h"
#include <media/PVPlayer.h>
+#include "TestPlayerStub.h"
+#include "StagefrightPlayer.h"
+
+#include <OMX.h>
/* desktop Linux needs a little help with gettid() */
#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -61,6 +74,111 @@
#undef __KERNEL__
#endif
+namespace {
+using android::media::Metadata;
+using android::status_t;
+using android::OK;
+using android::BAD_VALUE;
+using android::NOT_ENOUGH_DATA;
+using android::Parcel;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64; // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | number of entries (n) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 1 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 2 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type n |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+// filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+ Metadata::Filter *filter,
+ status_t *status)
+{
+ int32_t val;
+ if (p.readInt32(&val) != OK)
+ {
+ LOGE("Failed to read filter's length");
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ if( val > kMaxFilterSize || val < 0)
+ {
+ LOGE("Invalid filter len %d", val);
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ const size_t num = val;
+
+ filter->clear();
+ filter->setCapacity(num);
+
+ size_t size = num * sizeof(Metadata::Type);
+
+
+ if (p.dataAvail() < size)
+ {
+ LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ const Metadata::Type *data =
+ static_cast<const Metadata::Type*>(p.readInplace(size));
+
+ if (NULL == data)
+ {
+ LOGE("Filter had no data");
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ // TODO: The stl impl of vector would be more efficient here
+ // because it degenerates into a memcpy on pod types. Try to
+ // replace later or use stl::set.
+ for (size_t i = 0; i < num; ++i)
+ {
+ filter->add(*data);
+ ++data;
+ }
+ *status = OK;
+ return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const Metadata::Filter& filter, const int32_t val)
+{
+ // Deal with empty and ANY right away
+ if (filter.isEmpty()) return false;
+ if (filter[0] == Metadata::kAny) return true;
+
+ return filter.indexOf(val) >= 0;
+}
+
+} // anonymous namespace
+
namespace android {
@@ -105,7 +223,11 @@
sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
{
+#ifndef NO_OPENCORE
sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+#else
+ sp<MediaRecorderClient> recorder = NULL;
+#endif
LOGV("Create new media recorder client from pid %d", pid);
return recorder;
}
@@ -151,6 +273,10 @@
return c;
}
+sp<IOMX> MediaPlayerService::createOMX() {
+ return new OMX;
+}
+
status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
@@ -457,6 +583,7 @@
p = mPlayer;
}
mClient.clear();
+
mPlayer.clear();
// clear the notification to prevent callbacks to dead client
@@ -474,6 +601,16 @@
IPCThreadState::self()->flushCommands();
}
+static player_type getDefaultPlayerType() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.enable-player", value, NULL)
+ && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+ return STAGEFRIGHT_PLAYER;
+ }
+
+ return PV_PLAYER;
+}
+
static player_type getPlayerType(int fd, int64_t offset, int64_t length)
{
char buf[20];
@@ -504,12 +641,14 @@
EAS_Shutdown(easdata);
}
- // Fall through to PV
- return PV_PLAYER;
+ return getDefaultPlayerType();
}
static player_type getPlayerType(const char* url)
{
+ if (TestPlayerStub::canBeUsed(url)) {
+ return TEST_PLAYER;
+ }
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
@@ -523,8 +662,7 @@
}
}
- // Fall through to PV
- return PV_PLAYER;
+ return getDefaultPlayerType();
}
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
@@ -532,10 +670,12 @@
{
sp<MediaPlayerBase> p;
switch (playerType) {
+#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
+#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
@@ -544,6 +684,14 @@
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
+ case STAGEFRIGHT_PLAYER:
+ LOGV(" create StagefrightPlayer");
+ p = new StagefrightPlayer;
+ break;
+ case TEST_PLAYER:
+ LOGV("Create Test Player stub");
+ p = new TestPlayerStub();
+ break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
@@ -608,7 +756,11 @@
// now set data source
LOGV(" setDataSource");
mStatus = p->setDataSource(url);
- if (mStatus == NO_ERROR) mPlayer = p;
+ if (mStatus == NO_ERROR) {
+ mPlayer = p;
+ } else {
+ LOGE(" error: %d", mStatus);
+ }
return mStatus;
}
}
@@ -665,6 +817,73 @@
return p->setVideoSurface(surface);
}
+status_t MediaPlayerService::Client::invoke(const Parcel& request,
+ Parcel *reply)
+{
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == NULL) return UNKNOWN_ERROR;
+ return p->invoke(request, reply);
+}
+
+// This call doesn't need to access the native player.
+status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
+{
+ status_t status;
+ media::Metadata::Filter allow, drop;
+
+ if (unmarshallFilter(filter, &allow, &status) &&
+ unmarshallFilter(filter, &drop, &status)) {
+ Mutex::Autolock lock(mLock);
+
+ mMetadataAllow = allow;
+ mMetadataDrop = drop;
+ }
+ return status;
+}
+
+status_t MediaPlayerService::Client::getMetadata(
+ bool update_only, bool apply_filter, Parcel *reply)
+{
+ sp<MediaPlayerBase> player = getPlayer();
+ if (player == 0) return UNKNOWN_ERROR;
+
+ status_t status;
+ // Placeholder for the return code, updated by the caller.
+ reply->writeInt32(-1);
+
+ media::Metadata::Filter ids;
+
+ // We don't block notifications while we fetch the data. We clear
+ // mMetadataUpdated first so we don't lose notifications happening
+ // during the rest of this call.
+ {
+ Mutex::Autolock lock(mLock);
+ if (update_only) {
+ ids = mMetadataUpdated;
+ }
+ mMetadataUpdated.clear();
+ }
+
+ media::Metadata metadata(reply);
+
+ metadata.appendHeader();
+ status = player->getMetadata(ids, reply);
+
+ if (status != OK) {
+ metadata.resetParcel();
+ LOGE("getMetadata failed %d", status);
+ return status;
+ }
+
+ // FIXME: Implement filtering on the result. Not critical since
+ // filtering takes place on the update notifications already. This
+ // would be when all the metadata are fetch and a filter is set.
+
+ // Everything is fine, update the metadata length.
+ metadata.updateLength();
+ return OK;
+}
+
status_t MediaPlayerService::Client::prepareAsync()
{
LOGV("[%d] prepareAsync", mConnId);
@@ -784,13 +1003,51 @@
return NO_ERROR;
}
+
void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
{
Client* client = static_cast<Client*>(cookie);
+
+ if (MEDIA_INFO == msg &&
+ MEDIA_INFO_METADATA_UPDATE == ext1) {
+ const media::Metadata::Type metadata_type = ext2;
+
+ if(client->shouldDropMetadata(metadata_type)) {
+ return;
+ }
+
+ // Update the list of metadata that have changed. getMetadata
+ // also access mMetadataUpdated and clears it.
+ client->addNewMetadataUpdate(metadata_type);
+ }
LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
client->mClient->notify(msg, ext1, ext2);
}
+
+bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
+{
+ Mutex::Autolock lock(mLock);
+
+ if (findMetadata(mMetadataDrop, code)) {
+ return true;
+ }
+
+ if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+ Mutex::Autolock lock(mLock);
+ if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+ mMetadataUpdated.add(metadata_type);
+ }
+}
+
#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs
@@ -927,7 +1184,8 @@
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput()
-{
+ : mCallback(NULL),
+ mCallbackCookie(NULL) {
mTrack = 0;
mStreamType = AudioSystem::MUSIC;
mLeftVolume = 1.0;
@@ -997,8 +1255,13 @@
return mMsecsPerFrame;
}
-status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioOutput::open(
+ uint32_t sampleRate, int channelCount, int format, int bufferCount,
+ AudioCallback cb, void *cookie)
{
+ mCallback = cb;
+ mCallbackCookie = cookie;
+
// Check argument "bufferCount" against the mininum buffer count
if (bufferCount < mMinBufferCount) {
LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1019,7 +1282,27 @@
}
frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
- AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount);
+
+ AudioTrack *t;
+ if (mCallback != NULL) {
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+ frameCount,
+ 0 /* flags */,
+ CallbackWrapper,
+ this);
+ } else {
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+ frameCount);
+ }
+
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
LOGE("Unable to create audio track");
delete t;
@@ -1045,6 +1328,8 @@
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
{
+ LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+
//LOGV("write(%p, %u)", buffer, size);
if (mTrack) return mTrack->write(buffer, size);
return NO_INIT;
@@ -1085,6 +1370,20 @@
}
}
+// static
+void MediaPlayerService::AudioOutput::CallbackWrapper(
+ int event, void *cookie, void *info) {
+ if (event != AudioTrack::EVENT_MORE_DATA) {
+ return;
+ }
+
+ AudioOutput *me = (AudioOutput *)cookie;
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+
+ (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie);
+}
+
#undef LOG_TAG
#define LOG_TAG "AudioCache"
MediaPlayerService::AudioCache::AudioCache(const char* name) :
@@ -1105,8 +1404,14 @@
return mMsecsPerFrame;
}
-status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioCache::open(
+ uint32_t sampleRate, int channelCount, int format, int bufferCount,
+ AudioCallback cb, void *cookie)
{
+ if (cb != NULL) {
+ return UNKNOWN_ERROR; // TODO: implement this.
+ }
+
LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
if (mHeap->getHeapID() < 0) return NO_INIT;
mSampleRate = sampleRate;
@@ -1171,4 +1476,4 @@
p->mSignal.signal();
}
-}; // namespace android
+} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f138886..a4be414 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -18,17 +18,23 @@
#ifndef ANDROID_MEDIAPLAYERSERVICE_H
#define ANDROID_MEDIAPLAYERSERVICE_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
#include <ui/SurfaceComposerClient.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
namespace android {
class IMediaRecorder;
class IMediaMetadataRetriever;
+class IOMX;
#define CALLBACK_ANTAGONIZER 0
#if CALLBACK_ANTAGONIZER
@@ -69,7 +75,12 @@
virtual ssize_t frameSize() const;
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4);
+
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount,
+ int format, int bufferCount,
+ AudioCallback cb, void *cookie);
+
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
@@ -84,8 +95,12 @@
static int getMinBufferCount();
private:
static void setMinBufferCount();
+ static void CallbackWrapper(
+ int event, void *me, void *info);
AudioTrack* mTrack;
+ AudioCallback mCallback;
+ void * mCallbackCookie;
int mStreamType;
float mLeftVolume;
float mRightVolume;
@@ -113,7 +128,12 @@
virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1);
+
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount, int format,
+ int bufferCount = 1,
+ AudioCallback cb = NULL, void *cookie = NULL);
+
virtual void start() {}
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop() {}
@@ -140,7 +160,7 @@
sp<MemoryHeapBase> mHeap;
float mMsecsPerFrame;
uint16_t mChannelCount;
- uint16_t mFormat;
+ uint16_t mFormat;
ssize_t mFrameCount;
uint32_t mSampleRate;
uint32_t mSize;
@@ -160,11 +180,13 @@
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+ virtual sp<IOMX> createOMX();
virtual status_t dump(int fd, const Vector<String16>& args);
void removeClient(wp<Client> client);
+
private:
class Client : public BnMediaPlayer {
@@ -184,6 +206,11 @@
virtual status_t setAudioStreamType(int type);
virtual status_t setLooping(int loop);
virtual status_t setVolume(float leftVolume, float rightVolume);
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t setMetadataFilter(const Parcel& filter);
+ virtual status_t getMetadata(bool update_only,
+ bool apply_filter,
+ Parcel *reply);
sp<MediaPlayerBase> createPlayer(player_type playerType);
status_t setDataSource(const char *url);
@@ -206,6 +233,18 @@
sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
+
+
+ // @param type Of the metadata to be tested.
+ // @return true if the metadata should be dropped according to
+ // the filters.
+ bool shouldDropMetadata(media::Metadata::Type type) const;
+
+ // Add a new element to the set of metadata updated. Noop if
+ // the element exists already.
+ // @param type Of the metadata to be recorded.
+ void addNewMetadataUpdate(media::Metadata::Type type);
+
mutable Mutex mLock;
sp<MediaPlayerBase> mPlayer;
sp<MediaPlayerService> mService;
@@ -215,6 +254,17 @@
status_t mStatus;
bool mLoop;
int32_t mConnId;
+
+ // Metadata filters.
+ media::Metadata::Filter mMetadataAllow; // protected by mLock
+ media::Metadata::Filter mMetadataDrop; // protected by mLock
+
+ // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
+ // notification we try to update mMetadataUpdated which is a
+ // set: no duplicate.
+ // getMetadata clears this set.
+ media::Metadata::Filter mMetadataUpdated; // protected by mLock
+
#if CALLBACK_ANTAGONIZER
Antagonizer* mAntagonizer;
#endif
@@ -235,4 +285,3 @@
}; // namespace android
#endif // ANDROID_MEDIAPLAYERSERVICE_H
-
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 8bc410c..e54f20d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -25,10 +25,10 @@
#include <string.h>
#include <cutils/atomic.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
#include <media/PVMediaRecorder.h>
#include <utils/String16.h>
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a320bd5..ba8d9a8 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -26,10 +26,10 @@
#include <string.h>
#include <cutils/atomic.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/PVMetadataRetriever.h>
@@ -49,7 +49,11 @@
mThumbnail = NULL;
mAlbumArt = NULL;
+#ifndef NO_OPENCORE
mRetriever = new PVMetadataRetriever();
+#else
+ mRetriever = NULL;
+#endif
if (mRetriever == NULL) {
LOGE("failed to initialize the retriever");
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index ce29c98..88d50bf 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -18,9 +18,12 @@
#ifndef ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
#define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/KeyedVector.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <media/MediaMetadataRetrieverInterface.h>
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 302f1cf..25d4a1b 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -46,6 +46,9 @@
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return SONIVOX_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply) {
+ return INVALID_OPERATION;
+ }
private:
status_t createOutputTrack();
@@ -74,4 +77,3 @@
}; // namespace android
#endif // ANDROID_MIDIFILE_H
-
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
new file mode 100644
index 0000000..9a06d13
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -0,0 +1,208 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "StagefrightPlayer"
+#include <utils/Log.h>
+
+#include "StagefrightPlayer.h"
+#include <media/stagefright/MediaPlayerImpl.h>
+
+namespace android {
+
+StagefrightPlayer::StagefrightPlayer()
+ : mPlayer(NULL) {
+ LOGV("StagefrightPlayer");
+}
+
+StagefrightPlayer::~StagefrightPlayer() {
+ LOGV("~StagefrightPlayer");
+ reset();
+ LOGV("~StagefrightPlayer done.");
+}
+
+status_t StagefrightPlayer::initCheck() {
+ LOGV("initCheck");
+ return OK;
+}
+
+status_t StagefrightPlayer::setDataSource(const char *url) {
+ LOGV("setDataSource('%s')", url);
+
+ reset();
+ mPlayer = new MediaPlayerImpl(url);
+
+ status_t err = mPlayer->initCheck();
+ if (err != OK) {
+ delete mPlayer;
+ mPlayer = NULL;
+ } else {
+ mPlayer->setAudioSink(mAudioSink);
+ }
+
+ return err;
+}
+
+status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+
+ reset();
+ mPlayer = new MediaPlayerImpl(fd, offset, length);
+
+ status_t err = mPlayer->initCheck();
+ if (err != OK) {
+ delete mPlayer;
+ mPlayer = NULL;
+ } else {
+ mPlayer->setAudioSink(mAudioSink);
+ }
+
+ return err;
+}
+
+status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
+ LOGV("setVideoSurface");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->setISurface(surface);
+
+ return OK;
+}
+
+status_t StagefrightPlayer::prepare() {
+ LOGV("prepare");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ sendEvent(
+ MEDIA_SET_VIDEO_SIZE,
+ mPlayer->getWidth(), mPlayer->getHeight());
+
+ return OK;
+}
+
+status_t StagefrightPlayer::prepareAsync() {
+ LOGV("prepareAsync");
+
+ status_t err = prepare();
+
+ if (err != OK) {
+ return err;
+ }
+
+ sendEvent(MEDIA_PREPARED);
+
+ return OK;
+}
+
+status_t StagefrightPlayer::start() {
+ LOGV("start");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->play();
+
+ return OK;
+}
+
+status_t StagefrightPlayer::stop() {
+ LOGV("stop");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ reset();
+
+ return OK;
+}
+
+status_t StagefrightPlayer::pause() {
+ LOGV("pause");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->pause();
+
+ return OK;
+}
+
+bool StagefrightPlayer::isPlaying() {
+ LOGV("isPlaying");
+ return mPlayer != NULL && mPlayer->isPlaying();
+}
+
+status_t StagefrightPlayer::seekTo(int msec) {
+ LOGV("seekTo");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ status_t err = mPlayer->seekTo((int64_t)msec * 1000);
+
+ sendEvent(MEDIA_SEEK_COMPLETE);
+
+ return err;
+}
+
+status_t StagefrightPlayer::getCurrentPosition(int *msec) {
+ LOGV("getCurrentPosition");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ *msec = mPlayer->getPosition() / 1000;
+ return OK;
+}
+
+status_t StagefrightPlayer::getDuration(int *msec) {
+ LOGV("getDuration");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ *msec = mPlayer->getDuration() / 1000;
+ return OK;
+}
+
+status_t StagefrightPlayer::reset() {
+ LOGV("reset");
+
+ delete mPlayer;
+ mPlayer = NULL;
+
+ return OK;
+}
+
+status_t StagefrightPlayer::setLooping(int loop) {
+ LOGV("setLooping");
+ return UNKNOWN_ERROR;
+}
+
+player_type StagefrightPlayer::playerType() {
+ LOGV("playerType");
+ return STAGEFRIGHT_PLAYER;
+}
+
+status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
+ return INVALID_OPERATION;
+}
+
+void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
+ MediaPlayerInterface::setAudioSink(audioSink);
+
+ if (mPlayer != NULL) {
+ mPlayer->setAudioSink(audioSink);
+ }
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
new file mode 100644
index 0000000..f214872
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -0,0 +1,60 @@
+/*
+**
+** Copyright 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 ANDROID_STAGEFRIGHTPLAYER_H
+#define ANDROID_STAGEFRIGHTPLAYER_H
+
+#include <media/MediaPlayerInterface.h>
+
+namespace android {
+
+class MediaPlayerImpl;
+
+class StagefrightPlayer : public MediaPlayerInterface {
+public:
+ StagefrightPlayer();
+ virtual ~StagefrightPlayer();
+
+ virtual status_t initCheck();
+ virtual status_t setDataSource(const char *url);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setVideoSurface(const sp<ISurface> &surface);
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int *msec);
+ virtual status_t getDuration(int *msec);
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType();
+ virtual status_t invoke(const Parcel &request, Parcel *reply);
+ virtual void setAudioSink(const sp<AudioSink> &audioSink);
+
+private:
+ MediaPlayerImpl *mPlayer;
+
+ StagefrightPlayer(const StagefrightPlayer &);
+ StagefrightPlayer &operator=(const StagefrightPlayer &);
+};
+
+} // namespace android
+
+#endif // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
new file mode 100644
index 0000000..8627708
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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 "TestPlayerStub"
+#include "utils/Log.h"
+
+#include "TestPlayerStub.h"
+
+#include <dlfcn.h> // for dlopen/dlclose
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/properties.h>
+#include <utils/Errors.h> // for status_t
+
+#include "media/MediaPlayerInterface.h"
+
+
+namespace {
+using android::status_t;
+using android::MediaPlayerBase;
+
+const char *kTestUrlScheme = "test:";
+const char *kUrlParam = "url=";
+
+const char *kBuildTypePropName = "ro.build.type";
+const char *kEngBuild = "eng";
+const char *kTestBuild = "test";
+
+// @return true if the current build is 'eng' or 'test'.
+bool isTestBuild()
+{
+ char prop[PROPERTY_VALUE_MAX] = { '\0', };
+
+ property_get(kBuildTypePropName, prop, '\0');
+ return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
+}
+
+// @return true if the url scheme is 'test:'
+bool isTestUrl(const char *url)
+{
+ return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
+}
+
+} // anonymous namespace
+
+namespace android {
+
+TestPlayerStub::TestPlayerStub()
+ :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
+ mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
+ mPlayer(NULL) { }
+
+TestPlayerStub::~TestPlayerStub()
+{
+ resetInternal();
+}
+
+status_t TestPlayerStub::initCheck()
+{
+ return isTestBuild() ? OK : INVALID_OPERATION;
+}
+
+// Parse mUrl to get:
+// * The library to be dlopened.
+// * The url to be passed to the real setDataSource impl.
+//
+// mUrl is expected to be in following format:
+//
+// test:<name of the .so>?url=<url for setDataSource>
+//
+// The value of the url parameter is treated as a string (no
+// unescaping of illegal charaters).
+status_t TestPlayerStub::parseUrl()
+{
+ if (strlen(mUrl) < strlen(kTestUrlScheme)) {
+ resetInternal();
+ return BAD_VALUE;
+ }
+
+ char *i = mUrl + strlen(kTestUrlScheme);
+
+ mFilename = i;
+
+ while (*i != '\0' && *i != '?') {
+ ++i;
+ }
+
+ if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
+ resetInternal();
+ return BAD_VALUE;
+ }
+ *i = '\0'; // replace '?' to nul-terminate mFilename
+
+ mContentUrl = i + 1 + strlen(kUrlParam);
+ return OK;
+}
+
+// Load the dynamic library.
+// Create the test player.
+// Call setDataSource on the test player with the url in param.
+status_t TestPlayerStub::setDataSource(const char *url)
+{
+ if (!isTestUrl(url) || NULL != mHandle) {
+ return INVALID_OPERATION;
+ }
+
+ mUrl = strdup(url);
+
+ status_t status = parseUrl();
+
+ if (OK != status) {
+ resetInternal();
+ return status;
+ }
+
+ ::dlerror(); // Clears any pending error.
+
+ // Load the test player from the url. dlopen will fail if the lib
+ // is not there. dls are under /system/lib
+ // None of the entry points should be NULL.
+ mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
+ if (!mHandle) {
+ LOGE("dlopen failed: %s", ::dlerror());
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ // Load the 2 entry points to create and delete instances.
+ const char *err;
+ mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
+ "newPlayer"));
+ err = ::dlerror();
+ if (err || mNewPlayer == NULL) {
+ // if err is NULL the string <null> is inserted in the logs =>
+ // mNewPlayer was NULL.
+ LOGE("dlsym for newPlayer failed %s", err);
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
+ "deletePlayer"));
+ err = ::dlerror();
+ if (err || mDeletePlayer == NULL) {
+ LOGE("dlsym for deletePlayer failed %s", err);
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ mPlayer = (*mNewPlayer)();
+ return mPlayer->setDataSource(mContentUrl);
+}
+
+// Internal cleanup.
+status_t TestPlayerStub::resetInternal()
+{
+ if(mUrl) {
+ free(mUrl);
+ mUrl = NULL;
+ }
+ mFilename = NULL;
+ mContentUrl = NULL;
+
+ if (mPlayer) {
+ LOG_ASSERT(mDeletePlayer != NULL);
+ (*mDeletePlayer)(mPlayer);
+ mPlayer = NULL;
+ }
+
+ if (mHandle) {
+ ::dlclose(mHandle);
+ mHandle = NULL;
+ }
+ return OK;
+}
+
+/* static */ bool TestPlayerStub::canBeUsed(const char *url)
+{
+ return isTestBuild() && isTestUrl(url);
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
new file mode 100644
index 0000000..80d53a8
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -0,0 +1,119 @@
+/*
+ * 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 ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+
+#include <media/MediaPlayerInterface.h>
+#include <utils/Errors.h>
+
+namespace android {
+class MediaPlayerBase; // in media/MediaPlayerInterface.h
+
+// Wrapper around a test media player that gets dynamically loaded.
+//
+// The URL passed to setDataSource has this format:
+//
+// test:<name of the .so>?url=<url for the real setDataSource impl.>
+//
+// e.g:
+// test:invoke_test_media_player.so?url=http://youtube.com/
+// test:invoke_test_media_player.so?url=speedtest
+//
+// TestPlayerStub::setDataSource loads the library in the test url. 2
+// entry points with C linkage are expected. One to create the test
+// player and one to destroy it.
+//
+// extern "C" android::MediaPlayerBase* newPlayer();
+// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p);
+//
+// Once the test player has been loaded, its setDataSource
+// implementation is called with the value of the 'url' parameter.
+//
+// typical usage in a java test:
+// ============================
+//
+// MediaPlayer p = new MediaPlayer();
+// p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
+// p.prepare();
+// ...
+// p.release();
+
+class TestPlayerStub : public MediaPlayerInterface {
+ public:
+ typedef MediaPlayerBase* (*NEW_PLAYER)();
+ typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *);
+
+ TestPlayerStub();
+ virtual ~TestPlayerStub();
+
+ // Called right after the constructor. Check if the current build
+ // allows test players.
+ virtual status_t initCheck();
+
+ // @param url Should be a test url. See class comment.
+ virtual status_t setDataSource(const char* url);
+
+ // Test player for a file descriptor source is not supported.
+ virtual status_t setDataSource(int, int64_t, int64_t) {
+ return INVALID_OPERATION;
+ }
+
+
+ // All the methods below wrap the mPlayer instance.
+ virtual status_t setVideoSurface(const android::sp<android::ISurface>& s) {
+ return mPlayer->setVideoSurface(s);
+ }
+ virtual status_t prepare() {return mPlayer->prepare();}
+ virtual status_t prepareAsync() {return mPlayer->prepareAsync();}
+ virtual status_t start() {return mPlayer->start();}
+ virtual status_t stop() {return mPlayer->stop();}
+ virtual status_t pause() {return mPlayer->pause();}
+ virtual bool isPlaying() {return mPlayer->isPlaying();}
+ virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);}
+ virtual status_t getCurrentPosition(int *p) {
+ return mPlayer->getCurrentPosition(p);
+ }
+ virtual status_t getDuration(int *d) {return mPlayer->getDuration(d);}
+ virtual status_t reset() {return mPlayer->reset();}
+ virtual status_t setLooping(int b) {return mPlayer->setLooping(b);}
+ virtual player_type playerType() {return mPlayer->playerType();}
+ virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
+ return mPlayer->invoke(in, out);
+ }
+
+
+ // @return true if the current build is 'eng' or 'test' and the
+ // url's scheme is 'test:'
+ static bool canBeUsed(const char *url);
+
+ private:
+ // Release the player, dlclose the library.
+ status_t resetInternal();
+ status_t parseUrl();
+
+ char *mUrl; // test:foo.so?url=http://bar
+ char *mFilename; // foo.so
+ char *mContentUrl; // http://bar
+ void *mHandle; // returned by dlopen
+ NEW_PLAYER mNewPlayer;
+ DELETE_PLAYER mDeletePlayer;
+ MediaPlayerBase *mPlayer; // wrapped player
+};
+
+} // namespace android
+
+#endif
diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h
index c30dc1b..4024654 100644
--- a/media/libmediaplayerservice/VorbisPlayer.h
+++ b/media/libmediaplayerservice/VorbisPlayer.h
@@ -53,6 +53,7 @@
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return VORBIS_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;}
private:
status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length);
@@ -88,4 +89,3 @@
}; // namespace android
#endif // ANDROID_VORBISPLAYER_H
-
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
new file mode 100644
index 0000000..0c40b91
--- /dev/null
+++ b/media/libstagefright/Android.mk
@@ -0,0 +1,55 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CachingDataSource.cpp \
+ DataSource.cpp \
+ FileSource.cpp \
+ HTTPDataSource.cpp \
+ HTTPStream.cpp \
+ MP3Extractor.cpp \
+ MPEG4Extractor.cpp \
+ MPEG4Writer.cpp \
+ MediaBuffer.cpp \
+ MediaBufferGroup.cpp \
+ MediaExtractor.cpp \
+ MediaPlayerImpl.cpp \
+ MediaSource.cpp \
+ MetaData.cpp \
+ MmapSource.cpp \
+ OMXCodec.cpp \
+ SampleTable.cpp \
+ ShoutcastSource.cpp \
+ TimeSource.cpp \
+ TimedEventQueue.cpp \
+ Utils.cpp \
+ AudioPlayer.cpp \
+ ESDS.cpp \
+ OMXClient.cpp \
+ OMXDecoder.cpp \
+ string.cpp
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/external/opencore/android
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libmedia \
+ libutils \
+ libcutils \
+ libui
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
new file mode 100644
index 0000000..e8571b5
--- /dev/null
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+
+#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/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
+ : mAudioTrack(NULL),
+ mInputBuffer(NULL),
+ mSampleRate(0),
+ mLatencyUs(0),
+ mFrameSize(0),
+ mNumFramesPlayed(0),
+ mPositionTimeMediaUs(-1),
+ mPositionTimeRealUs(-1),
+ mSeeking(false),
+ mStarted(false),
+ mAudioSink(audioSink) {
+}
+
+AudioPlayer::~AudioPlayer() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
+ assert(mSource == NULL);
+ mSource = source;
+}
+
+void AudioPlayer::start() {
+ assert(!mStarted);
+ assert(mSource != NULL);
+
+ status_t err = mSource->start();
+ assert(err == OK);
+
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ assert(success);
+ assert(!strcasecmp(mime, "audio/raw"));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ assert(success);
+
+ int32_t numChannels;
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ assert(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);
+
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ mFrameSize = mAudioSink->frameSize();
+
+ mAudioSink->start();
+ } else {
+ mAudioTrack = new AudioTrack(
+ AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
+ (numChannels == 2)
+ ? AudioSystem::CHANNEL_OUT_STEREO
+ : AudioSystem::CHANNEL_OUT_MONO,
+ 8192, 0, &AudioCallback, this, 0);
+
+ assert(mAudioTrack->initCheck() == OK);
+
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ mFrameSize = mAudioTrack->frameSize();
+
+ mAudioTrack->start();
+ }
+
+ mStarted = true;
+}
+
+void AudioPlayer::pause() {
+ assert(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ } else {
+ mAudioTrack->stop();
+ }
+}
+
+void AudioPlayer::resume() {
+ assert(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->start();
+ } else {
+ mAudioTrack->start();
+ }
+}
+
+void AudioPlayer::stop() {
+ assert(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+
+ delete mAudioTrack;
+ mAudioTrack = NULL;
+ }
+
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+ if (mInputBuffer != NULL) {
+ LOGI("AudioPlayer releasing input buffer.");
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ mNumFramesPlayed = 0;
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mStarted = false;
+}
+
+// static
+void AudioPlayer::AudioCallback(int event, void *user, void *info) {
+ static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
+}
+
+// static
+void AudioPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie) {
+ AudioPlayer *me = (AudioPlayer *)cookie;
+
+ me->fillBuffer(buffer, size);
+}
+
+void AudioPlayer::AudioCallback(int event, void *info) {
+ if (event != AudioTrack::EVENT_MORE_DATA) {
+ return;
+ }
+
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ fillBuffer(buffer->raw, buffer->size);
+}
+
+void AudioPlayer::fillBuffer(void *data, size_t size) {
+ if (mNumFramesPlayed == 0) {
+ LOGI("AudioCallback");
+ }
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+ mSeeking = false;
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err = mSource->read(&mInputBuffer, &options);
+
+ assert((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+
+ if (err != OK) {
+ memset((char *)data + size_done, 0, size_remaining);
+ break;
+ }
+
+ int32_t units, scale;
+ bool success =
+ mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ success = success &&
+ mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ assert(success);
+
+ Mutex::Autolock autoLock(mLock);
+ mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ mNumFramesPlayed += size / mFrameSize;
+}
+
+int64_t AudioPlayer::getRealTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ return getRealTimeUsLocked();
+}
+
+int64_t AudioPlayer::getRealTimeUsLocked() const {
+ return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
+}
+
+int64_t AudioPlayer::getMediaTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+
+ return mPositionTimeMediaUs + (getRealTimeUsLocked() - mPositionTimeRealUs);
+}
+
+bool AudioPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeMediaUs;
+
+ return mPositionTimeRealUs != -1 || mPositionTimeMediaUs != -1;
+}
+
+status_t AudioPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+
+ return OK;
+}
+
+}
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
new file mode 100644
index 0000000..d599cd5
--- /dev/null
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/CachingDataSource.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+CachingDataSource::CachingDataSource(
+ const sp<DataSource> &source, size_t pageSize, int numPages)
+ : mSource(source),
+ mData(malloc(pageSize * numPages)),
+ mPageSize(pageSize),
+ mFirst(NULL),
+ mLast(NULL) {
+ for (int i = 0; i < numPages; ++i) {
+ Page *page = new Page;
+ page->mPrev = mLast;
+ page->mNext = NULL;
+
+ if (mLast == NULL) {
+ mFirst = page;
+ } else {
+ mLast->mNext = page;
+ }
+
+ mLast = page;
+
+ page->mOffset = -1;
+ page->mLength = 0;
+ page->mData = (char *)mData + mPageSize * i;
+ }
+}
+
+CachingDataSource::~CachingDataSource() {
+ Page *page = mFirst;
+ while (page != NULL) {
+ Page *next = page->mNext;
+ delete page;
+ page = next;
+ }
+ mFirst = mLast = NULL;
+
+ free(mData);
+ mData = NULL;
+}
+
+status_t CachingDataSource::InitCheck() const {
+ return OK;
+}
+
+ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ size_t total = 0;
+ while (size > 0) {
+ Page *page = mFirst;
+ while (page != NULL) {
+ if (page->mOffset >= 0 && offset >= page->mOffset
+ && offset < page->mOffset + (off_t)page->mLength) {
+ break;
+ }
+ page = page->mNext;
+ }
+
+ if (page == NULL) {
+ page = allocate_page();
+ page->mOffset = offset - offset % mPageSize;
+ ssize_t n = mSource->read_at(page->mOffset, page->mData, mPageSize);
+ if (n < 0) {
+ page->mLength = 0;
+ } else {
+ page->mLength = (size_t)n;
+ }
+ mFirst->mPrev = page;
+ page->mNext = mFirst;
+ page->mPrev = NULL;
+ mFirst = page;
+
+ if (n < 0) {
+ return n;
+ }
+
+ if (offset >= page->mOffset + (off_t)page->mLength) {
+ break;
+ }
+ } else {
+ // Move "page" to the front in LRU order.
+ if (page->mNext != NULL) {
+ page->mNext->mPrev = page->mPrev;
+ } else {
+ mLast = page->mPrev;
+ }
+
+ if (page->mPrev != NULL) {
+ page->mPrev->mNext = page->mNext;
+ } else {
+ mFirst = page->mNext;
+ }
+
+ mFirst->mPrev = page;
+ page->mNext = mFirst;
+ page->mPrev = NULL;
+ mFirst = page;
+ }
+
+ size_t copy = page->mLength - (offset - page->mOffset);
+ if (copy > size) {
+ copy = size;
+ }
+ memcpy(data,(const char *)page->mData + (offset - page->mOffset),
+ copy);
+
+ total += copy;
+
+ if (page->mLength < mPageSize) {
+ // This was the final page. There is no more data beyond it.
+ break;
+ }
+
+ offset += copy;
+ size -= copy;
+ data = (char *)data + copy;
+ }
+
+ return total;
+}
+
+CachingDataSource::Page *CachingDataSource::allocate_page() {
+ // The last page is the least recently used, i.e. oldest.
+
+ Page *page = mLast;
+
+ page->mPrev->mNext = NULL;
+ mLast = page->mPrev;
+ page->mPrev = NULL;
+
+ return page;
+}
+
+} // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
new file mode 100644
index 0000000..ee12873
--- /dev/null
+++ b/media/libstagefright/CameraSource.cpp
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+#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/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <ui/ICameraClient.h>
+#include <ui/ICameraService.h>
+#include <ui/Overlay.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class CameraBuffer : public MediaBuffer {
+public:
+ CameraBuffer(const sp<IMemory> &frame)
+ : MediaBuffer(frame->pointer(), frame->size()),
+ mFrame(frame) {
+ }
+
+ sp<IMemory> releaseFrame() {
+ sp<IMemory> frame = mFrame;
+ mFrame.clear();
+ return frame;
+ }
+
+private:
+ sp<IMemory> mFrame;
+};
+
+class CameraSourceClient : public BnCameraClient {
+public:
+ CameraSourceClient()
+ : mSource(NULL) {
+ }
+
+ virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+ assert(mSource != NULL);
+ mSource->notifyCallback(msgType, ext1, ext2);
+ }
+
+ virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
+ assert(mSource != NULL);
+ mSource->dataCallback(msgType, data);
+ }
+
+ void setCameraSource(CameraSource *source) {
+ mSource = source;
+ }
+
+private:
+ CameraSource *mSource;
+};
+
+class DummySurface : public BnSurface {
+public:
+ DummySurface() {}
+
+ virtual status_t registerBuffers(const BufferHeap &buffers) {
+ return OK;
+ }
+
+ virtual void postBuffer(ssize_t offset) {
+ }
+
+ virtual void unregisterBuffers() {
+ }
+
+ virtual sp<OverlayRef> createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ return NULL;
+ }
+};
+
+// static
+CameraSource *CameraSource::Create() {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<ICameraService> service =
+ interface_cast<ICameraService>(
+ sm->getService(String16("media.camera")));
+
+ sp<CameraSourceClient> client = new CameraSourceClient;
+ sp<ICamera> camera = service->connect(client);
+
+ CameraSource *source = new CameraSource(camera, client);
+ client->setCameraSource(source);
+
+ return source;
+}
+
+CameraSource::CameraSource(
+ const sp<ICamera> &camera, const sp<ICameraClient> &client)
+ : mCamera(camera),
+ mCameraClient(client),
+ mNumFrames(0),
+ mStarted(false) {
+ printf("params: \"%s\"\n", mCamera->getParameters().string());
+}
+
+CameraSource::~CameraSource() {
+ if (mStarted) {
+ stop();
+ }
+
+ mCamera->disconnect();
+}
+
+status_t CameraSource::start(MetaData *) {
+ assert(!mStarted);
+
+ status_t err = mCamera->lock();
+ assert(err == OK);
+
+ err = mCamera->setPreviewDisplay(new DummySurface);
+ assert(err == OK);
+ mCamera->setPreviewCallbackFlag(1);
+ mCamera->startPreview();
+ assert(err == OK);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t CameraSource::stop() {
+ assert(mStarted);
+
+ mCamera->stopPreview();
+ mCamera->unlock();
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> CameraSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "video/raw");
+ meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
+ meta->setInt32(kKeyWidth, 480);
+ meta->setInt32(kKeyHeight, 320);
+
+ return meta;
+}
+
+status_t CameraSource::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ assert(mStarted);
+
+ *buffer = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ sp<IMemory> frame;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ while (mFrames.empty()) {
+ mFrameAvailableCondition.wait(mLock);
+ }
+
+ frame = *mFrames.begin();
+ mFrames.erase(mFrames.begin());
+ }
+
+ int count = mNumFrames++;
+
+ *buffer = new CameraBuffer(frame);
+
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
+ (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
+
+ (*buffer)->add_ref();
+ (*buffer)->setObserver(this);
+
+ return OK;
+}
+
+void CameraSource::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+ printf("notifyCallback %d, %d, %d\n", msgType, ext1, ext2);
+}
+
+void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) {
+ Mutex::Autolock autoLock(mLock);
+
+ mFrames.push_back(data);
+ mFrameAvailableCondition.signal();
+}
+
+void CameraSource::signalBufferReturned(MediaBuffer *_buffer) {
+ CameraBuffer *buffer = static_cast<CameraBuffer *>(_buffer);
+
+ mCamera->releaseRecordingFrame(buffer->releaseFrame());
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ buffer = NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
new file mode 100644
index 0000000..02a276b
--- /dev/null
+++ b/media/libstagefright/DataSource.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <utils/String8.h>
+
+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;
+
+ return ERROR_UNSUPPORTED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Mutex DataSource::gSnifferMutex;
+List<DataSource::SnifferFunc> DataSource::gSniffers;
+
+bool DataSource::sniff(String8 *mimeType, float *confidence) {
+ *mimeType = "";
+ *confidence = 0.0f;
+
+ Mutex::Autolock autoLock(gSnifferMutex);
+ for (List<SnifferFunc>::iterator it = gSniffers.begin();
+ it != gSniffers.end(); ++it) {
+ String8 newMimeType;
+ float newConfidence;
+ if ((*it)(this, &newMimeType, &newConfidence)) {
+ if (newConfidence > *confidence) {
+ *mimeType = newMimeType;
+ *confidence = newConfidence;
+ }
+ }
+ }
+
+ return *confidence > 0.0;
+}
+
+// static
+void DataSource::RegisterSniffer(SnifferFunc func) {
+ Mutex::Autolock autoLock(gSnifferMutex);
+
+ for (List<SnifferFunc>::iterator it = gSniffers.begin();
+ it != gSniffers.end(); ++it) {
+ if (*it == func) {
+ return;
+ }
+ }
+
+ gSniffers.push_back(func);
+}
+
+// static
+void DataSource::RegisterDefaultSniffers() {
+ RegisterSniffer(SniffMP3);
+ RegisterSniffer(SniffMPEG4);
+}
+
+} // namespace android
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
new file mode 100644
index 0000000..53b92a0
--- /dev/null
+++ b/media/libstagefright/ESDS.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/ESDS.h>
+
+#include <string.h>
+
+namespace android {
+
+ESDS::ESDS(const void *data, size_t size)
+ : mData(new uint8_t[size]),
+ mSize(size),
+ mInitCheck(NO_INIT),
+ mDecoderSpecificOffset(0),
+ mDecoderSpecificLength(0) {
+ memcpy(mData, data, size);
+
+ mInitCheck = parse();
+}
+
+ESDS::~ESDS() {
+ delete[] mData;
+ mData = NULL;
+}
+
+status_t ESDS::InitCheck() const {
+ return mInitCheck;
+}
+
+status_t ESDS::getCodecSpecificInfo(const void **data, size_t *size) const {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ *data = &mData[mDecoderSpecificOffset];
+ *size = mDecoderSpecificLength;
+
+ return OK;
+}
+
+status_t ESDS::skipDescriptorHeader(
+ size_t offset, size_t size,
+ uint8_t *tag, size_t *data_offset, size_t *data_size) const {
+ if (size == 0) {
+ return ERROR_MALFORMED;
+ }
+
+ *tag = mData[offset++];
+ --size;
+
+ *data_size = 0;
+ bool more;
+ do {
+ if (size == 0) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t x = mData[offset++];
+ --size;
+
+ *data_size = (*data_size << 7) | (x & 0x7f);
+ more = (x & 0x80) != 0;
+ }
+ while (more);
+
+ if (*data_size > size) {
+ return ERROR_MALFORMED;
+ }
+
+ *data_offset = offset;
+
+ return OK;
+}
+
+status_t ESDS::parse() {
+ uint8_t tag;
+ size_t data_offset;
+ size_t data_size;
+ status_t err =
+ skipDescriptorHeader(0, mSize, &tag, &data_offset, &data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_ESDescriptor) {
+ return ERROR_MALFORMED;
+ }
+
+ return parseESDescriptor(data_offset, data_size);
+}
+
+status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
+ if (size < 3) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 2; // skip ES_ID
+ size -= 2;
+
+ unsigned streamDependenceFlag = mData[offset] & 0x80;
+ unsigned URL_Flag = mData[offset] & 0x40;
+ unsigned OCRstreamFlag = mData[offset] & 0x20;
+
+ ++offset;
+ --size;
+
+ if (streamDependenceFlag) {
+ offset += 2;
+ size -= 2;
+ }
+
+ if (URL_Flag) {
+ if (offset >= size) {
+ return ERROR_MALFORMED;
+ }
+ unsigned URLlength = mData[offset];
+ offset += URLlength + 1;
+ size -= URLlength + 1;
+ }
+
+ if (OCRstreamFlag) {
+ offset += 2;
+ size -= 2;
+ }
+
+ if (offset >= size) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t tag;
+ size_t sub_offset, sub_size;
+ status_t err = skipDescriptorHeader(
+ offset, size, &tag, &sub_offset, &sub_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_DecoderConfigDescriptor) {
+ return ERROR_MALFORMED;
+ }
+
+ err = parseDecoderConfigDescriptor(sub_offset, sub_size);
+
+ return err;
+}
+
+status_t ESDS::parseDecoderConfigDescriptor(size_t offset, size_t size) {
+ if (size < 13) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 13;
+ size -= 13;
+
+ if (size == 0) {
+ mDecoderSpecificOffset = 0;
+ mDecoderSpecificLength = 0;
+ return OK;
+ }
+
+ uint8_t tag;
+ size_t sub_offset, sub_size;
+ status_t err = skipDescriptorHeader(
+ offset, size, &tag, &sub_offset, &sub_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_DecoderSpecificInfo) {
+ return ERROR_MALFORMED;
+ }
+
+ mDecoderSpecificOffset = sub_offset;
+ mDecoderSpecificLength = sub_size;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
new file mode 100644
index 0000000..c26d0a0
--- /dev/null
+++ b/media/libstagefright/FileSource.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/FileSource.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+namespace android {
+
+FileSource::FileSource(const char *filename)
+ : mFile(fopen(filename, "rb")) {
+}
+
+FileSource::~FileSource() {
+ if (mFile != NULL) {
+ fclose(mFile);
+ mFile = NULL;
+ }
+}
+
+status_t FileSource::InitCheck() const {
+ return mFile != NULL ? OK : NO_INIT;
+}
+
+ssize_t FileSource::read_at(off_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ int err = fseeko(mFile, offset, SEEK_SET);
+ assert(err != -1);
+
+ ssize_t result = fread(data, 1, size, mFile);
+
+ return result;
+}
+
+} // namespace android
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
new file mode 100644
index 0000000..d1f8cd4
--- /dev/null
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <stdlib.h>
+
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+HTTPDataSource::HTTPDataSource(const char *uri)
+ : mHost(NULL),
+ mPort(0),
+ mPath(NULL),
+ mBuffer(malloc(kBufferSize)),
+ mBufferLength(0),
+ mBufferOffset(0) {
+ assert(!strncasecmp("http://", uri, 7));
+
+ string host;
+ string path;
+ int port;
+
+ char *slash = strchr(uri + 7, '/');
+ if (slash == NULL) {
+ host = uri + 7;
+ path = "/";
+ } else {
+ host = string(uri + 7, slash - (uri + 7));
+ path = slash;
+ }
+
+ char *colon = strchr(host.c_str(), ':');
+ if (colon == NULL) {
+ port = 80;
+ } else {
+ char *end;
+ long tmp = strtol(colon + 1, &end, 10);
+ assert(end > colon + 1);
+ assert(tmp > 0 && tmp < 65536);
+ port = tmp;
+
+ host = string(host, 0, colon - host.c_str());
+ }
+
+ LOGI("Connecting to host '%s', port %d, path '%s'",
+ host.c_str(), port, path.c_str());
+
+ mHost = strdup(host.c_str());
+ mPort = port;
+ mPath = strdup(path.c_str());
+
+ status_t err = mHttp.connect(mHost, mPort);
+ assert(err == OK);
+}
+
+HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
+ : mHost(strdup(host)),
+ mPort(port),
+ mPath(strdup(path)),
+ mBuffer(malloc(kBufferSize)),
+ mBufferLength(0),
+ mBufferOffset(0) {
+ status_t err = mHttp.connect(mHost, mPort);
+ assert(err == OK);
+}
+
+HTTPDataSource::~HTTPDataSource() {
+ mHttp.disconnect();
+
+ free(mBuffer);
+ mBuffer = NULL;
+
+ free(mPath);
+ mPath = NULL;
+}
+
+ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
+ if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+ size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
+
+ size_t copy = num_bytes_available;
+ if (copy > size) {
+ copy = size;
+ }
+
+ memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
+
+ return copy;
+ }
+
+ mBufferOffset = offset;
+ mBufferLength = 0;
+
+ char host[128];
+ sprintf(host, "Host: %s\r\n", mHost);
+
+ char range[128];
+ sprintf(range, "Range: bytes=%ld-%ld\r\n\r\n",
+ mBufferOffset, mBufferOffset + kBufferSize - 1);
+
+ int http_status;
+
+ status_t err;
+ int attempt = 1;
+ for (;;) {
+ if ((err = mHttp.send("GET ")) != OK
+ || (err = mHttp.send(mPath)) != OK
+ || (err = mHttp.send(" HTTP/1.1\r\n")) != OK
+ || (err = mHttp.send(host)) != OK
+ || (err = mHttp.send(range)) != OK
+ || (err = mHttp.send("\r\n")) != OK
+ || (err = mHttp.receive_header(&http_status)) != OK) {
+
+ if (attempt == 3) {
+ return err;
+ }
+
+ mHttp.connect(mHost, mPort);
+ ++attempt;
+ } else {
+ break;
+ }
+ }
+
+ if ((http_status / 100) != 2) {
+ return UNKNOWN_ERROR;
+ }
+
+ string value;
+ if (!mHttp.find_header_value("Content-Length", &value)) {
+ return UNKNOWN_ERROR;
+ }
+
+ char *end;
+ unsigned long contentLength = strtoul(value.c_str(), &end, 10);
+
+ ssize_t num_bytes_received = mHttp.receive(mBuffer, contentLength);
+
+ if (num_bytes_received <= 0) {
+ return num_bytes_received;
+ }
+
+ mBufferLength = (size_t)num_bytes_received;
+
+ size_t copy = mBufferLength;
+ if (copy > size) {
+ copy = size;
+ }
+
+ memcpy(data, mBuffer, copy);
+
+ return copy;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
new file mode 100644
index 0000000..29e6f72
--- /dev/null
+++ b/media/libstagefright/HTTPStream.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/HTTPStream.h>
+
+namespace android {
+
+// static
+const char *HTTPStream::kStatusKey = ":status:";
+
+HTTPStream::HTTPStream()
+ : mState(READY),
+ mSocket(-1) {
+}
+
+HTTPStream::~HTTPStream() {
+ disconnect();
+}
+
+status_t HTTPStream::connect(const char *server, int port) {
+ status_t err = OK;
+
+ if (mState == CONNECTED) {
+ return ERROR_ALREADY_CONNECTED;
+ }
+
+ assert(mSocket == -1);
+ mSocket = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (mSocket < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ struct hostent *ent = gethostbyname(server);
+ if (ent == NULL) {
+ err = ERROR_UNKNOWN_HOST;
+ goto exit1;
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+
+ if (::connect(mSocket, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ err = ERROR_CANNOT_CONNECT;
+ goto exit1;
+ }
+
+ mState = CONNECTED;
+
+ return OK;
+
+exit1:
+ close(mSocket);
+ mSocket = -1;
+
+ return err;
+}
+
+status_t HTTPStream::disconnect() {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ assert(mSocket >= 0);
+ close(mSocket);
+ mSocket = -1;
+
+ mState = READY;
+
+ return OK;
+}
+
+status_t HTTPStream::send(const char *data, size_t size) {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ while (size > 0) {
+ ssize_t n = ::send(mSocket, data, size, 0);
+
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ size -= (size_t)n;
+ data += (size_t)n;
+ }
+
+ return OK;
+}
+
+status_t HTTPStream::send(const char *data) {
+ return send(data, strlen(data));
+}
+
+status_t HTTPStream::receive_line(char *line, size_t size) {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ bool saw_CR = false;
+ size_t length = 0;
+
+ for (;;) {
+ char c;
+ ssize_t n = recv(mSocket, &c, 1, 0);
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ if (saw_CR && c == '\n') {
+ // We have a complete line.
+
+ line[length - 1] = '\0';
+ return OK;
+ }
+
+ saw_CR = (c == '\r');
+
+ assert(length + 1 < size);
+ line[length++] = c;
+ }
+}
+
+status_t HTTPStream::receive_header(int *http_status) {
+ *http_status = -1;
+ mHeaders.clear();
+
+ char line[256];
+ status_t err = receive_line(line, sizeof(line));
+ if (err != OK) {
+ return err;
+ }
+
+ mHeaders.add(string(kStatusKey), string(line));
+
+ char *spacePos = strchr(line, ' ');
+ if (spacePos == NULL) {
+ // Malformed response?
+ return UNKNOWN_ERROR;
+ }
+
+ char *status_start = spacePos + 1;
+ char *status_end = status_start;
+ while (isdigit(*status_end)) {
+ ++status_end;
+ }
+
+ if (status_end == status_start) {
+ // Malformed response, status missing?
+ return UNKNOWN_ERROR;
+ }
+
+ memmove(line, status_start, status_end - status_start);
+ line[status_end - status_start] = '\0';
+
+ long tmp = strtol(line, NULL, 10);
+ if (tmp < 0 || tmp > 999) {
+ return UNKNOWN_ERROR;
+ }
+
+ *http_status = (int)tmp;
+
+ for (;;) {
+ err = receive_line(line, sizeof(line));
+ if (err != OK) {
+ return err;
+ }
+
+ if (*line == '\0') {
+ // Empty line signals the end of the header.
+ break;
+ }
+
+ // puts(line);
+
+ char *colonPos = strchr(line, ':');
+ if (colonPos == NULL) {
+ mHeaders.add(string(line), string());
+ } else {
+ char *end_of_key = colonPos;
+ while (end_of_key > line && isspace(end_of_key[-1])) {
+ --end_of_key;
+ }
+
+ char *start_of_value = colonPos + 1;
+ while (isspace(*start_of_value)) {
+ ++start_of_value;
+ }
+
+ *end_of_key = '\0';
+
+ mHeaders.add(string(line), string(start_of_value));
+ }
+ }
+
+ return OK;
+}
+
+ssize_t HTTPStream::receive(void *data, size_t size) {
+ size_t total = 0;
+ while (total < size) {
+ ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
+
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ total += (size_t)n;
+ }
+
+ return (ssize_t)total;
+}
+
+bool HTTPStream::find_header_value(const string &key, string *value) const {
+ ssize_t index = mHeaders.indexOfKey(key);
+ if (index < 0) {
+ value->clear();
+ return false;
+ }
+
+ *value = mHeaders.valueAt(index);
+
+ return true;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
new file mode 100644
index 0000000..44258ba
--- /dev/null
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -0,0 +1,521 @@
+/*
+ * 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 "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/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static bool get_mp3_frame_size(
+ uint32_t header, size_t *frame_size,
+ int *out_sampling_rate = NULL, int *out_channels = NULL,
+ int *out_bitrate = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned protection = (header >> 16) & 1;
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+static bool Resync(
+ 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.
+ const uint32_t kMask = 0xfffe0ccf;
+
+ const size_t kMaxFrameSize = 4096;
+ uint8_t *buffer = new uint8_t[kMaxFrameSize];
+
+ off_t pos = *inout_pos - kMaxFrameSize;
+ size_t buffer_offset = kMaxFrameSize;
+ size_t buffer_length = kMaxFrameSize;
+ bool valid = false;
+ do {
+ if (buffer_offset + 3 >= buffer_length) {
+ if (buffer_length < kMaxFrameSize) {
+ break;
+ }
+
+ pos += buffer_offset;
+
+ if (pos >= *inout_pos + 128 * 1024) {
+ // Don't scan forever.
+ LOGV("giving up at offset %ld", pos);
+ break;
+ }
+
+ memmove(buffer, &buffer[buffer_offset], buffer_length - buffer_offset);
+ buffer_length = buffer_length - buffer_offset;
+ buffer_offset = 0;
+
+ ssize_t n = source->read_at(
+ pos, &buffer[buffer_length], kMaxFrameSize - buffer_length);
+
+ if (n <= 0) {
+ break;
+ }
+
+ buffer_length += (size_t)n;
+
+ continue;
+ }
+
+ uint32_t header = U32_AT(&buffer[buffer_offset]);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++buffer_offset;
+ continue;
+ }
+
+ size_t frame_size;
+ int sample_rate, num_channels, bitrate;
+ if (!get_mp3_frame_size(header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
+ ++buffer_offset;
+ continue;
+ }
+
+ LOGV("found possible 1st frame at %ld", pos + buffer_offset);
+
+ // We found what looks like a valid frame,
+ // now find its successors.
+
+ off_t test_pos = pos + buffer_offset + frame_size;
+
+ valid = true;
+ for (int j = 0; j < 3; ++j) {
+ uint8_t tmp[4];
+ if (source->read_at(test_pos, tmp, 4) < 4) {
+ valid = false;
+ break;
+ }
+
+ uint32_t test_header = U32_AT(tmp);
+
+ LOGV("subsequent header is %08x", test_header);
+
+ if ((test_header & kMask) != (header & kMask)) {
+ valid = false;
+ break;
+ }
+
+ size_t test_frame_size;
+ if (!get_mp3_frame_size(test_header, &test_frame_size)) {
+ valid = false;
+ break;
+ }
+
+ LOGV("found subsequent frame #%d at %ld", j + 2, test_pos);
+
+ test_pos += test_frame_size;
+ }
+
+ if (valid) {
+ *inout_pos = pos + buffer_offset;
+
+ if (out_header != NULL) {
+ *out_header = header;
+ }
+ } else {
+ LOGV("no dice, no valid sequence of frames found.");
+ }
+
+ ++buffer_offset;
+
+ } while (!valid);
+
+ delete[] buffer;
+ buffer = NULL;
+
+ return valid;
+}
+
+class MP3Source : public MediaSource {
+public:
+ MP3Source(
+ const sp<MetaData> &meta, const sp<DataSource> &source,
+ off_t first_frame_pos, uint32_t fixed_header);
+
+ 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 ~MP3Source();
+
+private:
+ sp<MetaData> mMeta;
+ sp<DataSource> mDataSource;
+ off_t mFirstFramePos;
+ uint32_t mFixedHeader;
+ off_t mCurrentPos;
+ int64_t mCurrentTimeUs;
+ bool mStarted;
+
+ MediaBufferGroup *mGroup;
+
+ MP3Source(const MP3Source &);
+ MP3Source &operator=(const MP3Source &);
+};
+
+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);
+
+ if (success) {
+ mFirstFramePos = pos;
+ mFixedHeader = header;
+
+ size_t frame_size;
+ int sample_rate;
+ int num_channels;
+ int bitrate;
+ get_mp3_frame_size(
+ header, &frame_size, &sample_rate, &num_channels, &bitrate);
+
+ mMeta = new MetaData;
+
+ mMeta->setCString(kKeyMIMEType, "audio/mpeg");
+ mMeta->setInt32(kKeySampleRate, sample_rate);
+ mMeta->setInt32(kKeyBitRate, bitrate);
+ mMeta->setInt32(kKeyChannelCount, num_channels);
+
+ off_t fileSize;
+ if (mDataSource->getSize(&fileSize) == OK) {
+ mMeta->setInt32(
+ kKeyDuration,
+ 8 * (fileSize - mFirstFramePos) / bitrate);
+ mMeta->setInt32(kKeyTimeScale, 1000);
+ }
+ }
+}
+
+MP3Extractor::~MP3Extractor() {
+}
+
+size_t MP3Extractor::countTracks() {
+ return (mFirstFramePos < 0) ? 0 : 1;
+}
+
+sp<MediaSource> MP3Extractor::getTrack(size_t index) {
+ if (mFirstFramePos < 0 || index != 0) {
+ return NULL;
+ }
+
+ return new MP3Source(
+ mMeta, mDataSource, mFirstFramePos, mFixedHeader);
+}
+
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
+ if (mFirstFramePos < 0 || index != 0) {
+ return NULL;
+ }
+
+ return mMeta;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MP3Source::MP3Source(
+ const sp<MetaData> &meta, const sp<DataSource> &source,
+ off_t first_frame_pos, uint32_t fixed_header)
+ : mMeta(meta),
+ mDataSource(source),
+ mFirstFramePos(first_frame_pos),
+ mFixedHeader(fixed_header),
+ mCurrentPos(0),
+ mCurrentTimeUs(0),
+ mStarted(false),
+ mGroup(NULL) {
+}
+
+MP3Source::~MP3Source() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MP3Source::start(MetaData *) {
+ assert(!mStarted);
+
+ mGroup = new MediaBufferGroup;
+
+ const size_t kMaxFrameSize = 32768;
+ mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+
+ mCurrentPos = mFirstFramePos;
+ mCurrentTimeUs = 0;
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MP3Source::stop() {
+ assert(mStarted);
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> MP3Source::getFormat() {
+ return mMeta;
+}
+
+status_t MP3Source::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ int32_t bitrate;
+ if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
+ // bitrate is in kbits/sec.
+ LOGI("no bitrate");
+
+ return ERROR_UNSUPPORTED;
+ }
+
+ mCurrentTimeUs = seekTimeUs;
+ mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 1000000 * 125;
+ }
+
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ size_t frame_size;
+ for (;;) {
+ ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), 4);
+ if (n < 4) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ uint32_t header = U32_AT((const uint8_t *)buffer->data());
+
+ if (get_mp3_frame_size(header, &frame_size)) {
+ break;
+ }
+
+ // Lost sync.
+ LOGW("lost sync!\n");
+
+ off_t pos = mCurrentPos;
+ if (!Resync(mDataSource, mFixedHeader, &pos, NULL)) {
+ LOGE("Unable to resync. Signalling end of stream.");
+
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ mCurrentPos = pos;
+
+ // Try again with the new position.
+ }
+
+ assert(frame_size <= buffer->size());
+
+ ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
+ if (n < (ssize_t)frame_size) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ buffer->set_range(0, frame_size);
+
+ buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
+ buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+
+ mCurrentPos += frame_size;
+ mCurrentTimeUs += 1152 * 1000000 / 44100;
+
+ *out = buffer;
+
+ return OK;
+}
+
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ off_t pos = 0;
+ uint32_t header;
+ if (!Resync(source, 0, &pos, &header)) {
+ return false;
+ }
+
+ *mimeType = "audio/mpeg";
+ *confidence = 0.3f;
+
+ return true;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
new file mode 100644
index 0000000..662d5fb
--- /dev/null
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -0,0 +1,944 @@
+/*
+ * 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_TAG "MPEG4Extractor"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class MPEG4Source : public MediaSource {
+public:
+ // Caller retains ownership of both "dataSource" and "sampleTable".
+ MPEG4Source(const sp<MetaData> &format,
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable);
+
+ 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 ~MPEG4Source();
+
+private:
+ sp<MetaData> mFormat;
+ sp<DataSource> mDataSource;
+ int32_t mTimescale;
+ sp<SampleTable> mSampleTable;
+ uint32_t mCurrentSampleIndex;
+
+ bool mIsAVC;
+ bool mStarted;
+
+ MediaBufferGroup *mGroup;
+
+ MediaBuffer *mBuffer;
+ size_t mBufferOffset;
+ size_t mBufferSizeRemaining;
+
+ bool mNeedsNALFraming;
+
+ uint8_t *mSrcBuffer;
+
+ MPEG4Source(const MPEG4Source &);
+ MPEG4Source &operator=(const MPEG4Source &);
+};
+
+static void hexdump(const void *_data, size_t size) {
+ const uint8_t *data = (const uint8_t *)_data;
+ size_t offset = 0;
+ while (offset < size) {
+ printf("0x%04x ", offset);
+
+ size_t n = size - offset;
+ if (n > 16) {
+ n = 16;
+ }
+
+ for (size_t i = 0; i < 16; ++i) {
+ if (i == 8) {
+ printf(" ");
+ }
+
+ if (offset + i < size) {
+ printf("%02x ", data[offset + i]);
+ } else {
+ printf(" ");
+ }
+ }
+
+ printf(" ");
+
+ for (size_t i = 0; i < n; ++i) {
+ if (isprint(data[offset + i])) {
+ printf("%c", data[offset + i]);
+ } else {
+ printf(".");
+ }
+ }
+
+ printf("\n");
+
+ offset += 16;
+ }
+}
+
+static const char *const FourCC2MIME(uint32_t fourcc) {
+ switch (fourcc) {
+ case FOURCC('m', 'p', '4', 'a'):
+ return "audio/mp4a-latm";
+
+ case FOURCC('s', 'a', 'm', 'r'):
+ return "audio/3gpp";
+
+ case FOURCC('m', 'p', '4', 'v'):
+ return "video/mp4v-es";
+
+ case FOURCC('s', '2', '6', '3'):
+ return "video/3gpp";
+
+ case FOURCC('a', 'v', 'c', '1'):
+ return "video/avc";
+
+ default:
+ assert(!"should not be here.");
+ return NULL;
+ }
+}
+
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mHaveMetadata(false),
+ mFirstTrack(NULL),
+ mLastTrack(NULL) {
+}
+
+MPEG4Extractor::~MPEG4Extractor() {
+ Track *track = mFirstTrack;
+ while (track) {
+ Track *next = track->next;
+
+ delete track;
+ track = next;
+ }
+ mFirstTrack = mLastTrack = NULL;
+}
+
+size_t MPEG4Extractor::countTracks() {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return 0;
+ }
+
+ size_t n = 0;
+ Track *track = mFirstTrack;
+ while (track) {
+ ++n;
+ track = track->next;
+ }
+
+ return n;
+}
+
+sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return NULL;
+ }
+
+ Track *track = mFirstTrack;
+ while (index > 0) {
+ if (track == NULL) {
+ return NULL;
+ }
+
+ track = track->next;
+ --index;
+ }
+
+ return track->meta;
+}
+
+status_t MPEG4Extractor::readMetaData() {
+ if (mHaveMetadata) {
+ return OK;
+ }
+
+ off_t offset = 0;
+ status_t err;
+ while ((err = parseChunk(&offset, 0)) == OK) {
+ }
+
+ if (mHaveMetadata) {
+ return OK;
+ }
+
+ return err;
+}
+
+static void MakeFourCCString(uint32_t x, char *s) {
+ s[0] = x >> 24;
+ s[1] = (x >> 16) & 0xff;
+ s[2] = (x >> 8) & 0xff;
+ s[3] = x & 0xff;
+ s[4] = '\0';
+}
+
+status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
+ uint32_t hdr[2];
+ if (mDataSource->read_at(*offset, hdr, 8) < 8) {
+ return ERROR_IO;
+ }
+ uint64_t chunk_size = ntohl(hdr[0]);
+ uint32_t chunk_type = ntohl(hdr[1]);
+ off_t data_offset = *offset + 8;
+
+ if (chunk_size == 1) {
+ if (mDataSource->read_at(*offset + 8, &chunk_size, 8) < 8) {
+ return ERROR_IO;
+ }
+ chunk_size = ntoh64(chunk_size);
+ data_offset += 8;
+ }
+
+ char chunk[5];
+ MakeFourCCString(chunk_type, chunk);
+
+#if 0
+ static const char kWhitespace[] = " ";
+ const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
+ printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size);
+
+ char buffer[256];
+ if (chunk_size <= sizeof(buffer)) {
+ if (mDataSource->read_at(*offset, buffer, chunk_size) < chunk_size) {
+ return ERROR_IO;
+ }
+
+ hexdump(buffer, chunk_size);
+ }
+#endif
+
+ off_t chunk_data_size = *offset + chunk_size - data_offset;
+
+ switch(chunk_type) {
+ case FOURCC('m', 'o', 'o', 'v'):
+ case FOURCC('t', 'r', 'a', 'k'):
+ case FOURCC('m', 'd', 'i', 'a'):
+ case FOURCC('m', 'i', 'n', 'f'):
+ case FOURCC('d', 'i', 'n', 'f'):
+ case FOURCC('s', 't', 'b', 'l'):
+ case FOURCC('m', 'v', 'e', 'x'):
+ case FOURCC('m', 'o', 'o', 'f'):
+ case FOURCC('t', 'r', 'a', 'f'):
+ case FOURCC('m', 'f', 'r', 'a'):
+ case FOURCC('s', 'k', 'i' ,'p'):
+ {
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset;
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ assert(*offset == stop_offset);
+
+ if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
+ mHaveMetadata = true;
+
+ return UNKNOWN_ERROR; // Return a dummy error.
+ }
+ break;
+ }
+
+ case FOURCC('t', 'k', 'h', 'd'):
+ {
+ assert(chunk_data_size >= 4);
+
+ uint8_t version;
+ if (mDataSource->read_at(data_offset, &version, 1) < 1) {
+ return ERROR_IO;
+ }
+
+ uint64_t ctime, mtime, duration;
+ int32_t id;
+ uint32_t width, height;
+
+ if (version == 1) {
+ if (chunk_data_size != 36 + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[36 + 60];
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ ctime = U64_AT(&buffer[4]);
+ mtime = U64_AT(&buffer[12]);
+ id = U32_AT(&buffer[20]);
+ duration = U64_AT(&buffer[28]);
+ width = U32_AT(&buffer[88]);
+ height = U32_AT(&buffer[92]);
+ } else if (version == 0) {
+ if (chunk_data_size != 24 + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[24 + 60];
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+ ctime = U32_AT(&buffer[4]);
+ mtime = U32_AT(&buffer[8]);
+ id = U32_AT(&buffer[12]);
+ duration = U32_AT(&buffer[20]);
+ width = U32_AT(&buffer[76]);
+ height = U32_AT(&buffer[80]);
+ }
+
+ Track *track = new Track;
+ track->next = NULL;
+ if (mLastTrack) {
+ mLastTrack->next = track;
+ } else {
+ mFirstTrack = track;
+ }
+ mLastTrack = track;
+
+ track->meta = new MetaData;
+ track->timescale = 0;
+ track->sampleTable = new SampleTable(mDataSource);
+ track->meta->setCString(kKeyMIMEType, "application/octet-stream");
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('m', 'd', 'h', 'd'):
+ {
+ if (chunk_data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t version;
+ if (mDataSource->read_at(
+ data_offset, &version, sizeof(version))
+ < (ssize_t)sizeof(version)) {
+ return ERROR_IO;
+ }
+
+ off_t timescale_offset;
+
+ if (version == 1) {
+ timescale_offset = data_offset + 4 + 16;
+ } else if (version == 0) {
+ timescale_offset = data_offset + 4 + 8;
+ } else {
+ return ERROR_IO;
+ }
+
+ uint32_t timescale;
+ if (mDataSource->read_at(
+ timescale_offset, ×cale, sizeof(timescale))
+ < (ssize_t)sizeof(timescale)) {
+ return ERROR_IO;
+ }
+
+ mLastTrack->timescale = ntohl(timescale);
+ mLastTrack->meta->setInt32(kKeyTimeScale, mLastTrack->timescale);
+
+ int64_t duration;
+ if (version == 1) {
+ if (mDataSource->read_at(
+ timescale_offset + 4, &duration, sizeof(duration))
+ < (ssize_t)sizeof(duration)) {
+ return ERROR_IO;
+ }
+ duration = ntoh64(duration);
+ } else {
+ int32_t duration32;
+ if (mDataSource->read_at(
+ timescale_offset + 4, &duration32, sizeof(duration32))
+ < (ssize_t)sizeof(duration32)) {
+ return ERROR_IO;
+ }
+ duration = ntohl(duration32);
+ }
+ mLastTrack->meta->setInt32(kKeyDuration, duration);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('h', 'd', 'l', 'r'):
+ {
+ if (chunk_data_size < 25) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[24];
+ if (mDataSource->read_at(data_offset, buffer, 24) < 24) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ if (U32_AT(&buffer[4]) != 0) {
+ // pre_defined should be 0.
+ return ERROR_MALFORMED;
+ }
+
+ mHandlerType = U32_AT(&buffer[8]);
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'd'):
+ {
+ if (chunk_data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[8];
+ assert(chunk_data_size >= (off_t)sizeof(buffer));
+ if (mDataSource->read_at(
+ data_offset, buffer, 8) < 8) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t entry_count = U32_AT(&buffer[4]);
+
+ if (entry_count > 1) {
+ // For now we only support a single type of media per track.
+ return ERROR_UNSUPPORTED;
+ }
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + 8;
+ for (uint32_t i = 0; i < entry_count; ++i) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ assert(*offset == stop_offset);
+ break;
+ }
+
+ case FOURCC('m', 'p', '4', 'a'):
+ case FOURCC('s', 'a', 'm', 'r'):
+ {
+ if (mHandlerType != FOURCC('s', 'o', 'u', 'n')) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[8 + 20];
+ if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+ // Basic AudioSampleEntry size.
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t num_channels = U16_AT(&buffer[16]);
+
+ if (!strcasecmp("audio/3gpp", FourCC2MIME(chunk_type))) {
+ // AMR audio is always mono.
+ num_channels = 1;
+ }
+
+ uint16_t sample_size = U16_AT(&buffer[18]);
+ uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+
+ printf("*** coding='%s' %d channels, size %d, rate %d\n",
+ chunk, num_channels, sample_size, sample_rate);
+
+ mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+ mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
+ mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + sizeof(buffer);
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ assert(*offset == stop_offset);
+ break;
+ }
+
+ case FOURCC('m', 'p', '4', 'v'):
+ case FOURCC('s', '2', '6', '3'):
+ case FOURCC('a', 'v', 'c', '1'):
+ {
+ if (mHandlerType != FOURCC('v', 'i', 'd', 'e')) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[78];
+ if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+ // Basic VideoSampleEntry size.
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t width = U16_AT(&buffer[6 + 18]);
+ uint16_t height = U16_AT(&buffer[6 + 20]);
+
+ printf("*** coding='%s' width=%d height=%d\n",
+ chunk, width, height);
+
+ mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+ mLastTrack->meta->setInt32(kKeyWidth, width);
+ mLastTrack->meta->setInt32(kKeyHeight, height);
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + sizeof(buffer);
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ assert(*offset == stop_offset);
+ break;
+ }
+
+ case FOURCC('s', 't', 'c', 'o'):
+ case FOURCC('c', 'o', '6', '4'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setChunkOffsetParams(
+ chunk_type, data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'c'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSampleToChunkParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'z'):
+ case FOURCC('s', 't', 'z', '2'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSampleSizeParams(
+ chunk_type, data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 't', 's'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setTimeToSampleParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 's'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSyncSampleParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('e', 's', 'd', 's'):
+ {
+ if (chunk_data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[256];
+ if (chunk_data_size > (off_t)sizeof(buffer)) {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ mLastTrack->meta->setData(
+ kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('a', 'v', 'c', 'C'):
+ {
+ char buffer[256];
+ if (chunk_data_size > (off_t)sizeof(buffer)) {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ mLastTrack->meta->setData(
+ kKeyAVCC, kTypeAVCC, buffer, chunk_data_size);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ default:
+ {
+ *offset += chunk_size;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return NULL;
+ }
+
+ Track *track = mFirstTrack;
+ while (index > 0) {
+ if (track == NULL) {
+ return NULL;
+ }
+
+ track = track->next;
+ --index;
+ }
+
+ return new MPEG4Source(
+ track->meta, mDataSource, track->sampleTable);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Source::MPEG4Source(
+ const sp<MetaData> &format,
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable)
+ : mFormat(format),
+ mDataSource(dataSource),
+ mTimescale(0),
+ mSampleTable(sampleTable),
+ mCurrentSampleIndex(0),
+ mIsAVC(false),
+ mStarted(false),
+ mGroup(NULL),
+ mBuffer(NULL),
+ mBufferOffset(0),
+ mBufferSizeRemaining(0),
+ mNeedsNALFraming(false),
+ mSrcBuffer(NULL) {
+ const char *mime;
+ bool success = mFormat->findCString(kKeyMIMEType, &mime);
+ assert(success);
+
+ success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
+ assert(success);
+
+ mIsAVC = !strcasecmp(mime, "video/avc");
+}
+
+MPEG4Source::~MPEG4Source() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MPEG4Source::start(MetaData *params) {
+ assert(!mStarted);
+
+ int32_t val;
+ if (mIsAVC && params && params->findInt32(kKeyNeedsNALFraming, &val)
+ && val != 0) {
+ mNeedsNALFraming = true;
+ } else {
+ mNeedsNALFraming = false;
+ }
+
+ mGroup = new MediaBufferGroup;
+
+ size_t max_size;
+ status_t err = mSampleTable->getMaxSampleSize(&max_size);
+ assert(err == OK);
+
+ // Assume that a given buffer only contains at most 10 fragments,
+ // each fragment originally prefixed with a 2 byte length will
+ // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+ // and thus will grow by 2 bytes per fragment.
+ mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+ mSrcBuffer = new uint8_t[max_size];
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MPEG4Source::stop() {
+ assert(mStarted);
+
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ delete[] mSrcBuffer;
+ mSrcBuffer = NULL;
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+ mCurrentSampleIndex = 0;
+
+ return OK;
+}
+
+sp<MetaData> MPEG4Source::getFormat() {
+ return mFormat;
+}
+
+status_t MPEG4Source::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ assert(mStarted);
+
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ uint32_t sampleIndex;
+ status_t err = mSampleTable->findClosestSample(
+ seekTimeUs * mTimescale / 1000000,
+ &sampleIndex, SampleTable::kSyncSample_Flag);
+
+ if (err != OK) {
+ return err;
+ }
+
+ mCurrentSampleIndex = sampleIndex;
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ // fall through
+ }
+
+ 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);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = mGroup->acquire_buffer(&mBuffer);
+ if (err != OK) {
+ assert(mBuffer == NULL);
+ return err;
+ }
+
+ if (!mIsAVC || !mNeedsNALFraming) {
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return err;
+ }
+
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+
+ *out = mBuffer;
+ mBuffer = NULL;
+
+ 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(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ uint8_t header[8];
+
+ ssize_t n = source->read_at(4, header, sizeof(header));
+ if (n < (ssize_t)sizeof(header)) {
+ return false;
+ }
+
+ if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+ || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
+ *mimeType = "video/mp4";
+ *confidence = 0.1;
+
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
new file mode 100644
index 0000000..10c4629
--- /dev/null
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -0,0 +1,649 @@
+/*
+ * 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.
+ */
+
+#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/MediaSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+class MPEG4Writer::Track {
+public:
+ Track(MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source);
+ ~Track();
+
+ void start();
+ void stop();
+
+ int64_t getDuration() const;
+ void writeTrackHeader(int32_t trackID);
+
+private:
+ MPEG4Writer *mOwner;
+ sp<MetaData> mMeta;
+ sp<MediaSource> mSource;
+ volatile bool mDone;
+
+ pthread_t mThread;
+
+ struct SampleInfo {
+ size_t size;
+ off_t offset;
+ int64_t timestamp;
+ };
+ List<SampleInfo> mSampleInfos;
+
+ void *mCodecSpecificData;
+ size_t mCodecSpecificDataSize;
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ Track(const Track &);
+ Track &operator=(const Track &);
+};
+
+MPEG4Writer::MPEG4Writer(const char *filename)
+ : mFile(fopen(filename, "wb")),
+ mOffset(0),
+ mMdatOffset(0) {
+ assert(mFile != NULL);
+}
+
+MPEG4Writer::~MPEG4Writer() {
+ stop();
+
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ delete *it;
+ }
+ mTracks.clear();
+}
+
+void MPEG4Writer::addSource(
+ const sp<MetaData> &meta, const sp<MediaSource> &source) {
+ Track *track = new Track(this, meta, source);
+ mTracks.push_back(track);
+}
+
+void MPEG4Writer::start() {
+ if (mFile == NULL) {
+ return;
+ }
+
+ beginBox("ftyp");
+ writeFourcc("isom");
+ writeInt32(0);
+ writeFourcc("isom");
+ endBox();
+
+ mMdatOffset = mOffset;
+ write("\x00\x00\x00\x01mdat????????", 16);
+
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ (*it)->start();
+ }
+}
+
+void MPEG4Writer::stop() {
+ if (mFile == NULL) {
+ return;
+ }
+
+ int64_t max_duration = 0;
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ (*it)->stop();
+
+ int64_t duration = (*it)->getDuration();
+ if (duration > max_duration) {
+ max_duration = duration;
+ }
+ }
+
+ // Fix up the size of the 'mdat' chunk.
+ fseek(mFile, mMdatOffset + 8, SEEK_SET);
+ int64_t size = mOffset - mMdatOffset;
+ size = hton64(size);
+ fwrite(&size, 1, 8, mFile);
+ fseek(mFile, mOffset, SEEK_SET);
+
+ time_t now = time(NULL);
+
+ beginBox("moov");
+
+ beginBox("mvhd");
+ writeInt32(0); // version=0, flags=0
+ writeInt32(now); // creation time
+ writeInt32(now); // modification time
+ writeInt32(1000); // timescale
+ writeInt32(max_duration);
+ writeInt32(0x10000); // rate
+ writeInt16(0x100); // volume
+ writeInt16(0); // reserved
+ writeInt32(0); // reserved
+ writeInt32(0); // reserved
+ writeInt32(0x10000); // matrix
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0x10000);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0x40000000);
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(mTracks.size() + 1); // nextTrackID
+ endBox(); // mvhd
+
+ int32_t id = 1;
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it, ++id) {
+ (*it)->writeTrackHeader(id);
+ }
+ endBox(); // moov
+
+ assert(mBoxes.empty());
+
+ fclose(mFile);
+ mFile = NULL;
+}
+
+off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ off_t old_offset = mOffset;
+
+ fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1, buffer->range_length(), mFile);
+
+ mOffset += buffer->range_length();
+
+ return old_offset;
+}
+
+void MPEG4Writer::beginBox(const char *fourcc) {
+ assert(strlen(fourcc) == 4);
+
+ mBoxes.push_back(mOffset);
+
+ writeInt32(0);
+ writeFourcc(fourcc);
+}
+
+void MPEG4Writer::endBox() {
+ assert(!mBoxes.empty());
+
+ off_t offset = *--mBoxes.end();
+ mBoxes.erase(--mBoxes.end());
+
+ fseek(mFile, offset, SEEK_SET);
+ writeInt32(mOffset - offset);
+ mOffset -= 4;
+ fseek(mFile, mOffset, SEEK_SET);
+}
+
+void MPEG4Writer::writeInt8(int8_t x) {
+ fwrite(&x, 1, 1, mFile);
+ ++mOffset;
+}
+
+void MPEG4Writer::writeInt16(int16_t x) {
+ x = htons(x);
+ fwrite(&x, 1, 2, mFile);
+ mOffset += 2;
+}
+
+void MPEG4Writer::writeInt32(int32_t x) {
+ x = htonl(x);
+ fwrite(&x, 1, 4, mFile);
+ mOffset += 4;
+}
+
+void MPEG4Writer::writeInt64(int64_t x) {
+ x = hton64(x);
+ fwrite(&x, 1, 8, mFile);
+ mOffset += 8;
+}
+
+void MPEG4Writer::writeCString(const char *s) {
+ size_t n = strlen(s);
+
+ fwrite(s, 1, n + 1, mFile);
+ mOffset += n + 1;
+}
+
+void MPEG4Writer::writeFourcc(const char *s) {
+ assert(strlen(s) == 4);
+ fwrite(s, 1, 4, mFile);
+ mOffset += 4;
+}
+
+void MPEG4Writer::write(const void *data, size_t size) {
+ fwrite(data, 1, size, mFile);
+ mOffset += size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Writer::Track::Track(
+ MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source)
+ : mOwner(owner),
+ mMeta(meta),
+ mSource(source),
+ mDone(false),
+ mCodecSpecificData(NULL),
+ mCodecSpecificDataSize(0) {
+}
+
+MPEG4Writer::Track::~Track() {
+ stop();
+
+ if (mCodecSpecificData != NULL) {
+ free(mCodecSpecificData);
+ mCodecSpecificData = NULL;
+ }
+}
+
+void MPEG4Writer::Track::start() {
+ mSource->start();
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mDone = false;
+
+ int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+ assert(err == 0);
+
+ pthread_attr_destroy(&attr);
+}
+
+void MPEG4Writer::Track::stop() {
+ if (mDone) {
+ return;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ mSource->stop();
+}
+
+// static
+void *MPEG4Writer::Track::ThreadWrapper(void *me) {
+ Track *track = static_cast<Track *>(me);
+
+ track->threadEntry();
+
+ return NULL;
+}
+
+void MPEG4Writer::Track::threadEntry() {
+ bool is_mpeg4 = false;
+ sp<MetaData> meta = mSource->getFormat();
+ const char *mime;
+ meta->findCString(kKeyMIMEType, &mime);
+ is_mpeg4 = !strcasecmp(mime, "video/mp4v-es");
+
+ MediaBuffer *buffer;
+ while (!mDone && mSource->read(&buffer) == OK) {
+ if (buffer->range_length() == 0) {
+ buffer->release();
+ buffer = NULL;
+
+ continue;
+ }
+
+ if (mCodecSpecificData == NULL && is_mpeg4) {
+ const uint8_t *data =
+ (const uint8_t *)buffer->data() + buffer->range_offset();
+
+ const size_t size = buffer->range_length();
+
+ size_t offset = 0;
+ while (offset + 3 < size) {
+ if (data[offset] == 0x00 && data[offset + 1] == 0x00
+ && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
+ break;
+ }
+
+ ++offset;
+ }
+
+ // assert(offset + 3 < size);
+ if (offset + 3 >= size) {
+ // XXX assume the entire first chunk of data is the codec specific
+ // data.
+ offset = size;
+ }
+
+ mCodecSpecificDataSize = offset;
+ mCodecSpecificData = malloc(offset);
+ memcpy(mCodecSpecificData, data, offset);
+
+ buffer->set_range(buffer->range_offset() + offset, size - offset);
+ }
+
+ off_t offset = mOwner->addSample(buffer);
+
+ SampleInfo info;
+ info.size = buffer->range_length();
+ info.offset = offset;
+
+ int32_t units, scale;
+ bool success =
+ buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ assert(success);
+ success =
+ buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ assert(success);
+
+ info.timestamp = (int64_t)units * 1000 / scale;
+
+ mSampleInfos.push_back(info);
+
+ buffer->release();
+ buffer = NULL;
+ }
+}
+
+int64_t MPEG4Writer::Track::getDuration() const {
+ return 10000; // XXX
+}
+
+void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
+ const char *mime;
+ bool success = mMeta->findCString(kKeyMIMEType, &mime);
+ assert(success);
+
+ bool is_audio = !strncasecmp(mime, "audio/", 6);
+
+ time_t now = time(NULL);
+
+ mOwner->beginBox("trak");
+
+ mOwner->beginBox("tkhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(now); // creation time
+ mOwner->writeInt32(now); // modification time
+ mOwner->writeInt32(trackID);
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(getDuration());
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // layer
+ mOwner->writeInt16(0); // alternate group
+ mOwner->writeInt16(is_audio ? 0x100 : 0); // volume
+ mOwner->writeInt16(0); // reserved
+
+ mOwner->writeInt32(0x10000); // matrix
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0x10000);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0x40000000);
+
+ if (is_audio) {
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ } else {
+ int32_t width, height;
+ bool success = mMeta->findInt32(kKeyWidth, &width);
+ success = success && mMeta->findInt32(kKeyHeight, &height);
+ assert(success);
+
+ mOwner->writeInt32(width);
+ mOwner->writeInt32(height);
+ }
+ mOwner->endBox(); // tkhd
+
+ mOwner->beginBox("mdia");
+
+ mOwner->beginBox("mdhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(now); // creation time
+ mOwner->writeInt32(now); // modification time
+ mOwner->writeInt32(1000); // timescale
+ mOwner->writeInt32(getDuration());
+ mOwner->writeInt16(0); // language code XXX
+ mOwner->writeInt16(0); // predefined
+ mOwner->endBox();
+
+ mOwner->beginBox("hdlr");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeFourcc(is_audio ? "soun" : "vide");
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeCString(""); // name
+ mOwner->endBox();
+
+ mOwner->beginBox("minf");
+
+ mOwner->beginBox("dinf");
+ mOwner->beginBox("dref");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1);
+ mOwner->beginBox("url ");
+ mOwner->writeInt32(1); // version=0, flags=1
+ mOwner->endBox(); // url
+ mOwner->endBox(); // dref
+ mOwner->endBox(); // dinf
+
+ if (is_audio) {
+ mOwner->beginBox("smhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt16(0); // balance
+ mOwner->writeInt16(0); // reserved
+ mOwner->endBox();
+ } else {
+ mOwner->beginBox("vmhd");
+ mOwner->writeInt32(0x00000001); // version=0, flags=1
+ mOwner->writeInt16(0); // graphics mode
+ mOwner->writeInt16(0); // opcolor
+ mOwner->writeInt16(0);
+ mOwner->writeInt16(0);
+ mOwner->endBox();
+ }
+ mOwner->endBox(); // minf
+
+ mOwner->beginBox("stbl");
+
+ mOwner->beginBox("stsd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1); // entry count
+ if (is_audio) {
+ mOwner->beginBox("xxxx"); // audio format XXX
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt16(0); // data ref index
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(2); // channel count
+ mOwner->writeInt16(16); // sample size
+ mOwner->writeInt16(0); // predefined
+ mOwner->writeInt16(0); // reserved
+
+ int32_t samplerate;
+ bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
+ assert(success);
+
+ mOwner->writeInt32(samplerate << 16);
+ mOwner->endBox();
+ } else {
+ if (!strcasecmp("video/mp4v-es", mime)) {
+ mOwner->beginBox("mp4v");
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ mOwner->beginBox("s263");
+ } else {
+ assert(!"should not be here, unknown mime type.");
+ }
+
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt16(0); // data ref index
+ mOwner->writeInt16(0); // predefined
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeInt32(0); // predefined
+
+ int32_t width, height;
+ bool success = mMeta->findInt32(kKeyWidth, &width);
+ success = success && mMeta->findInt32(kKeyHeight, &height);
+ assert(success);
+
+ mOwner->writeInt16(width);
+ mOwner->writeInt16(height);
+ mOwner->writeInt32(0x480000); // horiz resolution
+ mOwner->writeInt32(0x480000); // vert resolution
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(1); // frame count
+ mOwner->write(" ", 32);
+ mOwner->writeInt16(0x18); // depth
+ mOwner->writeInt16(-1); // predefined
+
+ assert(23 + mCodecSpecificDataSize < 128);
+
+ if (!strcasecmp("video/mp4v-es", mime)) {
+ mOwner->beginBox("esds");
+
+ mOwner->writeInt32(0); // version=0, flags=0
+
+ mOwner->writeInt8(0x03); // ES_DescrTag
+ mOwner->writeInt8(23 + mCodecSpecificDataSize);
+ mOwner->writeInt16(0x0000); // ES_ID
+ mOwner->writeInt8(0x1f);
+
+ mOwner->writeInt8(0x04); // DecoderConfigDescrTag
+ mOwner->writeInt8(15 + mCodecSpecificDataSize);
+ mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2
+ mOwner->writeInt8(0x11); // streamType VisualStream
+
+ static const uint8_t kData[] = {
+ 0x01, 0x77, 0x00,
+ 0x00, 0x03, 0xe8, 0x00,
+ 0x00, 0x03, 0xe8, 0x00
+ };
+ mOwner->write(kData, sizeof(kData));
+
+ mOwner->writeInt8(0x05); // DecoderSpecificInfoTag
+
+ mOwner->writeInt8(mCodecSpecificDataSize);
+ mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+
+ static const uint8_t kData2[] = {
+ 0x06, // SLConfigDescriptorTag
+ 0x01,
+ 0x02
+ };
+ mOwner->write(kData2, sizeof(kData2));
+
+ mOwner->endBox(); // esds
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ mOwner->beginBox("d263");
+
+ mOwner->writeInt32(0); // vendor
+ mOwner->writeInt8(0); // decoder version
+ mOwner->writeInt8(10); // level: 10
+ mOwner->writeInt8(0); // profile: 0
+
+ mOwner->endBox(); // d263
+ }
+ mOwner->endBox(); // mp4v or s263
+ }
+ mOwner->endBox(); // stsd
+
+ mOwner->beginBox("stts");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size() - 1);
+
+ List<SampleInfo>::iterator it = mSampleInfos.begin();
+ int64_t last = (*it).timestamp;
+ ++it;
+ while (it != mSampleInfos.end()) {
+ mOwner->writeInt32(1);
+ mOwner->writeInt32((*it).timestamp - last);
+
+ last = (*it).timestamp;
+
+ ++it;
+ }
+ mOwner->endBox(); // stts
+
+ mOwner->beginBox("stsz");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(0); // default sample size
+ mOwner->writeInt32(mSampleInfos.size());
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it) {
+ mOwner->writeInt32((*it).size);
+ }
+ mOwner->endBox(); // stsz
+
+ mOwner->beginBox("stsc");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size());
+ int32_t n = 1;
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it, ++n) {
+ mOwner->writeInt32(n);
+ mOwner->writeInt32(1);
+ mOwner->writeInt32(1);
+ }
+ mOwner->endBox(); // stsc
+
+ mOwner->beginBox("co64");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size());
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it, ++n) {
+ mOwner->writeInt64((*it).offset);
+ }
+ mOwner->endBox(); // co64
+
+ mOwner->endBox(); // stbl
+ mOwner->endBox(); // mdia
+ mOwner->endBox(); // trak
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
new file mode 100644
index 0000000..cd78dbd
--- /dev/null
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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_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/MetaData.h>
+
+namespace android {
+
+// XXX make this truly atomic.
+static int atomic_add(int *value, int delta) {
+ int prev_value = *value;
+ *value += delta;
+
+ return prev_value;
+}
+
+MediaBuffer::MediaBuffer(void *data, size_t size)
+ : mObserver(NULL),
+ mNextBuffer(NULL),
+ mRefCount(0),
+ mData(data),
+ mSize(size),
+ mRangeOffset(0),
+ mRangeLength(size),
+ mOwnsData(false),
+ mMetaData(new MetaData),
+ mOriginal(NULL) {
+}
+
+MediaBuffer::MediaBuffer(size_t size)
+ : mObserver(NULL),
+ mNextBuffer(NULL),
+ mRefCount(0),
+ mData(malloc(size)),
+ mSize(size),
+ mRangeOffset(0),
+ mRangeLength(size),
+ mOwnsData(true),
+ mMetaData(new MetaData),
+ mOriginal(NULL) {
+}
+
+void MediaBuffer::release() {
+ if (mObserver == NULL) {
+ assert(mRefCount == 0);
+ delete this;
+ return;
+ }
+
+ int prevCount = atomic_add(&mRefCount, -1);
+ if (prevCount == 1) {
+ if (mObserver == NULL) {
+ delete this;
+ return;
+ }
+
+ mObserver->signalBufferReturned(this);
+ }
+ assert(prevCount > 0);
+}
+
+void MediaBuffer::claim() {
+ assert(mObserver != NULL);
+ assert(mRefCount == 1);
+
+ mRefCount = 0;
+}
+
+void MediaBuffer::add_ref() {
+ atomic_add(&mRefCount, 1);
+}
+
+void *MediaBuffer::data() const {
+ return mData;
+}
+
+size_t MediaBuffer::size() const {
+ return mSize;
+}
+
+size_t MediaBuffer::range_offset() const {
+ return mRangeOffset;
+}
+
+size_t MediaBuffer::range_length() const {
+ return mRangeLength;
+}
+
+void MediaBuffer::set_range(size_t offset, size_t length) {
+ if (offset < 0 || offset + length > mSize) {
+ LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
+ }
+ assert(offset >= 0 && offset + length <= mSize);
+
+ mRangeOffset = offset;
+ mRangeLength = length;
+}
+
+sp<MetaData> MediaBuffer::meta_data() {
+ return mMetaData;
+}
+
+void MediaBuffer::reset() {
+ mMetaData->clear();
+ set_range(0, mSize);
+}
+
+MediaBuffer::~MediaBuffer() {
+ assert(mObserver == NULL);
+
+ if (mOwnsData && mData != NULL) {
+ free(mData);
+ mData = NULL;
+ }
+
+ if (mOriginal != NULL) {
+ mOriginal->release();
+ mOriginal = NULL;
+ }
+}
+
+void MediaBuffer::setObserver(MediaBufferObserver *observer) {
+ assert(observer == NULL || mObserver == NULL);
+ mObserver = observer;
+}
+
+void MediaBuffer::setNextBuffer(MediaBuffer *buffer) {
+ mNextBuffer = buffer;
+}
+
+MediaBuffer *MediaBuffer::nextBuffer() {
+ return mNextBuffer;
+}
+
+int MediaBuffer::refcount() const {
+ return mRefCount;
+}
+
+MediaBuffer *MediaBuffer::clone() {
+ MediaBuffer *buffer = new MediaBuffer(mData, mSize);
+ buffer->set_range(mRangeOffset, mRangeLength);
+ buffer->mMetaData = new MetaData(*mMetaData.get());
+
+ add_ref();
+ buffer->mOriginal = this;
+
+ return buffer;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
new file mode 100644
index 0000000..aec7722
--- /dev/null
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+ : mFirstBuffer(NULL),
+ mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+ MediaBuffer *next;
+ for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+ buffer = next) {
+ next = buffer->nextBuffer();
+
+ assert(buffer->refcount() == 0);
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ buffer->setObserver(this);
+
+ if (mLastBuffer) {
+ mLastBuffer->setNextBuffer(buffer);
+ } else {
+ mFirstBuffer = buffer;
+ }
+
+ mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(MediaBuffer **out) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (;;) {
+ for (MediaBuffer *buffer = mFirstBuffer;
+ buffer != NULL; buffer = buffer->nextBuffer()) {
+ if (buffer->refcount() == 0) {
+ buffer->add_ref();
+ buffer->reset();
+
+ *out = buffer;
+ goto exit;
+ }
+ }
+
+ // All buffers are in use. Block until one of them is returned to us.
+ mCondition.wait(mLock);
+ }
+
+exit:
+ return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+ Mutex::Autolock autoLock(mLock);
+ mCondition.signal();
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
new file mode 100644
index 0000000..5f78e12
--- /dev/null
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "MediaExtractor"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<MediaExtractor> MediaExtractor::Create(
+ const sp<DataSource> &source, const char *mime) {
+ String8 tmp;
+ if (mime == NULL) {
+ float confidence;
+ if (!source->sniff(&tmp, &confidence)) {
+ LOGE("FAILED to autodetect media content.");
+
+ return NULL;
+ }
+
+ mime = tmp.string();
+ LOGI("Autodetected media content as '%s' with confidence %.2f",
+ mime, confidence);
+ }
+
+ if (!strcasecmp(mime, "video/mp4") || !strcasecmp(mime, "audio/mp4")) {
+ return new MPEG4Extractor(source);
+ } else if (!strcasecmp(mime, "audio/mpeg")) {
+ return new MP3Extractor(source);
+ }
+
+ return NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
new file mode 100644
index 0000000..2d7b62837b
--- /dev/null
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -0,0 +1,662 @@
+/*
+ * 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 "MediaPlayerImpl"
+#include "utils/Log.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <OMX_Component.h>
+
+#include <unistd.h>
+
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/CachingDataSource.h>
+// #include <media/stagefright/CameraSource.h>
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/HTTPStream.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),
+ mTimeSource(NULL),
+ mAudioPlayer(NULL),
+ mVideoWidth(0),
+ mVideoHeight(0),
+ mVideoPosition(0),
+ mDuration(0),
+ mPlaying(false),
+ mPaused(false),
+ mSeeking(false) {
+ LOGI("MediaPlayerImpl(%s)", uri);
+ DataSource::RegisterDefaultSniffers();
+
+ status_t err = mClient.connect();
+ if (err != OK) {
+ LOGE("Failed to connect to OMXClient.");
+ return;
+ }
+
+ if (!strncasecmp("shoutcast://", uri, 12)) {
+ setAudioSource(makeShoutcastSource(uri));
+#if 0
+ } else if (!strncasecmp("camera:", uri, 7)) {
+ mVideoWidth = 480;
+ mVideoHeight = 320;
+ mVideoDecoder = CameraSource::Create();
+#endif
+ } else {
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = new MmapSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7)) {
+ source = new HTTPDataSource(uri);
+ source = new CachingDataSource(source, 64 * 1024, 10);
+ } else {
+ // Assume it's a filename.
+ source = new MmapSource(uri);
+ }
+
+ mExtractor = MediaExtractor::Create(source);
+
+ if (mExtractor == NULL) {
+ return;
+ }
+ }
+
+ init();
+
+ mInitCheck = OK;
+}
+
+MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
+ : mInitCheck(NO_INIT),
+ mTimeSource(NULL),
+ mAudioPlayer(NULL),
+ mVideoWidth(0),
+ mVideoHeight(0),
+ mVideoPosition(0),
+ mDuration(0),
+ mPlaying(false),
+ mPaused(false),
+ mSeeking(false) {
+ LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
+ DataSource::RegisterDefaultSniffers();
+
+ status_t err = mClient.connect();
+ if (err != OK) {
+ LOGE("Failed to connect to OMXClient.");
+ return;
+ }
+
+ mExtractor = MediaExtractor::Create(
+ new MmapSource(fd, offset, length));
+
+ if (mExtractor == NULL) {
+ return;
+ }
+
+ init();
+
+ mInitCheck = OK;
+}
+
+status_t MediaPlayerImpl::initCheck() const {
+ return mInitCheck;
+}
+
+MediaPlayerImpl::~MediaPlayerImpl() {
+ stop();
+ setSurface(NULL);
+
+ if (mInitCheck == OK) {
+ mClient.disconnect();
+ }
+
+ LOGV("~MediaPlayerImpl done.");
+}
+
+void MediaPlayerImpl::play() {
+ LOGI("play");
+
+ if (mPlaying) {
+ if (mPaused) {
+ if (mAudioSource != NULL) {
+ mAudioPlayer->resume();
+ }
+ mPaused = false;
+ }
+ return;
+ }
+
+ mPlaying = true;
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer = new AudioPlayer(mAudioSink);
+ mAudioPlayer->setSource(mAudioDecoder);
+ mAudioPlayer->start();
+ mTimeSource = mAudioPlayer;
+ } else {
+ mTimeSource = new SystemTimeSource;
+ }
+
+ if (mVideoDecoder != NULL) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&mVideoThread, &attr, VideoWrapper, this);
+
+ pthread_attr_destroy(&attr);
+ }
+}
+
+void MediaPlayerImpl::pause() {
+ if (!mPlaying || mPaused) {
+ return;
+ }
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer->pause();
+ }
+
+ mPaused = true;
+}
+
+void MediaPlayerImpl::stop() {
+ if (!mPlaying) {
+ return;
+ }
+
+ mPlaying = false;
+
+ if (mVideoDecoder != NULL) {
+ void *dummy;
+ pthread_join(mVideoThread, &dummy);
+ }
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer->stop();
+
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ } else {
+ delete mTimeSource;
+ }
+
+ mTimeSource = NULL;
+}
+
+// static
+void *MediaPlayerImpl::VideoWrapper(void *me) {
+ ((MediaPlayerImpl *)me)->videoEntry();
+
+ return NULL;
+}
+
+void MediaPlayerImpl::videoEntry() {
+ bool firstFrame = true;
+ bool eof = false;
+
+ status_t err = mVideoDecoder->start();
+ assert(err == OK);
+
+ while (mPlaying) {
+ MediaBuffer *buffer;
+
+ MediaSource::ReadOptions options;
+ bool seeking = false;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mSeeking) {
+ LOGI("seek-options to %lld", mSeekTimeUs);
+ options.setSeekTo(mSeekTimeUs);
+
+ mSeeking = false;
+ seeking = true;
+ eof = false;
+ }
+ }
+
+ if (eof || mPaused) {
+ usleep(100000);
+ continue;
+ }
+
+ status_t err = mVideoDecoder->read(&buffer, &options);
+ assert((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
+
+ if (err == ERROR_END_OF_STREAM || err != OK) {
+ eof = true;
+ continue;
+ }
+
+ if (buffer->range_length() == 0) {
+ // The final buffer is empty.
+ buffer->release();
+ continue;
+ }
+
+ int32_t units, scale;
+ bool success =
+ buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ assert(success);
+ success =
+ buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ assert(success);
+
+ int64_t pts_us = (int64_t)units * 1000000 / scale;
+ {
+ Mutex::Autolock autoLock(mLock);
+ mVideoPosition = pts_us;
+
+ LOGV("now_video = %.2f secs (%lld ms)",
+ pts_us / 1E6, (pts_us + 500) / 1000);
+ }
+
+ if (seeking && mAudioPlayer != NULL) {
+ // Now that we know where exactly video seeked (taking sync-samples
+ // into account), we will seek the audio track to the same time.
+ mAudioPlayer->seekTo(pts_us);
+ }
+
+ if (firstFrame || seeking) {
+ mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - pts_us;
+ firstFrame = false;
+ }
+
+ displayOrDiscardFrame(buffer, pts_us);
+ }
+
+ mVideoDecoder->stop();
+}
+
+void MediaPlayerImpl::displayOrDiscardFrame(
+ MediaBuffer *buffer, int64_t pts_us) {
+ for (;;) {
+ if (!mPlaying || mPaused) {
+ buffer->release();
+ buffer = NULL;
+
+ return;
+ }
+
+ int64_t realtime_us, mediatime_us;
+ if (mAudioPlayer != NULL
+ && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
+ mTimeSourceDeltaUs = realtime_us - mediatime_us;
+ LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
+ }
+
+ int64_t now_us = mTimeSource->getRealTimeUs();
+ now_us -= mTimeSourceDeltaUs;
+
+ int64_t delay_us = pts_us - now_us;
+
+ if (delay_us < -15000) {
+ // We're late.
+
+ LOGI("we're late by %lld ms, dropping a frame\n",
+ -delay_us / 1000);
+
+ buffer->release();
+ buffer = NULL;
+ return;
+ } else if (delay_us > 100000) {
+ LOGI("we're much too early (by %lld ms)\n",
+ delay_us / 1000);
+ usleep(100000);
+ continue;
+ } else if (delay_us > 0) {
+ usleep(delay_us);
+ }
+
+ break;
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mVideoRenderer.get() != NULL) {
+ sendFrameToISurface(buffer);
+ }
+ }
+
+ buffer->release();
+ buffer = NULL;
+}
+
+void MediaPlayerImpl::init() {
+ if (mExtractor != NULL) {
+ size_t num_tracks = mExtractor->countTracks();
+
+ mDuration = 0;
+
+ for (size_t i = 0; i < num_tracks; ++i) {
+ const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ assert(meta != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ bool is_audio = false;
+ bool is_acceptable = false;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ is_audio = true;
+ is_acceptable = (mAudioSource == NULL);
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ is_acceptable = (mVideoSource == NULL);
+ }
+
+ if (!is_acceptable) {
+ continue;
+ }
+
+ sp<MediaSource> source = mExtractor->getTrack(i);
+
+ int32_t units, scale;
+ if (meta->findInt32(kKeyDuration, &units)
+ && meta->findInt32(kKeyTimeScale, &scale)) {
+ int64_t duration_us = (int64_t)units * 1000000 / scale;
+ if (duration_us > mDuration) {
+ mDuration = duration_us;
+ }
+ }
+
+ if (is_audio) {
+ setAudioSource(source);
+ } else {
+ setVideoSource(source);
+ }
+ }
+ }
+}
+
+void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
+ LOGI("setAudioSource");
+ mAudioSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+#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(const sp<MediaSource> &source) {
+ LOGI("setVideoSource");
+ mVideoSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+ bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
+ assert(success);
+
+ success = meta->findInt32(kKeyHeight, &mVideoHeight);
+ assert(success);
+
+#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();
+ populateISurface();
+ }
+}
+
+void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
+ LOGI("setSurface %p", surface.get());
+ Mutex::Autolock autoLock(mLock);
+
+ depopulateISurface();
+
+ mSurface = surface;
+ mISurface = NULL;
+
+ if (mSurface.get() != NULL) {
+ populateISurface();
+ }
+}
+
+void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
+ LOGI("setISurface %p", isurface.get());
+ Mutex::Autolock autoLock(mLock);
+
+ depopulateISurface();
+
+ mSurface = NULL;
+ mISurface = isurface;
+
+ if (mISurface.get() != NULL) {
+ populateISurface();
+ }
+}
+
+MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
+ if (strncasecmp(uri, "shoutcast://", 12)) {
+ return NULL;
+ }
+
+ string host;
+ string path;
+ int port;
+
+ char *slash = strchr(uri + 12, '/');
+ if (slash == NULL) {
+ host = uri + 12;
+ path = "/";
+ } else {
+ host = string(uri + 12, slash - (uri + 12));
+ path = slash;
+ }
+
+ char *colon = strchr(host.c_str(), ':');
+ if (colon == NULL) {
+ port = 80;
+ } else {
+ char *end;
+ long tmp = strtol(colon + 1, &end, 10);
+ assert(end > colon + 1);
+ assert(tmp > 0 && tmp < 65536);
+ port = tmp;
+
+ host = string(host, 0, colon - host.c_str());
+ }
+
+ LOGI("Connecting to host '%s', port %d, path '%s'",
+ host.c_str(), port, path.c_str());
+
+ HTTPStream *http = new HTTPStream;
+ int http_status;
+
+ for (;;) {
+ status_t err = http->connect(host.c_str(), port);
+ assert(err == OK);
+
+ err = http->send("GET ");
+ err = http->send(path.c_str());
+ err = http->send(" HTTP/1.1\r\n");
+ err = http->send("Host: ");
+ err = http->send(host.c_str());
+ err = http->send("\r\n");
+ err = http->send("Icy-MetaData: 1\r\n\r\n");
+
+ assert(OK == http->receive_header(&http_status));
+
+ if (http_status == 301 || http_status == 302) {
+ string location;
+ assert(http->find_header_value("Location", &location));
+
+ assert(string(location, 0, 7) == "http://");
+ location.erase(0, 7);
+ string::size_type slashPos = location.find('/');
+ if (slashPos == string::npos) {
+ slashPos = location.size();
+ location += '/';
+ }
+
+ http->disconnect();
+
+ LOGI("Redirecting to %s\n", location.c_str());
+
+ host = string(location, 0, slashPos);
+
+ string::size_type colonPos = host.find(':');
+ if (colonPos != string::npos) {
+ const char *start = host.c_str() + colonPos + 1;
+ char *end;
+ long tmp = strtol(start, &end, 10);
+ assert(end > start && *end == '\0');
+
+ port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
+ } else {
+ port = 80;
+ }
+
+ path = string(location, slashPos);
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (http_status != 200) {
+ LOGE("Connection failed: http_status = %d", http_status);
+ return NULL;
+ }
+
+ MediaSource *source = new ShoutcastSource(http);
+
+ return source;
+}
+
+bool MediaPlayerImpl::isPlaying() const {
+ return mPlaying && !mPaused;
+}
+
+int64_t MediaPlayerImpl::getDuration() {
+ return mDuration;
+}
+
+int64_t MediaPlayerImpl::getPosition() {
+ int64_t position = 0;
+ if (mVideoSource != NULL) {
+ Mutex::Autolock autoLock(mLock);
+ position = mVideoPosition;
+ } else if (mAudioPlayer != NULL) {
+ position = mAudioPlayer->getMediaTimeUs();
+ }
+
+ return position;
+}
+
+status_t MediaPlayerImpl::seekTo(int64_t time) {
+ LOGI("seekTo %lld", time);
+
+ if (mPaused) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mVideoSource == NULL && mAudioPlayer != NULL) {
+ mAudioPlayer->seekTo(time);
+ } else {
+ Mutex::Autolock autoLock(mLock);
+ mSeekTimeUs = time;
+ mSeeking = true;
+ }
+
+ return OK;
+}
+
+void MediaPlayerImpl::populateISurface() {
+ if (mVideoSource == NULL) {
+ return;
+ }
+
+ sp<MetaData> meta = mVideoDecoder->getFormat();
+
+ int32_t format;
+ const char *component;
+ int32_t decodedWidth, decodedHeight;
+ bool success = meta->findInt32(kKeyColorFormat, &format);
+ success = success && meta->findCString(kKeyDecoderComponent, &component);
+ success = success && meta->findInt32(kKeyWidth, &decodedWidth);
+ success = success && meta->findInt32(kKeyHeight, &decodedHeight);
+ assert(success);
+
+ if (mSurface.get() != NULL) {
+ mVideoRenderer =
+ mClient.interface()->createRenderer(
+ mSurface, component,
+ (OMX_COLOR_FORMATTYPE)format,
+ decodedWidth, decodedHeight,
+ mVideoWidth, mVideoHeight);
+ } else {
+ mVideoRenderer =
+ mClient.interface()->createRenderer(
+ mISurface, component,
+ (OMX_COLOR_FORMATTYPE)format,
+ decodedWidth, decodedHeight,
+ mVideoWidth, mVideoHeight);
+ }
+}
+
+void MediaPlayerImpl::depopulateISurface() {
+ mVideoRenderer.clear();
+}
+
+void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
+ void *id;
+ if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
+ mVideoRenderer->render((IOMX::buffer_id)id);
+ }
+}
+
+void MediaPlayerImpl::setAudioSink(
+ const sp<MediaPlayerBase::AudioSink> &audioSink) {
+ LOGI("setAudioSink %p", audioSink.get());
+ mAudioSink = audioSink;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
new file mode 100644
index 0000000..ec89b74
--- /dev/null
+++ b/media/libstagefright/MediaSource.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(int64_t *time_us) const {
+ *time_us = mSeekTimeUs;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
new file mode 100644
index 0000000..5d23732b
--- /dev/null
+++ b/media/libstagefright/MetaData.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+MetaData::MetaData() {
+}
+
+MetaData::MetaData(const MetaData &from)
+ : RefBase(),
+ mItems(from.mItems) {
+}
+
+MetaData::~MetaData() {
+ clear();
+}
+
+void MetaData::clear() {
+ mItems.clear();
+}
+
+bool MetaData::remove(uint32_t key) {
+ ssize_t i = mItems.indexOfKey(key);
+
+ if (i < 0) {
+ return false;
+ }
+
+ mItems.removeItemsAt(i);
+
+ return true;
+}
+
+bool MetaData::setCString(uint32_t key, const char *value) {
+ return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
+}
+
+bool MetaData::setInt32(uint32_t key, int32_t value) {
+ return setData(key, TYPE_INT32, &value, sizeof(value));
+}
+
+bool MetaData::setFloat(uint32_t key, float value) {
+ return setData(key, TYPE_FLOAT, &value, sizeof(value));
+}
+
+bool MetaData::setPointer(uint32_t key, void *value) {
+ return setData(key, TYPE_POINTER, &value, sizeof(value));
+}
+
+bool MetaData::findCString(uint32_t key, const char **value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
+ return false;
+ }
+
+ *value = (const char *)data;
+
+ return true;
+}
+
+bool MetaData::findInt32(uint32_t key, int32_t *value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
+ return false;
+ }
+
+ assert(size == sizeof(*value));
+
+ *value = *(int32_t *)data;
+
+ return true;
+}
+
+bool MetaData::findFloat(uint32_t key, float *value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
+ return false;
+ }
+
+ assert(size == sizeof(*value));
+
+ *value = *(float *)data;
+
+ return true;
+}
+
+bool MetaData::findPointer(uint32_t key, void **value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
+ return false;
+ }
+
+ assert(size == sizeof(*value));
+
+ *value = *(void **)data;
+
+ return true;
+}
+
+bool MetaData::setData(
+ uint32_t key, uint32_t type, const void *data, size_t size) {
+ bool overwrote_existing = true;
+
+ ssize_t i = mItems.indexOfKey(key);
+ if (i < 0) {
+ typed_data item;
+ i = mItems.add(key, item);
+
+ overwrote_existing = false;
+ }
+
+ typed_data &item = mItems.editValueAt(i);
+
+ item.setData(type, data, size);
+
+ return overwrote_existing;
+}
+
+bool MetaData::findData(uint32_t key, uint32_t *type,
+ const void **data, size_t *size) const {
+ ssize_t i = mItems.indexOfKey(key);
+
+ if (i < 0) {
+ return false;
+ }
+
+ const typed_data &item = mItems.valueAt(i);
+
+ item.getData(type, data, size);
+
+ return true;
+}
+
+MetaData::typed_data::typed_data()
+ : mType(0),
+ mSize(0) {
+}
+
+MetaData::typed_data::~typed_data() {
+ clear();
+}
+
+MetaData::typed_data::typed_data(const typed_data &from)
+ : mType(from.mType),
+ mSize(0) {
+ allocateStorage(from.mSize);
+ memcpy(storage(), from.storage(), mSize);
+}
+
+MetaData::typed_data &MetaData::typed_data::operator=(
+ const MetaData::typed_data &from) {
+ if (this != &from) {
+ clear();
+ mType = from.mType;
+ allocateStorage(from.mSize);
+ memcpy(storage(), from.storage(), mSize);
+ }
+
+ return *this;
+}
+
+void MetaData::typed_data::clear() {
+ freeStorage();
+
+ mType = 0;
+}
+
+void MetaData::typed_data::setData(
+ uint32_t type, const void *data, size_t size) {
+ clear();
+
+ mType = type;
+ allocateStorage(size);
+ memcpy(storage(), data, size);
+}
+
+void MetaData::typed_data::getData(
+ uint32_t *type, const void **data, size_t *size) const {
+ *type = mType;
+ *size = mSize;
+ *data = storage();
+}
+
+void MetaData::typed_data::allocateStorage(size_t size) {
+ mSize = size;
+
+ if (usesReservoir()) {
+ return;
+ }
+
+ u.ext_data = malloc(mSize);
+}
+
+void MetaData::typed_data::freeStorage() {
+ if (!usesReservoir()) {
+ if (u.ext_data) {
+ free(u.ext_data);
+ }
+ }
+
+ mSize = 0;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
new file mode 100644
index 0000000..7cb861c
--- /dev/null
+++ b/media/libstagefright/MmapSource.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "MmapSource"
+#include <utils/Log.h>
+
+#include <sys/mman.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/MmapSource.h>
+
+namespace android {
+
+MmapSource::MmapSource(const char *filename)
+ : mFd(open(filename, O_RDONLY)),
+ mBase(NULL),
+ mSize(0) {
+ LOGV("MmapSource '%s'", filename);
+ assert(mFd >= 0);
+
+ off_t size = lseek(mFd, 0, SEEK_END);
+ mSize = (size_t)size;
+
+ mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, 0);
+
+ if (mBase == (void *)-1) {
+ mBase = NULL;
+
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+MmapSource::MmapSource(int fd, int64_t offset, int64_t length)
+ : mFd(fd),
+ mBase(NULL),
+ mSize(length) {
+ LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length);
+ assert(fd >= 0);
+
+ mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset);
+
+ if (mBase == (void *)-1) {
+ mBase = NULL;
+
+ close(mFd);
+ mFd = -1;
+ }
+
+}
+
+MmapSource::~MmapSource() {
+ if (mFd != -1) {
+ munmap(mBase, mSize);
+ mBase = NULL;
+ mSize = 0;
+
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t MmapSource::InitCheck() const {
+ return mFd == -1 ? NO_INIT : OK;
+}
+
+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);
+
+ size_t avail = 0;
+ if (offset >= 0 && offset < (off_t)mSize) {
+ avail = mSize - offset;
+ }
+
+ if (size > avail) {
+ size = avail;
+ }
+
+ memcpy(data, (const uint8_t *)mBase + offset, size);
+
+ return (ssize_t)size;
+}
+
+status_t MmapSource::getSize(off_t *size) {
+ *size = mSize;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
new file mode 100644
index 0000000..5423ffa
--- /dev/null
+++ b/media/libstagefright/OMXClient.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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 "OMXClient"
+#include <utils/Log.h>
+
+#include <sys/socket.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/stagefright/OMXClient.h>
+
+namespace android {
+
+OMXClient::OMXClient() {
+}
+
+OMXClient::~OMXClient() {
+ disconnect();
+}
+
+status_t OMXClient::connect() {
+ Mutex::Autolock autoLock(mLock);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ assert(service.get() != NULL);
+
+ mOMX = service->createOMX();
+ assert(mOMX.get() != NULL);
+
+ mReflector = new OMXClientReflector(this);
+
+ return OK;
+}
+
+void OMXClient::disconnect() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mReflector.get() != NULL) {
+ return;
+ }
+
+ assert(mObservers.isEmpty());
+
+ mReflector->reset();
+ mReflector.clear();
+}
+
+status_t OMXClient::registerObserver(
+ IOMX::node_id node, OMXObserver *observer) {
+ Mutex::Autolock autoLock(&mLock);
+
+ ssize_t index = mObservers.indexOfKey(node);
+ if (index >= 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ mObservers.add(node, observer);
+ observer->start();
+
+ mOMX->observe_node(node, mReflector);
+
+ return OK;
+}
+
+void OMXClient::unregisterObserver(IOMX::node_id node) {
+ Mutex::Autolock autoLock(mLock);
+
+ ssize_t index = mObservers.indexOfKey(node);
+ assert(index >= 0);
+
+ if (index < 0) {
+ return;
+ }
+
+ OMXObserver *observer = mObservers.valueAt(index);
+ observer->stop();
+ mObservers.removeItemsAt(index);
+}
+
+bool OMXClient::onOMXMessage(const omx_message &msg) {
+ bool done = false;
+
+ switch (msg.type) {
+ case omx_message::EVENT:
+ {
+ LOGV("OnEvent node:%p event:%d data1:%ld data2:%ld",
+ msg.u.event_data.node,
+ msg.u.event_data.event,
+ msg.u.event_data.data1,
+ msg.u.event_data.data2);
+
+ break;
+ }
+
+ case omx_message::FILL_BUFFER_DONE:
+ {
+ LOGV("FillBufferDone %p", msg.u.extended_buffer_data.buffer);
+ break;
+ }
+
+ case omx_message::EMPTY_BUFFER_DONE:
+ {
+ LOGV("EmptyBufferDone %p", msg.u.buffer_data.buffer);
+ break;
+ }
+
+ default:
+ LOGE("received unknown omx_message type %d", msg.type);
+ break;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ ssize_t index = mObservers.indexOfKey(msg.node);
+
+ if (index >= 0) {
+ mObservers.editValueAt(index)->postMessage(msg);
+ }
+
+ return done;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMXObserver::OMXObserver() {
+}
+
+OMXObserver::~OMXObserver() {
+}
+
+void OMXObserver::start() {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+ assert(err == 0);
+
+ pthread_attr_destroy(&attr);
+}
+
+void OMXObserver::stop() {
+ omx_message msg;
+ msg.type = omx_message::QUIT_OBSERVER;
+ postMessage(msg);
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+}
+
+void OMXObserver::postMessage(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+ mQueue.push_back(msg);
+ mQueueNotEmpty.signal();
+}
+
+// static
+void *OMXObserver::ThreadWrapper(void *me) {
+ static_cast<OMXObserver *>(me)->threadEntry();
+
+ return NULL;
+}
+
+void OMXObserver::threadEntry() {
+ for (;;) {
+ omx_message msg;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ while (mQueue.empty()) {
+ mQueueNotEmpty.wait(mLock);
+ }
+
+ msg = *mQueue.begin();
+ mQueue.erase(mQueue.begin());
+ }
+
+ if (msg.type == omx_message::QUIT_OBSERVER) {
+ break;
+ }
+
+ onOMXMessage(msg);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMXClientReflector::OMXClientReflector(OMXClient *client)
+ : mClient(client) {
+}
+
+void OMXClientReflector::on_message(const omx_message &msg) {
+ if (mClient != NULL) {
+ mClient->onOMXMessage(msg);
+ }
+}
+
+void OMXClientReflector::reset() {
+ mClient = NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
new file mode 100644
index 0000000..35d599c
--- /dev/null
+++ b/media/libstagefright/OMXCodec.cpp
@@ -0,0 +1,1962 @@
+/*
+ * 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 <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;
+}
+
+// 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 |= kWantsRawNALFrames;
+ }
+ if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ 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);
+
+ const uint8_t *ptr = (const uint8_t *)data + 6;
+ size -= 6;
+ while (size >= 2) {
+ size_t length = ptr[0] << 8 | ptr[1];
+
+ ptr += 2;
+ size -= 2;
+
+ // printf("length = %d, size = %d\n", length, size);
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+
+ if (size <= 1) {
+ break;
+ }
+
+ ptr++; // XXX skip trailing 0x01 byte???
+ --size;
+ }
+ }
+
+ 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);
+ assert(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);
+ assert(success);
+
+ codec->setImageOutputFormat(format, width, height);
+ }
+
+ 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.
+ // assert(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 (!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);
+ }
+
+ 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),
+ mDealer(new MemoryDealer(5 * 1024 * 1024)),
+ 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_EQ(mState, LOADED);
+
+ 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;
+ }
+
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ sp<IMemory> mem = mDealer->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 {
+ 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 (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) {
+ flushPortAsync(portIndex);
+ } else {
+ disablePortAsync(portIndex);
+ }
+}
+
+void OMXCodec::flushPortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ CHECK_EQ(mPortStatus[portIndex], ENABLED);
+ mPortStatus[portIndex] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+ CHECK_EQ(err, OK);
+}
+
+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(mMIME, "video/avc")
+ && !(mQuirks & kWantsRawNALFrames)) {
+ 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);
+
+ 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;
+ }
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ ////
+
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
+ imageDef->nFrameWidth = width;
+ imageDef->nFrameHeight = height;
+
+ def.nBufferSize = 128 * 1024;
+ 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 (!strcasecmp(mMIME, "video/avc") && !(mQuirks & kWantsRawNALFrames)) {
+ params->setInt32(kKeyNeedsNALFraming, 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() {
+ LOGI("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);
+
+ flushPortAsync(kPortIndexInput);
+ flushPortAsync(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
new file mode 100644
index 0000000..94cca43
--- /dev/null
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -0,0 +1,1651 @@
+/*
+ * 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 "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/MetaData.h>
+#include <media/stagefright/OMXDecoder.h>
+
+namespace android {
+
+class OMXMediaBuffer : public MediaBuffer {
+public:
+ OMXMediaBuffer(IOMX::buffer_id buffer_id, const sp<IMemory> &mem)
+ : MediaBuffer(mem->pointer(),
+ mem->size()),
+ mBufferID(buffer_id),
+ mMem(mem) {
+ }
+
+ IOMX::buffer_id buffer_id() const { return mBufferID; }
+
+private:
+ IOMX::buffer_id mBufferID;
+ sp<IMemory> mMem;
+
+ OMXMediaBuffer(const OMXMediaBuffer &);
+ OMXMediaBuffer &operator=(const OMXMediaBuffer &);
+};
+
+struct CodecInfo {
+ const char *mime;
+ const char *codec;
+};
+
+static const CodecInfo kDecoderInfo[] = {
+ { "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.PV.amrencnb" },
+ { "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" },
+};
+
+static const char *GetCodec(const CodecInfo *info, size_t numInfos,
+ const char *mime, int index) {
+ assert(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;
+}
+
+// static
+sp<OMXDecoder> OMXDecoder::Create(
+ OMXClient *client, const sp<MetaData> &meta,
+ bool createEncoder,
+ const sp<MediaSource> &source) {
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ assert(success);
+
+ sp<IOMX> omx = client->interface();
+
+ const char *codec = NULL;
+ IOMX::node_id node = 0;
+ for (int index = 0;; ++index) {
+ if (createEncoder) {
+ codec = GetCodec(
+ kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ codec = GetCodec(
+ kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
+
+ if (!codec) {
+ return NULL;
+ }
+
+ LOGI("Attempting to allocate OMX node '%s'", codec);
+
+ status_t err = omx->allocate_node(codec, &node);
+ if (err == OK) {
+ break;
+ }
+ }
+
+ uint32_t quirks = 0;
+ if (!strcmp(codec, "OMX.PV.avcdec")) {
+ quirks |= kWantsRawNALFrames;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")
+ || !strcmp(codec, "OMX.TI.MP3.decode")) {
+ quirks |= kDoesntReturnBuffersOnDisable;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+ quirks |= kDoesntFlushOnExecutingToIdle;
+ quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ }
+
+ 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);
+
+ 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);
+
+ decoder->addCodecSpecificData(
+ codec_specific_data, codec_specific_data_size);
+ } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ printf("found avcc of size %d\n", size);
+
+ const uint8_t *ptr = (const uint8_t *)data + 6;
+ size -= 6;
+ while (size >= 2) {
+ size_t length = ptr[0] << 8 | ptr[1];
+
+ ptr += 2;
+ size -= 2;
+
+ // printf("length = %d, size = %d\n", length, size);
+
+ assert(size >= length);
+
+ decoder->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+
+ if (size <= 1) {
+ break;
+ }
+
+ ptr++; // XXX skip trailing 0x01 byte???
+ --size;
+ }
+ }
+
+ return decoder;
+}
+
+OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
+ const char *mime, const char *codec,
+ bool is_encoder,
+ uint32_t quirks,
+ const sp<MediaSource> &source)
+ : mClient(client),
+ mOMX(mClient->interface()),
+ mNode(node),
+ mComponentName(strdup(codec)),
+ mMIME(strdup(mime)),
+ mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+ mIsAVC(!strcasecmp(mime, "video/avc")),
+ mIsEncoder(is_encoder),
+ mQuirks(quirks),
+ mSource(source),
+ mCodecSpecificDataIterator(mCodecSpecificData.begin()),
+ mState(OMX_StateLoaded),
+ mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
+ mShutdownInitiated(false),
+ mDealer(new MemoryDealer(5 * 1024 * 1024)),
+ mSeeking(false),
+ mStarted(false),
+ mErrorCondition(OK),
+ mReachedEndOfInput(false) {
+ mClient->registerObserver(mNode, this);
+
+ mBuffers.push(); // input buffers
+ mBuffers.push(); // output buffers
+
+ setup();
+}
+
+OMXDecoder::~OMXDecoder() {
+ if (mStarted) {
+ stop();
+ }
+
+ for (List<CodecSpecificData>::iterator it = mCodecSpecificData.begin();
+ it != mCodecSpecificData.end(); ++it) {
+ free((*it).data);
+ }
+ mCodecSpecificData.clear();
+
+ mClient->unregisterObserver(mNode);
+
+ status_t err = mOMX->free_node(mNode);
+ assert(err == OK);
+ mNode = 0;
+
+ free(mMIME);
+ mMIME = NULL;
+
+ free(mComponentName);
+ mComponentName = NULL;
+}
+
+status_t OMXDecoder::start(MetaData *) {
+ assert(!mStarted);
+
+ // mDealer->dump("Decoder Dealer");
+
+ sp<MetaData> params = new MetaData;
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
+ params->setInt32(kKeyNeedsNALFraming, true);
+ }
+
+ status_t err = mSource->start(params.get());
+
+ if (err != OK) {
+ return err;
+ }
+
+ postStart();
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t OMXDecoder::stop() {
+ assert(mStarted);
+
+ LOGI("Initiating OMX Node shutdown, busy polling.");
+ initiateShutdown();
+
+ // Important: initiateShutdown must be called first, _then_ release
+ // buffers we're holding onto.
+ while (!mOutputBuffers.empty()) {
+ MediaBuffer *buffer = *mOutputBuffers.begin();
+ mOutputBuffers.erase(mOutputBuffers.begin());
+
+ LOGV("releasing buffer %p.", buffer->data());
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ int attempt = 1;
+ while (mState != OMX_StateLoaded && attempt < 20) {
+ usleep(100000);
+
+ ++attempt;
+ }
+
+ if (mState != OMX_StateLoaded) {
+ LOGE("!!! OMX Node '%s' did NOT shutdown cleanly !!!", mComponentName);
+ } else {
+ LOGI("OMX Node '%s' has shutdown cleanly.", mComponentName);
+ }
+
+ mSource->stop();
+
+ mCodecSpecificDataIterator = mCodecSpecificData.begin();
+ mShutdownInitiated = false;
+ mSeeking = false;
+ mStarted = false;
+ mErrorCondition = OK;
+ mReachedEndOfInput = false;
+
+ return OK;
+}
+
+sp<MetaData> OMXDecoder::getFormat() {
+ return mOutputFormat;
+}
+
+status_t OMXDecoder::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ assert(mStarted);
+
+ *out = NULL;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mErrorCondition != OK && mErrorCondition != ERROR_END_OF_STREAM) {
+ // Errors are sticky.
+ return mErrorCondition;
+ }
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ LOGI("[%s] seeking to %lld us", mComponentName, seekTimeUs);
+
+ mErrorCondition = OK;
+ mReachedEndOfInput = false;
+
+ setPortStatus(kPortIndexInput, kPortStatusFlushing);
+ setPortStatus(kPortIndexOutput, kPortStatusFlushing);
+
+ mSeeking = true;
+ mSeekTimeUs = seekTimeUs;
+
+ while (!mOutputBuffers.empty()) {
+ OMXMediaBuffer *buffer =
+ static_cast<OMXMediaBuffer *>(*mOutputBuffers.begin());
+
+ // We could have used buffer->release() instead, but we're
+ // holding the lock and signalBufferReturned attempts to acquire
+ // the lock.
+ buffer->claim();
+ mBuffers.editItemAt(
+ kPortIndexOutput).push_back(buffer->buffer_id());
+ buffer = NULL;
+
+ mOutputBuffers.erase(mOutputBuffers.begin());
+ }
+
+ // XXX One of TI's decoders appears to ignore a flush if it doesn't
+ // currently hold on to any buffers on the port in question and
+ // never sends the completion event... FIXME
+
+ status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+ assert(err == OK);
+
+ // Once flushing is completed buffers will again be scheduled to be
+ // filled/emptied.
+ }
+
+ while (mErrorCondition == OK && mOutputBuffers.empty()) {
+ mOutputBufferAvailable.wait(mLock);
+ }
+
+ if (!mOutputBuffers.empty()) {
+ MediaBuffer *buffer = *mOutputBuffers.begin();
+ mOutputBuffers.erase(mOutputBuffers.begin());
+
+ *out = buffer;
+
+ return OK;
+ } else {
+ assert(mErrorCondition != OK);
+ return mErrorCondition;
+ }
+}
+
+void OMXDecoder::addCodecSpecificData(const void *data, size_t size) {
+ CodecSpecificData specific;
+ specific.data = malloc(size);
+ memcpy(specific.data, data, size);
+ specific.size = size;
+
+ mCodecSpecificData.push_back(specific);
+ mCodecSpecificDataIterator = mCodecSpecificData.begin();
+}
+
+void OMXDecoder::onOMXMessage(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+
+ switch (msg.type) {
+ case omx_message::START:
+ {
+ onStart();
+ break;
+ }
+
+ 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:
+ {
+ onEmptyBufferDone(msg.u.buffer_data.buffer);
+ break;
+ }
+
+ case omx_message::FILL_BUFFER_DONE:
+ case omx_message::INITIAL_FILL_BUFFER:
+ {
+ onFillBufferDone(msg);
+ break;
+ }
+
+ default:
+ LOGE("received unknown omx_message type %d", msg.type);
+ break;
+ }
+}
+
+void OMXDecoder::setAMRFormat() {
+ 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));
+
+ assert(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);
+}
+
+void OMXDecoder::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));
+ assert(err == NO_ERROR);
+
+ def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+ assert(err == NO_ERROR);
+}
+
+status_t OMXDecoder::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.
+ // assert(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 OMXDecoder::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", mMIME)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mMIME)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mMIME)) {
+ 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.");
+ }
+
+ 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));
+
+ assert(err == NO_ERROR);
+
+ assert(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));
+ assert(err == NO_ERROR);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ 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));
+ assert(err == NO_ERROR);
+
+ def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
+ LOGI("setting nBufferSize = %ld", def.nBufferSize);
+
+ assert(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));
+ assert(err == NO_ERROR);
+}
+
+void OMXDecoder::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 1
+ // 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 (!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));
+ assert(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);
+ assert(!"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));
+ assert(err == OK);
+
+ assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ assert(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));
+ assert(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));
+
+ assert(err == NO_ERROR);
+
+#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
+
+ assert(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));
+ assert(err == NO_ERROR);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ 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));
+ assert(err == NO_ERROR);
+
+ assert(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));
+ assert(err == NO_ERROR);
+}
+
+void OMXDecoder::setup() {
+ const sp<MetaData> &meta = mSource->getFormat();
+
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ assert(success);
+
+ if (!strcasecmp(mime, "audio/3gpp")) {
+ setAMRFormat();
+ } else if (!strcasecmp(mime, "audio/mp4a-latm")) {
+ setAACFormat();
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ int32_t width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+ assert(success);
+
+ if (mIsEncoder) {
+ setVideoInputFormat(mime, width, height);
+ } else {
+ setVideoOutputFormat(mime, width, height);
+ }
+ }
+
+ // dumpPortDefinition(0);
+ // dumpPortDefinition(1);
+
+ 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));
+ assert(err == NO_ERROR);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+
+ assert(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));
+ assert(err == OK);
+
+ assert(params.eNumData == OMX_NumericalDataSigned);
+ assert(params.nBitPerSample == 16);
+ assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+
+ int32_t numChannels, sampleRate;
+ meta->findInt32(kKeyChannelCount, &numChannels);
+ meta->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 {
+ assert(!"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:
+ {
+ assert(!"should not be here, neither audio nor video.");
+ break;
+ }
+ }
+}
+
+void OMXDecoder::onStart() {
+ if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ assert(err == NO_ERROR);
+ }
+
+ allocateBuffers(kPortIndexInput);
+ allocateBuffers(kPortIndexOutput);
+
+ if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
+ // XXX this should happen before AllocateBuffers, but qcom's
+ // h264 vdec disagrees.
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ assert(err == NO_ERROR);
+ }
+}
+
+void OMXDecoder::allocateBuffers(OMX_U32 port_index) {
+ assert(mBuffers[port_index].empty());
+
+ OMX_U32 num_buffers;
+ OMX_U32 buffer_size;
+
+ 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 = port_index;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == NO_ERROR);
+
+ num_buffers = def.nBufferCountActual;
+ buffer_size = def.nBufferSize;
+
+ LOGV("[%s] port %ld: allocating %ld buffers of size %ld each\n",
+ mComponentName, port_index, num_buffers, buffer_size);
+
+ for (OMX_U32 i = 0; i < num_buffers; ++i) {
+ sp<IMemory> mem = mDealer->allocate(buffer_size);
+ if (mem.get() == NULL) {
+ LOGE("[%s] allocating IMemory of size %ld FAILED.",
+ mComponentName, buffer_size);
+ }
+ assert(mem.get() != NULL);
+
+ IOMX::buffer_id buffer;
+ status_t err;
+
+ if (port_index == kPortIndexInput
+ && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+ // qcom's H.263 encoder appears to want to allocate its own input
+ // buffers.
+ err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
+ if (err != OK) {
+ LOGE("[%s] allocate_buffer_with_backup failed with error %d",
+ mComponentName, err);
+ }
+ } else if (port_index == kPortIndexOutput
+ && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
+#if 1
+ err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
+#else
+ // XXX This is fine as long as we are either running the player
+ // inside the media server process or we are using the
+ // QComHardwareRenderer to output the frames.
+ err = mOMX->allocate_buffer(mNode, port_index, buffer_size, &buffer);
+#endif
+ if (err != OK) {
+ LOGE("[%s] allocate_buffer_with_backup failed with error %d",
+ mComponentName, err);
+ }
+ } else {
+ err = mOMX->use_buffer(mNode, port_index, mem, &buffer);
+ if (err != OK) {
+ LOGE("[%s] use_buffer failed with error %d",
+ mComponentName, err);
+ }
+ }
+ assert(err == OK);
+
+ LOGV("allocated %s buffer %p.",
+ port_index == kPortIndexInput ? "INPUT" : "OUTPUT",
+ buffer);
+
+ mBuffers.editItemAt(port_index).push_back(buffer);
+ mBufferMap.add(buffer, mem);
+
+ if (port_index == kPortIndexOutput) {
+ OMXMediaBuffer *media_buffer = new OMXMediaBuffer(buffer, mem);
+ media_buffer->setObserver(this);
+
+ mMediaBufferMap.add(buffer, media_buffer);
+ }
+ }
+
+ LOGV("allocate %s buffers done.",
+ port_index == kPortIndexInput ? "INPUT" : "OUTPUT");
+}
+
+void OMXDecoder::onEvent(
+ OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+ LOGV("[%s] onEvent event=%d, data1=%ld, data2=%ld",
+ mComponentName, event, data1, data2);
+
+ switch (event) {
+ case OMX_EventCmdComplete: {
+ onEventCmdComplete(
+ static_cast<OMX_COMMANDTYPE>(data1), data2);
+
+ break;
+ }
+
+ case OMX_EventPortSettingsChanged: {
+ onEventPortSettingsChanged(data1);
+ break;
+ }
+
+ case OMX_EventBufferFlag: {
+ // initiateShutdown();
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) {
+ switch (type) {
+ case OMX_CommandStateSet: {
+ OMX_STATETYPE state = static_cast<OMX_STATETYPE>(data);
+ onStateChanged(state);
+ break;
+ }
+
+ case OMX_CommandPortDisable: {
+ OMX_U32 port_index = data;
+ assert(getPortStatus(port_index) == kPortStatusDisabled);
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandPortEnable, port_index);
+
+ allocateBuffers(port_index);
+
+ break;
+ }
+
+ case OMX_CommandPortEnable: {
+ OMX_U32 port_index = data;
+ assert(getPortStatus(port_index) ==kPortStatusDisabled);
+ setPortStatus(port_index, kPortStatusActive);
+
+ assert(port_index == kPortIndexOutput);
+
+ BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
+ while (!obuffers->empty()) {
+ IOMX::buffer_id buffer = *obuffers->begin();
+ obuffers->erase(obuffers->begin());
+
+ mOMX->fill_buffer(mNode, buffer);
+ }
+
+ break;
+ }
+
+ case OMX_CommandFlush: {
+ OMX_U32 port_index = data;
+ LOGV("Port %ld flush complete.", port_index);
+
+ PortStatus status = getPortStatus(port_index);
+
+ assert(status == kPortStatusFlushing
+ || status == kPortStatusFlushingToDisabled
+ || status == kPortStatusFlushingToShutdown);
+
+ switch (status) {
+ case kPortStatusFlushing:
+ {
+ // This happens when we're flushing before a seek.
+ setPortStatus(port_index, kPortStatusActive);
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ postEmptyBufferDone(buffer);
+ } else {
+ postInitialFillBuffer(buffer);
+ }
+ }
+ break;
+ }
+
+ case kPortStatusFlushingToDisabled:
+ {
+ // Port settings have changed and the (buggy) OMX component
+ // does not properly return buffers on disabling, we need to
+ // do a flush first and _then_ disable the port in question.
+
+ setPortStatus(port_index, kPortStatusDisabled);
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandPortDisable, port_index);
+ assert(err == OK);
+
+ freePortBuffers(port_index);
+ break;
+ }
+
+ default:
+ {
+ assert(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);
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
+ assert(getPortStatus(port_index) == kPortStatusActive);
+
+ status_t err;
+
+ if (mQuirks & kDoesntReturnBuffersOnDisable) {
+ // Decoder does not properly return our buffers when disabled...
+ // Need to flush port instead and _then_ disable.
+
+ setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+ } else {
+ setPortStatus(port_index, kPortStatusDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+ }
+
+ assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onStateChanged(OMX_STATETYPE to) {
+ if (mState == OMX_StateLoaded) {
+ assert(to == OMX_StateIdle);
+
+ mState = to;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateExecuting);
+ assert(err == NO_ERROR);
+ } else if (mState == OMX_StateIdle) {
+ if (to == OMX_StateExecuting) {
+ mState = to;
+
+ BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
+ while (!ibuffers->empty()) {
+ IOMX::buffer_id buffer = *ibuffers->begin();
+ ibuffers->erase(ibuffers->begin());
+
+ postEmptyBufferDone(buffer);
+ }
+
+ BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
+ while (!obuffers->empty()) {
+ IOMX::buffer_id buffer = *obuffers->begin();
+ obuffers->erase(obuffers->begin());
+
+ postInitialFillBuffer(buffer);
+ }
+ } else {
+ assert(to == OMX_StateLoaded);
+
+ mState = to;
+
+ setPortStatus(kPortIndexInput, kPortStatusActive);
+ setPortStatus(kPortIndexOutput, kPortStatusActive);
+ }
+ } else if (mState == OMX_StateExecuting) {
+ assert(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);
+
+ freePortBuffers(kPortIndexInput);
+ freePortBuffers(kPortIndexOutput);
+ }
+}
+
+void OMXDecoder::initiateShutdown() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mShutdownInitiated) {
+ return;
+ }
+
+ if (mState == OMX_StateLoaded) {
+ return;
+ }
+
+ assert(mState == OMX_StateExecuting);
+
+ mShutdownInitiated = true;
+
+ status_t err;
+ if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+ if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+ assert(err == OK);
+
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+ } else {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+ }
+
+ setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+ } else {
+ err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+ setPortStatus(kPortIndexInput, kPortStatusShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+ }
+ assert(err == OK);
+}
+
+void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
+ int shift = 3 * port_index;
+
+ mPortStatusMask &= ~(7 << shift);
+ mPortStatusMask |= status << shift;
+}
+
+OMXDecoder::PortStatus OMXDecoder::getPortStatus(
+ OMX_U32 port_index) const {
+ int shift = 3 * port_index;
+
+ return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
+}
+
+void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
+ LOGV("[%s] onEmptyBufferDone (%p)", mComponentName, buffer);
+
+ status_t err;
+ switch (getPortStatus(kPortIndexInput)) {
+ case kPortStatusDisabled:
+ freeInputBuffer(buffer);
+ err = NO_ERROR;
+ break;
+
+ case kPortStatusShutdown:
+ LOGV("We're shutting down, enqueue INPUT buffer %p.", buffer);
+ mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+ err = NO_ERROR;
+ break;
+
+ case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
+ LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
+ mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+ err = NO_ERROR;
+ break;
+
+ default:
+ onRealEmptyBufferDone(buffer);
+ err = NO_ERROR;
+ break;
+ }
+ assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onFillBufferDone(const omx_message &msg) {
+ IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+
+ LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+ msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+ buffer, msg.u.extended_buffer_data.range_length);
+
+ status_t err;
+ switch (getPortStatus(kPortIndexOutput)) {
+ case kPortStatusDisabled:
+ freeOutputBuffer(buffer);
+ err = NO_ERROR;
+ break;
+ case kPortStatusShutdown:
+ LOGV("We're shutting down, enqueue OUTPUT buffer %p.", buffer);
+ mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+ err = NO_ERROR;
+ break;
+
+ case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
+ LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
+ mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+ err = NO_ERROR;
+ break;
+
+ default:
+ {
+ if (msg.type == omx_message::INITIAL_FILL_BUFFER) {
+ mOMX->fill_buffer(mNode, buffer);
+ } else {
+ LOGV("[%s] Filled OUTPUT buffer %p, flags=0x%08lx.",
+ mComponentName, buffer, msg.u.extended_buffer_data.flags);
+
+ onRealFillBufferDone(msg);
+ }
+ err = NO_ERROR;
+ break;
+ }
+ }
+ assert(err == NO_ERROR);
+}
+
+void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
+ if (mReachedEndOfInput) {
+ // We already sent the EOS notification.
+
+ mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
+ return;
+ }
+
+ const sp<IMemory> mem = mBufferMap.valueFor(buffer);
+ assert(mem.get() != NULL);
+
+ static const uint8_t kNALStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
+
+ if (mCodecSpecificDataIterator != mCodecSpecificData.end()) {
+ List<CodecSpecificData>::iterator it = mCodecSpecificDataIterator;
+
+ size_t range_length = 0;
+
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
+ assert((*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());
+
+ memcpy((uint8_t *)mem->pointer(), (*it).data, (*it).size);
+ range_length = (*it).size;
+ }
+
+ ++mCodecSpecificDataIterator;
+
+ mOMX->empty_buffer(
+ mNode, buffer, 0, range_length,
+ OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
+ 0);
+
+ return;
+ }
+
+ LOGV("[%s] waiting for input data", mComponentName);
+
+ MediaBuffer *input_buffer;
+ for (;;) {
+ status_t err;
+
+ if (mSeeking) {
+ MediaSource::ReadOptions options;
+ options.setSeekTo(mSeekTimeUs);
+
+ mSeeking = false;
+
+ err = mSource->read(&input_buffer, &options);
+ } else {
+ err = mSource->read(&input_buffer);
+ }
+ assert((err == OK && input_buffer != NULL)
+ || (err != OK && input_buffer == NULL));
+
+ if (err == ERROR_END_OF_STREAM) {
+ LOGE("[%s] Reached end of stream.", mComponentName);
+ mReachedEndOfInput = true;
+ } else {
+ LOGV("[%s] got input data", mComponentName);
+ }
+
+ if (err != OK) {
+ mOMX->empty_buffer(
+ mNode, buffer, 0, 0, OMX_BUFFERFLAG_EOS, 0);
+
+ return;
+ }
+
+ if (mSeeking) {
+ input_buffer->release();
+ input_buffer = NULL;
+
+ continue;
+ }
+
+ break;
+ }
+
+ const uint8_t *src_data =
+ (const uint8_t *)input_buffer->data() + input_buffer->range_offset();
+
+ size_t src_length = input_buffer->range_length();
+ if (src_length == 195840) {
+ // When feeding the output of the AVC decoder into the H263 encoder,
+ // buffer sizes mismatch if width % 16 != 0 || height % 16 != 0.
+ src_length = 194400; // XXX HACK
+ } else if (src_length == 115200) {
+ src_length = 114240; // XXX HACK
+ }
+
+ if (src_length > mem->size()) {
+ LOGE("src_length=%d > mem->size() = %d\n",
+ src_length, mem->size());
+ }
+
+ assert(src_length <= mem->size());
+ memcpy(mem->pointer(), src_data, src_length);
+
+ OMX_U32 flags = 0;
+ if (!mIsMP3) {
+ // Only mp3 audio data may be streamed, all other data is assumed
+ // to be fed into the decoder at frame boundaries.
+ flags |= OMX_BUFFERFLAG_ENDOFFRAME;
+ }
+
+ int32_t units, scale;
+ bool success =
+ input_buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+
+ success = success &&
+ input_buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+
+ OMX_TICKS timestamp = 0;
+
+ if (success) {
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ timestamp = ((OMX_S64)units * 1000) / scale;
+ } else {
+ timestamp = ((OMX_S64)units * 1000000) / scale;
+ }
+ }
+
+ input_buffer->release();
+ input_buffer = NULL;
+
+ LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+ mComponentName, buffer, src_length, flags);
+
+ mOMX->empty_buffer(
+ mNode, buffer, 0, src_length, flags, timestamp);
+}
+
+void OMXDecoder::onRealFillBufferDone(const omx_message &msg) {
+ OMXMediaBuffer *media_buffer =
+ mMediaBufferMap.valueFor(msg.u.extended_buffer_data.buffer);
+
+ media_buffer->set_range(
+ msg.u.extended_buffer_data.range_offset,
+ msg.u.extended_buffer_data.range_length);
+
+ media_buffer->add_ref();
+
+ media_buffer->meta_data()->clear();
+
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ msg.u.extended_buffer_data.timestamp);
+ } else {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+ }
+
+ media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+
+ if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
+ media_buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
+ }
+
+ media_buffer->meta_data()->setPointer(
+ kKeyPlatformPrivate,
+ msg.u.extended_buffer_data.platform_private);
+
+ media_buffer->meta_data()->setPointer(
+ kKeyBufferID,
+ msg.u.extended_buffer_data.buffer);
+
+ if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
+ mErrorCondition = ERROR_END_OF_STREAM;
+ }
+
+ mOutputBuffers.push_back(media_buffer);
+ mOutputBufferAvailable.signal();
+}
+
+void OMXDecoder::signalBufferReturned(MediaBuffer *_buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMXMediaBuffer *media_buffer = static_cast<OMXMediaBuffer *>(_buffer);
+
+ IOMX::buffer_id buffer = media_buffer->buffer_id();
+
+ PortStatus outputStatus = getPortStatus(kPortIndexOutput);
+ if (outputStatus == kPortStatusShutdown
+ || outputStatus == kPortStatusFlushing
+ || outputStatus == kPortStatusFlushingToDisabled
+ || outputStatus == kPortStatusFlushingToShutdown) {
+ mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
+ } else {
+ LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
+
+ mOMX->fill_buffer(mNode, buffer);
+ }
+}
+
+void OMXDecoder::freeInputBuffer(IOMX::buffer_id buffer) {
+ LOGV("freeInputBuffer %p", buffer);
+
+ status_t err = mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+ assert(err == NO_ERROR);
+ mBufferMap.removeItem(buffer);
+
+ LOGV("freeInputBuffer %p done", buffer);
+}
+
+void OMXDecoder::freeOutputBuffer(IOMX::buffer_id buffer) {
+ LOGV("freeOutputBuffer %p", buffer);
+
+ status_t err = mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+ assert(err == NO_ERROR);
+ mBufferMap.removeItem(buffer);
+
+ ssize_t index = mMediaBufferMap.indexOfKey(buffer);
+ assert(index >= 0);
+ MediaBuffer *mbuffer = mMediaBufferMap.editValueAt(index);
+ mMediaBufferMap.removeItemsAt(index);
+ mbuffer->setObserver(NULL);
+ mbuffer->release();
+ mbuffer = NULL;
+
+ LOGV("freeOutputBuffer %p done", buffer);
+}
+
+void OMXDecoder::dumpPortDefinition(OMX_U32 port_index) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = port_index;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == NO_ERROR);
+
+ LOGI("DumpPortDefinition on port %ld", port_index);
+ LOGI("nBufferCountActual = %ld, nBufferCountMin = %ld, nBufferSize = %ld",
+ def.nBufferCountActual, def.nBufferCountMin, def.nBufferSize);
+ switch (def.eDomain) {
+ case OMX_PortDomainAudio:
+ {
+ LOGI("eDomain = AUDIO");
+
+ if (port_index == kPortIndexOutput) {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+ assert(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 = port_index;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params));
+ assert(err == OK);
+
+ assert(params.nChannels == 1 || params.bInterleaved);
+ assert(params.eNumData == OMX_NumericalDataSigned);
+ assert(params.nBitPerSample == 16);
+ assert(params.ePCMMode == OMX_AUDIO_PCMModeLinear);
+
+ LOGI("nChannels = %ld, nSamplingRate = %ld",
+ params.nChannels, params.nSamplingRate);
+ }
+
+ break;
+ }
+
+ case OMX_PortDomainVideo:
+ {
+ LOGI("eDomain = VIDEO");
+
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+ LOGI("nFrameWidth = %ld, nFrameHeight = %ld, nStride = %ld, "
+ "nSliceHeight = %ld",
+ video_def->nFrameWidth, video_def->nFrameHeight,
+ video_def->nStride, video_def->nSliceHeight);
+ LOGI("nBitrate = %ld, xFrameRate = %.2f",
+ video_def->nBitrate, video_def->xFramerate / 65536.0f);
+ LOGI("eCompressionFormat = %d, eColorFormat = %d",
+ video_def->eCompressionFormat, video_def->eColorFormat);
+
+ break;
+ }
+
+ default:
+ LOGI("eDomain = UNKNOWN");
+ break;
+ }
+}
+
+void OMXDecoder::postStart() {
+ omx_message msg;
+ msg.type = omx_message::START;
+ postMessage(msg);
+}
+
+void OMXDecoder::postEmptyBufferDone(IOMX::buffer_id buffer) {
+ omx_message msg;
+ msg.type = omx_message::EMPTY_BUFFER_DONE;
+ msg.node = mNode;
+ msg.u.buffer_data.buffer = buffer;
+ postMessage(msg);
+}
+
+void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) {
+ omx_message msg;
+ msg.type = omx_message::INITIAL_FILL_BUFFER;
+ msg.node = mNode;
+ msg.u.buffer_data.buffer = buffer;
+ postMessage(msg);
+}
+
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ freeInputBuffer(buffer);
+ } else {
+ freeOutputBuffer(buffer);
+ }
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
new file mode 100644
index 0000000..75bfde3
--- /dev/null
+++ b/media/libstagefright/SampleTable.cpp
@@ -0,0 +1,598 @@
+/*
+ * 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_TAG "SampleTable"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
+static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
+static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
+static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+
+SampleTable::SampleTable(const sp<DataSource> &source)
+ : mDataSource(source),
+ mChunkOffsetOffset(-1),
+ mChunkOffsetType(0),
+ mNumChunkOffsets(0),
+ mSampleToChunkOffset(-1),
+ mNumSampleToChunkOffsets(0),
+ mSampleSizeOffset(-1),
+ mSampleSizeFieldSize(0),
+ mDefaultSampleSize(0),
+ mNumSampleSizes(0),
+ mTimeToSampleCount(0),
+ mTimeToSample(NULL),
+ mSyncSampleOffset(-1),
+ mNumSyncSamples(0) {
+}
+
+SampleTable::~SampleTable() {
+ delete[] mTimeToSample;
+ mTimeToSample = NULL;
+}
+
+status_t SampleTable::setChunkOffsetParams(
+ uint32_t type, off_t data_offset, off_t data_size) {
+ if (mChunkOffsetOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ assert(type == kChunkOffsetType32 || type == kChunkOffsetType64);
+
+ mChunkOffsetOffset = data_offset;
+ mChunkOffsetType = type;
+
+ if (data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumChunkOffsets = U32_AT(&header[4]);
+
+ if (mChunkOffsetType == kChunkOffsetType32) {
+ if (data_size < 8 + mNumChunkOffsets * 4) {
+ return ERROR_MALFORMED;
+ }
+ } else {
+ if (data_size < 8 + mNumChunkOffsets * 8) {
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSampleToChunkParams(
+ off_t data_offset, off_t data_size) {
+ if (mSampleToChunkOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ mSampleToChunkOffset = data_offset;
+
+ if (data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumSampleToChunkOffsets = U32_AT(&header[4]);
+
+ if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
+ return ERROR_MALFORMED;
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSampleSizeParams(
+ uint32_t type, off_t data_offset, off_t data_size) {
+ if (mSampleSizeOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ assert(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
+
+ mSampleSizeOffset = data_offset;
+
+ if (data_size < 12) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[12];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mDefaultSampleSize = U32_AT(&header[4]);
+ mNumSampleSizes = U32_AT(&header[8]);
+
+ if (type == kSampleSizeType32) {
+ mSampleSizeFieldSize = 32;
+
+ if (mDefaultSampleSize != 0) {
+ return OK;
+ }
+
+ if (data_size < 12 + mNumSampleSizes * 4) {
+ return ERROR_MALFORMED;
+ }
+ } else {
+ if ((mDefaultSampleSize & 0xffffff00) != 0) {
+ // The high 24 bits are reserved and must be 0.
+ return ERROR_MALFORMED;
+ }
+
+ mSampleSizeFieldSize = mDefaultSampleSize & 0xf;
+ mDefaultSampleSize = 0;
+
+ if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
+ && mSampleSizeFieldSize != 16) {
+ return ERROR_MALFORMED;
+ }
+
+ if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setTimeToSampleParams(
+ off_t data_offset, off_t data_size) {
+ if (mTimeToSample != NULL || data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mTimeToSampleCount = U32_AT(&header[4]);
+ mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
+
+ size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
+ if (mDataSource->read_at(
+ data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
+ return ERROR_IO;
+ }
+
+ for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
+ mTimeToSample[i] = ntohl(mTimeToSample[i]);
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+ if (mSyncSampleOffset >= 0 || data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ mSyncSampleOffset = data_offset;
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumSyncSamples = U32_AT(&header[4]);
+
+ if (mNumSyncSamples < 2) {
+ LOGW("Table of sync samples is empty or has only a single entry!");
+ }
+ return OK;
+}
+
+uint32_t SampleTable::countChunkOffsets() const {
+ return mNumChunkOffsets;
+}
+
+status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
+ *offset = 0;
+
+ if (mChunkOffsetOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (chunk_index >= mNumChunkOffsets) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mChunkOffsetType == kChunkOffsetType32) {
+ uint32_t offset32;
+
+ if (mDataSource->read_at(
+ mChunkOffsetOffset + 8 + 4 * chunk_index,
+ &offset32,
+ sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntohl(offset32);
+ } else {
+ assert(mChunkOffsetOffset == kChunkOffsetType64);
+
+ uint64_t offset64;
+ if (mDataSource->read_at(
+ mChunkOffsetOffset + 8 + 8 * chunk_index,
+ &offset64,
+ sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntoh64(offset64);
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getChunkForSample(
+ uint32_t sample_index,
+ uint32_t *chunk_index,
+ uint32_t *chunk_relative_sample_index,
+ uint32_t *desc_index) {
+ *chunk_index = 0;
+ *chunk_relative_sample_index = 0;
+ *desc_index = 0;
+
+ if (mSampleToChunkOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (sample_index >= countSamples()) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ uint32_t first_chunk = 0;
+ uint32_t samples_per_chunk = 0;
+ uint32_t chunk_desc_index = 0;
+
+ uint32_t index = 0;
+ while (index < mNumSampleToChunkOffsets) {
+ uint8_t buffer[12];
+ if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
+ buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint32_t stop_chunk = U32_AT(buffer);
+ if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
+ break;
+ }
+
+ sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
+ first_chunk = stop_chunk;
+ samples_per_chunk = U32_AT(&buffer[4]);
+ chunk_desc_index = U32_AT(&buffer[8]);
+
+ ++index;
+ }
+
+ *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
+ *chunk_relative_sample_index = sample_index % samples_per_chunk;
+ *desc_index = chunk_desc_index;
+
+ return OK;
+}
+
+uint32_t SampleTable::countSamples() const {
+ return mNumSampleSizes;
+}
+
+status_t SampleTable::getSampleSize(
+ uint32_t sample_index, size_t *sample_size) {
+ *sample_size = 0;
+
+ if (mSampleSizeOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (sample_index >= mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mDefaultSampleSize > 0) {
+ *sample_size = mDefaultSampleSize;
+ return OK;
+ }
+
+ switch (mSampleSizeFieldSize) {
+ case 32:
+ {
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + 4 * sample_index,
+ sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = ntohl(*sample_size);
+ break;
+ }
+
+ case 16:
+ {
+ uint16_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + 2 * sample_index,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = ntohs(x);
+ break;
+ }
+
+ case 8:
+ {
+ uint8_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + sample_index,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = x;
+ break;
+ }
+
+ default:
+ {
+ assert(mSampleSizeFieldSize == 4);
+
+ uint8_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + sample_index / 2,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getSampleOffsetAndSize(
+ uint32_t sample_index, off_t *offset, size_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
+ *offset = 0;
+ *size = 0;
+
+ uint32_t chunk_index;
+ uint32_t chunk_relative_sample_index;
+ uint32_t desc_index;
+ status_t err = getChunkForSample(
+ sample_index, &chunk_index, &chunk_relative_sample_index,
+ &desc_index);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = getChunkOffset(chunk_index, offset);
+
+ if (err != OK) {
+ return err;
+ }
+
+ for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
+ size_t sample_size;
+ err = getSampleSize(sample_index - j - 1, &sample_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += sample_size;
+ }
+
+ err = getSampleSize(sample_index, size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getMaxSampleSize(size_t *max_size) {
+ Mutex::Autolock autoLock(mLock);
+
+ *max_size = 0;
+
+ for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
+ size_t sample_size;
+ status_t err = getSampleSize(i, &sample_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (sample_size > *max_size) {
+ *max_size = sample_size;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
+ // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (sample_index >= mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ uint32_t cur_sample = 0;
+ *time = 0;
+ for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+ uint32_t n = mTimeToSample[2 * i];
+ uint32_t delta = mTimeToSample[2 * i + 1];
+
+ if (sample_index < cur_sample + n) {
+ *time += delta * (sample_index - cur_sample);
+
+ return OK;
+ }
+
+ *time += delta * n;
+ cur_sample += n;
+ }
+
+ return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSample(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+ Mutex::Autolock autoLock(mLock);
+
+ uint32_t cur_sample = 0;
+ uint32_t time = 0;
+ for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+ uint32_t n = mTimeToSample[2 * i];
+ uint32_t delta = mTimeToSample[2 * i + 1];
+
+ if (req_time < time + n * delta) {
+ int j = (req_time - time) / delta;
+
+ *sample_index = cur_sample + j;
+
+ if (flags & kSyncSample_Flag) {
+ return findClosestSyncSample(*sample_index, sample_index);
+ }
+
+ return OK;
+ }
+
+ time += delta * n;
+ cur_sample += n;
+ }
+
+ return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSyncSample(
+ uint32_t start_sample_index, uint32_t *sample_index) {
+ *sample_index = 0;
+
+ if (mSyncSampleOffset < 0) {
+ // All samples are sync-samples.
+ *sample_index = start_sample_index;
+ return OK;
+ }
+
+ uint32_t x;
+ uint32_t left = 0;
+ uint32_t right = mNumSyncSamples;
+ while (left < right) {
+ uint32_t mid = (left + right) / 2;
+ if (mDataSource->read_at(
+ mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
+ return ERROR_IO;
+ }
+
+ x = ntohl(x);
+
+ if (x < (start_sample_index + 1)) {
+ left = mid + 1;
+ } else if (x > (start_sample_index + 1)) {
+ right = mid;
+ } else {
+ break;
+ }
+ }
+
+#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;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
new file mode 100644
index 0000000..17b626e
--- /dev/null
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ShoutcastSource.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+ShoutcastSource::ShoutcastSource(HTTPStream *http)
+ : mHttp(http),
+ mMetaDataOffset(0),
+ mBytesUntilMetaData(0),
+ mGroup(NULL),
+ mStarted(false) {
+ string metaint;
+ if (mHttp->find_header_value("icy-metaint", &metaint)) {
+ char *end;
+ const char *start = metaint.c_str();
+ mMetaDataOffset = strtol(start, &end, 10);
+ assert(end > start && *end == '\0');
+ assert(mMetaDataOffset > 0);
+
+ mBytesUntilMetaData = mMetaDataOffset;
+ }
+}
+
+ShoutcastSource::~ShoutcastSource() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mHttp;
+ mHttp = NULL;
+}
+
+status_t ShoutcastSource::start(MetaData *) {
+ assert(!mStarted);
+
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(4096)); // XXX
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t ShoutcastSource::stop() {
+ assert(mStarted);
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> ShoutcastSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "audio/mpeg");
+ meta->setInt32(kKeySampleRate, 44100);
+ meta->setInt32(kKeyChannelCount, 2); // XXX
+
+ return meta;
+}
+
+status_t ShoutcastSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ assert(mStarted);
+
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ *out = buffer;
+
+ size_t num_bytes = buffer->size();
+ if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
+ num_bytes = mBytesUntilMetaData;
+ }
+
+ ssize_t n = mHttp->receive(buffer->data(), num_bytes);
+
+ if (n <= 0) {
+ return (status_t)n;
+ }
+
+ buffer->set_range(0, n);
+
+ mBytesUntilMetaData -= (size_t)n;
+
+ if (mBytesUntilMetaData == 0) {
+ unsigned char num_16_byte_blocks = 0;
+ n = mHttp->receive((char *)&num_16_byte_blocks, 1);
+ assert(n == 1);
+
+ char meta[255 * 16];
+ size_t meta_size = num_16_byte_blocks * 16;
+ size_t meta_length = 0;
+ while (meta_length < meta_size) {
+ n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
+ if (n <= 0) {
+ return (status_t)n;
+ }
+
+ meta_length += (size_t) n;
+ }
+
+ while (meta_length > 0 && meta[meta_length - 1] == '\0') {
+ --meta_length;
+ }
+
+ if (meta_length > 0) {
+ // Technically we should probably attach this meta data to the
+ // next buffer. XXX
+ buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
+ }
+
+ mBytesUntilMetaData = mMetaDataOffset;
+ }
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/TimeSource.cpp b/media/libstagefright/TimeSource.cpp
new file mode 100644
index 0000000..d987fbf
--- /dev/null
+++ b/media/libstagefright/TimeSource.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <stddef.h>
+#include <sys/time.h>
+
+#include <media/stagefright/TimeSource.h>
+
+namespace android {
+
+SystemTimeSource::SystemTimeSource()
+ : mStartTimeUs(GetSystemTimeUs()) {
+}
+
+int64_t SystemTimeSource::getRealTimeUs() {
+ return GetSystemTimeUs() - mStartTimeUs;
+}
+
+// static
+int64_t SystemTimeSource::GetSystemTimeUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
new file mode 100644
index 0000000..2f8a19f
--- /dev/null
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#define LOG_TAG "TimedEventQueue"
+#include <utils/Log.h>
+
+#include <sys/time.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TimedEventQueue.h>
+
+namespace android {
+
+TimedEventQueue::TimedEventQueue()
+ : mRunning(false),
+ mStopped(false) {
+}
+
+TimedEventQueue::~TimedEventQueue() {
+ stop();
+}
+
+void TimedEventQueue::start() {
+ if (mRunning) {
+ return;
+ }
+
+ mStopped = 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);
+
+ mRunning = true;
+}
+
+void TimedEventQueue::stop(bool flush) {
+ if (!mRunning) {
+ return;
+ }
+
+ if (flush) {
+ postEventToBack(new StopEvent);
+ } else {
+ postTimedEvent(new StopEvent, INT64_MIN);
+ }
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ mQueue.clear();
+
+ mRunning = false;
+}
+
+void TimedEventQueue::postEvent(const sp<Event> &event) {
+ // Reserve an earlier timeslot an INT64_MIN to be able to post
+ // the StopEvent to the absolute head of the queue.
+ postTimedEvent(event, INT64_MIN + 1);
+}
+
+void TimedEventQueue::postEventToBack(const sp<Event> &event) {
+ postTimedEvent(event, INT64_MAX);
+}
+
+void TimedEventQueue::postEventWithDelay(
+ const sp<Event> &event, int64_t delay_us) {
+ assert(delay_us >= 0);
+ postTimedEvent(event, getRealTimeUs() + delay_us);
+}
+
+void TimedEventQueue::postTimedEvent(
+ const sp<Event> &event, int64_t realtime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ List<QueueItem>::iterator it = mQueue.begin();
+ while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
+ ++it;
+ }
+
+ QueueItem item;
+ item.event = event;
+ item.realtime_us = realtime_us;
+
+ if (it == mQueue.begin()) {
+ mQueueHeadChangedCondition.signal();
+ }
+
+ mQueue.insert(it, item);
+
+ mQueueNotEmptyCondition.signal();
+}
+
+bool TimedEventQueue::cancelEvent(const sp<Event> &event) {
+ Mutex::Autolock autoLock(mLock);
+
+ List<QueueItem>::iterator it = mQueue.begin();
+ while (it != mQueue.end() && (*it).event != event) {
+ ++it;
+ }
+
+ if (it == mQueue.end()) {
+ return false;
+ }
+
+ if (it == mQueue.begin()) {
+ mQueueHeadChangedCondition.signal();
+ }
+
+ mQueue.erase(it);
+
+ return true;
+}
+
+// static
+int64_t TimedEventQueue::getRealTimeUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+// static
+void *TimedEventQueue::ThreadWrapper(void *me) {
+ static_cast<TimedEventQueue *>(me)->threadEntry();
+
+ return NULL;
+}
+
+void TimedEventQueue::threadEntry() {
+ for (;;) {
+ int64_t now_us;
+ sp<Event> event;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mStopped) {
+ break;
+ }
+
+ while (mQueue.empty()) {
+ mQueueNotEmptyCondition.wait(mLock);
+ }
+
+ List<QueueItem>::iterator it;
+ for (;;) {
+ it = mQueue.begin();
+
+ now_us = getRealTimeUs();
+ int64_t when_us = (*it).realtime_us;
+
+ int64_t delay_us;
+ if (when_us < 0 || when_us == INT64_MAX) {
+ delay_us = 0;
+ } else {
+ delay_us = when_us - now_us;
+ }
+
+ if (delay_us <= 0) {
+ break;
+ }
+
+ status_t err = mQueueHeadChangedCondition.waitRelative(
+ mLock, delay_us * 1000);
+
+ if (err == -ETIMEDOUT) {
+ now_us = getRealTimeUs();
+ break;
+ }
+ }
+
+ event = (*it).event;
+ mQueue.erase(it);
+ }
+
+ // Fire event with the lock NOT held.
+ event->fire(this, now_us);
+ }
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
new file mode 100644
index 0000000..2720f93
--- /dev/null
+++ b/media/libstagefright/Utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include <arpa/inet.h>
+
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+uint16_t U16_AT(const uint8_t *ptr) {
+ return ptr[0] << 8 | ptr[1];
+}
+
+uint32_t U32_AT(const uint8_t *ptr) {
+ return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+uint64_t U64_AT(const uint8_t *ptr) {
+ return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
+}
+
+// XXX warning: these won't work on big-endian host.
+uint64_t ntoh64(uint64_t x) {
+ return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
+}
+
+uint64_t hton64(uint64_t x) {
+ return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
new file mode 100644
index 0000000..ecd3b2e
--- /dev/null
+++ b/media/libstagefright/omx/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Set up the OpenCore variables.
+include external/opencore/Config.mk
+LOCAL_C_INCLUDES := $(PV_INCLUDES)
+LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
+
+LOCAL_SRC_FILES:= \
+ OMX.cpp \
+ QComHardwareRenderer.cpp \
+ SoftwareRenderer.cpp \
+ TIHardwareRenderer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libmedia \
+ libutils \
+ libui \
+ libcutils \
+ libopencore_common
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright_omx
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
new file mode 100644
index 0000000..39fa27e
--- /dev/null
+++ b/media/libstagefright/omx/OMX.cpp
@@ -0,0 +1,641 @@
+/*
+ * 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 "OMX"
+#include <utils/Log.h>
+
+#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/QComHardwareRenderer.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <media/stagefright/VideoRenderer.h>
+
+#include <OMX_Component.h>
+
+namespace android {
+
+class NodeMeta {
+public:
+ NodeMeta(OMX *owner)
+ : mOwner(owner),
+ mHandle(NULL) {
+ }
+
+ OMX *owner() const {
+ return mOwner;
+ }
+
+ void setHandle(OMX_HANDLETYPE handle) {
+ assert(mHandle == NULL);
+ mHandle = handle;
+ }
+
+ OMX_HANDLETYPE handle() const {
+ return mHandle;
+ }
+
+ void setObserver(const sp<IOMXObserver> &observer) {
+ mObserver = observer;
+ }
+
+ sp<IOMXObserver> observer() {
+ return mObserver;
+ }
+
+private:
+ OMX *mOwner;
+ OMX_HANDLETYPE mHandle;
+ sp<IOMXObserver> mObserver;
+
+ NodeMeta(const NodeMeta &);
+ 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)
+ : mOwner(owner),
+ mMem(mem),
+ mIsBackup(is_backup) {
+ }
+
+ BufferMeta(OMX *owner, size_t size)
+ : mOwner(owner),
+ mSize(size),
+ mIsBackup(false) {
+ }
+
+ void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->pBuffer + header->nOffset,
+ header->nFilledLen);
+ }
+
+ void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy(header->pBuffer + header->nOffset,
+ (const OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->nFilledLen);
+ }
+
+private:
+ OMX *mOwner;
+ sp<IMemory> mMem;
+ size_t mSize;
+ bool mIsBackup;
+
+ BufferMeta(const BufferMeta &);
+ BufferMeta &operator=(const BufferMeta &);
+};
+
+// static
+OMX_CALLBACKTYPE OMX::kCallbacks = {
+ &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
+};
+
+// static
+OMX_ERRORTYPE OMX::OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnFillBufferDone(meta, pBuffer);
+}
+
+OMX::OMX()
+ : mDispatcher(new CallbackDispatcher) {
+}
+
+status_t OMX::list_nodes(List<String8> *list) {
+ OMX_MasterInit(); // XXX Put this somewhere else.
+
+ list->clear();
+
+ OMX_U32 index = 0;
+ char componentName[256];
+ while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
+ == OMX_ErrorNone) {
+ list->push_back(String8(componentName));
+
+ ++index;
+ }
+
+ return OK;
+}
+
+status_t OMX::allocate_node(const char *name, node_id *node) {
+ Mutex::Autolock autoLock(mLock);
+
+ *node = 0;
+
+ OMX_MasterInit(); // XXX Put this somewhere else.
+
+ NodeMeta *meta = new NodeMeta(this);
+
+ OMX_HANDLETYPE handle;
+ OMX_ERRORTYPE err = OMX_MasterGetHandle(
+ &handle, const_cast<char *>(name), meta, &kCallbacks);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("FAILED to allocate omx component '%s'", name);
+
+ delete meta;
+ meta = NULL;
+
+ return UNKNOWN_ERROR;
+ }
+
+ meta->setHandle(handle);
+
+ *node = meta;
+
+ return OK;
+}
+
+status_t OMX::free_node(node_id node) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
+
+ delete meta;
+ meta = NULL;
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::get_parameter(
+ 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_GetParameter(meta->handle(), index, params);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_parameter(
+ 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_SetParameter(meta->handle(), index, const_cast<void *>(params));
+
+ 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) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, params);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
+ params->size(), static_cast<OMX_U8 *>(params->pointer()));
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, size);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
+ buffer_meta, size);
+
+ if (err != OMX_ErrorNone) {
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, params, true);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_AllocateBuffer(
+ node_meta->handle(), &header, port_index, buffer_meta,
+ params->size());
+
+ if (err != OMX_ErrorNone) {
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_FreeBuffer(node_meta->handle(), port_index, header);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+OMX_ERRORTYPE OMX::OnEvent(
+ NodeMeta *meta,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData) {
+ LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
+
+ omx_message msg;
+ msg.type = omx_message::EVENT;
+ msg.node = meta;
+ msg.u.event_data.event = eEvent;
+ msg.u.event_data.data1 = nData1;
+ msg.u.event_data.data2 = nData2;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
+
+ omx_message msg;
+ msg.type = omx_message::EMPTY_BUFFER_DONE;
+ msg.node = meta;
+ msg.u.buffer_data.buffer = pBuffer;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ LOGV("OnFillBufferDone buffer=%p", pBuffer);
+ BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
+ buffer_meta->CopyFromOMX(pBuffer);
+
+ omx_message msg;
+ msg.type = omx_message::FILL_BUFFER_DONE;
+ 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;
+ msg.u.extended_buffer_data.flags = pBuffer->nFlags;
+ msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
+ msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+status_t OMX::observe_node(
+ node_id node, const sp<IOMXObserver> &observer) {
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ node_meta->setObserver(observer);
+
+ return OK;
+}
+
+void OMX::fill_buffer(node_id node, buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = 0;
+ header->nOffset = 0;
+ header->nFlags = 0;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_FillThisBuffer(node_meta->handle(), header);
+ assert(err == OMX_ErrorNone);
+}
+
+void OMX::empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = range_length;
+ header->nOffset = range_offset;
+ header->nFlags = flags;
+ header->nTimeStamp = timestamp;
+
+ BufferMeta *buffer_meta =
+ static_cast<BufferMeta *>(header->pAppPrivate);
+ buffer_meta->CopyToOMX(header);
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_EmptyThisBuffer(node_meta->handle(), header);
+ assert(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;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+sp<IOMXRenderer> OMX::createRenderer(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ VideoRenderer *impl = NULL;
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+ && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
+ LOGW("Using QComHardwareRenderer.");
+ impl =
+ new QComHardwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ } else if (colorFormat == OMX_COLOR_FormatCbYCrY
+ && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
+ LOGW("Using TIHardwareRenderer.");
+ impl =
+ new TIHardwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ } else {
+ LOGW("Using software renderer.");
+ impl = new SoftwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ }
+
+ return new OMXRenderer(impl);
+}
+
+OMXRenderer::OMXRenderer(VideoRenderer *impl)
+ : mImpl(impl) {
+}
+
+OMXRenderer::~OMXRenderer() {
+ delete mImpl;
+ mImpl = NULL;
+}
+
+void OMXRenderer::render(IOMX::buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+
+ mImpl->render(
+ header->pBuffer + header->nOffset,
+ header->nFilledLen,
+ header->pPlatformPrivate);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
new file mode 100644
index 0000000..6325f79
--- /dev/null
+++ b/media/libstagefright/omx/OMX.h
@@ -0,0 +1,138 @@
+/*
+ * 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 ANDROID_OMX_H_
+#define ANDROID_OMX_H_
+
+#include <media/IOMX.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class NodeMeta;
+
+class OMX : public BnOMX {
+public:
+ OMX();
+
+ virtual status_t list_nodes(List<String8> *list);
+
+ virtual status_t allocate_node(const char *name, node_id *node);
+ virtual status_t free_node(node_id node);
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+ virtual status_t get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t set_parameter(
+ 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);
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer);
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer);
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer);
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer);
+
+ virtual void fill_buffer(node_id node, buffer_id buffer);
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ 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,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight);
+
+private:
+ static OMX_CALLBACKTYPE kCallbacks;
+
+ Mutex mLock;
+
+ struct CallbackDispatcher;
+ sp<CallbackDispatcher> mDispatcher;
+
+ static OMX_ERRORTYPE OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+ static OMX_ERRORTYPE OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ OMX_ERRORTYPE OnEvent(
+ NodeMeta *meta,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+ OMX_ERRORTYPE OnEmptyBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ OMX_ERRORTYPE OnFillBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ OMX(const OMX &);
+ OMX &operator=(const OMX &);
+};
+
+} // namespace android
+
+#endif // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/OMXRenderer.h b/media/libstagefright/omx/OMXRenderer.h
new file mode 100644
index 0000000..4d194ce
--- /dev/null
+++ b/media/libstagefright/omx/OMXRenderer.h
@@ -0,0 +1,44 @@
+/*
+ * 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_RENDERER_H_
+
+#define OMX_RENDERER_H_
+
+#include <media/IOMX.h>
+
+namespace android {
+
+class VideoRenderer;
+
+class OMXRenderer : public BnOMXRenderer {
+public:
+ // Assumes ownership of "impl".
+ OMXRenderer(VideoRenderer *impl);
+ virtual ~OMXRenderer();
+
+ virtual void render(IOMX::buffer_id buffer);
+
+private:
+ VideoRenderer *mImpl;
+
+ OMXRenderer(const OMXRenderer &);
+ OMXRenderer &operator=(const OMXRenderer &);
+};
+
+} // namespace android
+
+#endif // OMX_RENDERER_H_
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
new file mode 100644
index 0000000..5a23792
--- /dev/null
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+typedef struct PLATFORM_PRIVATE_ENTRY
+{
+ /* Entry type */
+ uint32_t type;
+
+ /* Pointer to platform specific entry */
+ void *entry;
+
+} PLATFORM_PRIVATE_ENTRY;
+
+typedef struct PLATFORM_PRIVATE_LIST
+{
+ /* Number of entries */
+ uint32_t nEntries;
+
+ /* Pointer to array of platform specific entries *
+ * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */
+ PLATFORM_PRIVATE_ENTRY *entryList;
+
+} PLATFORM_PRIVATE_LIST;
+
+// data structures for tunneling buffers
+typedef struct PLATFORM_PRIVATE_PMEM_INFO
+{
+ /* pmem file descriptor */
+ uint32_t pmem_fd;
+ uint32_t offset;
+
+} PLATFORM_PRIVATE_PMEM_INFO;
+
+#define PLATFORM_PRIVATE_PMEM 1
+
+QComHardwareRenderer::QComHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+ assert(mISurface.get() != NULL);
+ assert(mDecodedWidth > 0);
+ assert(mDecodedHeight > 0);
+}
+
+QComHardwareRenderer::~QComHardwareRenderer() {
+ mISurface->unregisterBuffers();
+}
+
+void QComHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ size_t offset;
+ if (!getOffset(platformPrivate, &offset)) {
+ return;
+ }
+
+ mISurface->postBuffer(offset);
+}
+
+bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) {
+ *offset = 0;
+
+ PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate;
+ for (uint32_t i = 0; i < list->nEntries; ++i) {
+ if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) {
+ continue;
+ }
+
+ PLATFORM_PRIVATE_PMEM_INFO *info =
+ (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry;
+
+ if (info != NULL) {
+ if (mMemoryHeap.get() == NULL) {
+ publishBuffers(info->pmem_fd);
+ }
+
+ if (mMemoryHeap.get() == NULL) {
+ return false;
+ }
+
+ *offset = info->offset;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) {
+ sp<MemoryHeapBase> master =
+ reinterpret_cast<MemoryHeapBase *>(pmem_fd);
+
+ master->setDevice("/dev/pmem");
+
+ mMemoryHeap = new MemoryHeapPmem(master, 0);
+ mMemoryHeap->slap();
+
+ ISurface::BufferHeap bufferHeap(
+ mDisplayWidth, mDisplayHeight,
+ mDecodedWidth, mDecodedHeight,
+ PIXEL_FORMAT_YCbCr_420_SP,
+ mMemoryHeap);
+
+ status_t err = mISurface->registerBuffers(bufferHeap);
+ assert(err == OK);
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
new file mode 100644
index 0000000..5483238
--- /dev/null
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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_TAG "SoftwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+#define QCOM_YUV 0
+
+SoftwareRenderer::SoftwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ 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);
+
+ ISurface::BufferHeap bufferHeap(
+ mDisplayWidth, mDisplayHeight,
+ mDecodedWidth, mDecodedHeight,
+ PIXEL_FORMAT_RGB_565,
+ mMemoryHeap);
+
+ status_t err = mISurface->registerBuffers(bufferHeap);
+ assert(err == OK);
+}
+
+SoftwareRenderer::~SoftwareRenderer() {
+ mISurface->unregisterBuffers();
+}
+
+void SoftwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
+ LOGE("size is %d, expected %d",
+ size, (mDecodedHeight * mDecodedWidth * 3) / 2);
+ }
+ assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
+
+ static const signed kClipMin = -278;
+ static const signed kClipMax = 535;
+ static uint8_t kClip[kClipMax - kClipMin + 1];
+ static uint8_t *kAdjustedClip = &kClip[-kClipMin];
+
+ static bool clipInitialized = false;
+
+ if (!clipInitialized) {
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+ }
+ clipInitialized = true;
+ }
+
+ size_t offset = mIndex * mFrameSize;
+
+ void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
+
+ uint32_t *dst_ptr = (uint32_t *)dst;
+
+ const uint8_t *src_y = (const uint8_t *)data;
+
+ const uint8_t *src_u =
+ (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
+
+#if !QCOM_YUV
+ const uint8_t *src_v =
+ (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
+#endif
+
+ for (size_t y = 0; y < mDecodedHeight; ++y) {
+ for (size_t x = 0; x < mDecodedWidth; x += 2) {
+ // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
+ // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
+ // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
+
+ // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
+ // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
+ // R = .................. + 409/256 * (V - 128)
+
+ // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
+ // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
+ // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
+
+ // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
+ // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
+ // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
+
+ // clip range -278 .. 535
+
+ signed y1 = (signed)src_y[x] - 16;
+ signed y2 = (signed)src_y[x + 1] - 16;
+
+#if QCOM_YUV
+ signed u = (signed)src_u[x & ~1] - 128;
+ signed v = (signed)src_u[(x & ~1) + 1] - 128;
+#else
+ signed u = (signed)src_u[x / 2] - 128;
+ signed v = (signed)src_v[x / 2] - 128;
+#endif
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src_y += mDecodedWidth;
+
+ if (y & 1) {
+#if QCOM_YUV
+ src_u += mDecodedWidth;
+#else
+ src_u += mDecodedWidth / 2;
+ src_v += mDecodedWidth / 2;
+#endif
+ }
+
+ dst_ptr += mDecodedWidth / 2;
+ }
+
+ mISurface->postBuffer(offset);
+ mIndex = 1 - mIndex;
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+ assert(mISurface.get() != NULL);
+ assert(mDecodedWidth > 0);
+ assert(mDecodedHeight > 0);
+
+ sp<OverlayRef> ref = mISurface->createOverlay(
+ mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+ if (ref.get() == NULL) {
+ LOGE("Unable to create the overlay!");
+ return;
+ }
+
+ mOverlay = new Overlay(ref);
+
+ for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+ mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+ }
+ mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+ if (mOverlay.get() != NULL) {
+ mOverlay->destroy();
+ mOverlay.clear();
+
+ // XXX apparently destroying an overlay is an asynchronous process...
+ sleep(1);
+ }
+}
+
+void TIHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ // assert(size == mFrameSize);
+
+ if (mOverlay.get() == NULL) {
+ return;
+ }
+
+#if 0
+ overlay_buffer_t buffer;
+ if (mOverlay->dequeueBuffer(&buffer) == OK) {
+ void *addr = mOverlay->getBufferAddress(buffer);
+
+ memcpy(addr, data, size);
+
+ mOverlay->queueBuffer(buffer);
+ }
+#else
+ memcpy(mOverlayAddresses[mIndex], data, size);
+ mOverlay->queueBuffer((void *)mIndex);
+
+ if (mIndex-- == 0) {
+ mIndex = mOverlayAddresses.size() - 1;
+ }
+#endif
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
new file mode 100644
index 0000000..5b16784
--- /dev/null
+++ b/media/libstagefright/string.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/string.h>
+
+namespace android {
+
+// static
+string::size_type string::npos = (string::size_type)-1;
+
+string::string() {
+}
+
+string::string(const char *s, size_t length)
+ : mString(s, length) {
+}
+
+string::string(const string &from, size_type start, size_type length)
+ : mString(from.c_str() + start, length) {
+}
+
+string::string(const char *s)
+ : mString(s) {
+}
+
+const char *string::c_str() const {
+ return mString.string();
+}
+
+string::size_type string::size() const {
+ return mString.length();
+}
+
+void string::clear() {
+ mString = String8();
+}
+
+string::size_type string::find(char c) const {
+ char s[2];
+ s[0] = c;
+ s[1] = '\0';
+
+ ssize_t index = mString.find(s);
+
+ return index < 0 ? npos : (size_type)index;
+}
+
+bool string::operator<(const string &other) const {
+ return mString < other.mString;
+}
+
+bool string::operator==(const string &other) const {
+ return mString == other.mString;
+}
+
+string &string::operator+=(char c) {
+ mString.append(&c, 1);
+
+ return *this;
+}
+
+void string::erase(size_t from, size_t length) {
+ String8 s(mString.string(), from);
+ s.append(mString.string() + from + length);
+
+ mString = s;
+}
+
+} // namespace android
+
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index c681698..a92cea8 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -8,7 +8,8 @@
libaudioflinger \
libcameraservice \
libmediaplayerservice \
- libutils
+ libutils \
+ libbinder
base := $(LOCAL_PATH)/../..
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 6954b63..7094cfa 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -20,14 +20,15 @@
#include <unistd.h>
#include <grp.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <AudioFlinger.h>
#include <CameraService.h>
#include <MediaPlayerService.h>
+#include <AudioPolicyService.h>
#include <private/android_filesystem_config.h>
using namespace android;
@@ -40,6 +41,7 @@
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
+ AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index 06120f5..fe11878 100644
--- a/media/sdutils/sdutil.cpp
+++ b/media/sdutils/sdutil.cpp
@@ -15,8 +15,8 @@
*/
#include <hardware_legacy/IMountService.h>
-#include <utils/BpBinder.h>
-#include <utils/IServiceManager.h>
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 6edc2cc..2a4e9a0 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -23,6 +23,7 @@
import com.android.mediaframeworktest.functional.MediaPlayerApiTest;
import com.android.mediaframeworktest.functional.MediaRecorderTest;
import com.android.mediaframeworktest.functional.SimTonesTest;
+import com.android.mediaframeworktest.functional.MediaPlayerInvokeTest;
import junit.framework.TestSuite;
@@ -32,7 +33,7 @@
/**
* Instrumentation Test Runner for all MediaPlayer tests.
- *
+ *
* Running all tests:
*
* adb shell am instrument \
@@ -52,6 +53,7 @@
suite.addTestSuite(MediaRecorderTest.class);
suite.addTestSuite(MediaAudioTrackTest.class);
suite.addTestSuite(MediaMimeTest.class);
+ suite.addTestSuite(MediaPlayerInvokeTest.class);
return suite;
}
@@ -60,5 +62,3 @@
return MediaFrameworkTestRunner.class.getClassLoader();
}
}
-
-
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 81d59da..a203adc 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -24,16 +24,16 @@
/**
* Instrumentation Test Runner for all media framework unit tests.
- *
+ *
* Make sure that MediaFrameworkUnitTestRunner has been added to
* AndroidManifest.xml file, and then "make -j4 mediaframeworktest; adb sync"
* to build and upload mediaframeworktest to the phone or emulator.
- *
+ *
* Example on running all unit tests for a single class:
* adb shell am instrument -e class \
- * com.android.mediaframeworktest.unit.MediaMetadataRetrieverUnitTest \
+ * com.android.mediaframeworktest.unit.MediaMetadataRetrieverUnitTest \
* -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- *
+ *
* Example on running all unit tests for the media framework:
* adb shell am instrument \
* -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
@@ -54,12 +54,12 @@
public ClassLoader getLoader() {
return MediaFrameworkUnitTestRunner.class.getClassLoader();
}
-
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaMetadataRetrieverTest.class);
}
-
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaRecorderStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaRecorderPrepareStateUnitTest.class);
@@ -87,5 +87,6 @@
suite.addTestSuite(MediaPlayerSetLoopingStateUnitTest.class);
suite.addTestSuite(MediaPlayerSetAudioStreamTypeStateUnitTest.class);
suite.addTestSuite(MediaPlayerSetVolumeStateUnitTest.class);
+ suite.addTestSuite(MediaPlayerMetadataParserTest.class);
}
}
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/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
index aefedc3..cea3a5a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
@@ -140,7 +140,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorMono16MusicStream: " + res.mResultLog, res.mResult);
@@ -153,7 +153,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorStereo16MusicStream: " + res.mResultLog, res.mResult);
@@ -166,7 +166,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorMono16MusicStatic: " + res.mResultLog, res.mResult);
@@ -179,7 +179,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorStereo16MusicStatic: " + res.mResultLog, res.mResult);
@@ -196,7 +196,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorMono8MusicStream: " + res.mResultLog, res.mResult);
@@ -208,7 +208,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorStereo8MusicStream: " + res.mResultLog, res.mResult);
@@ -220,7 +220,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorMono8MusicStatic: " + res.mResultLog, res.mResult);
@@ -232,7 +232,7 @@
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorStereo8MusicStatic: " + res.mResultLog, res.mResult);
@@ -248,15 +248,15 @@
public void testConstructorStreamType() throws Exception {
// constants for test
final int TYPE_TEST_SR = 22050;
- final int TYPE_TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TYPE_TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TYPE_TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TYPE_TEST_MODE = AudioTrack.MODE_STREAM;
final int[] STREAM_TYPES = { AudioManager.STREAM_ALARM, AudioManager.STREAM_BLUETOOTH_SCO,
AudioManager.STREAM_MUSIC, AudioManager.STREAM_NOTIFICATION,
AudioManager.STREAM_RING, AudioManager.STREAM_SYSTEM,
- AudioManager.STREAM_VOICE_CALL };
+ AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_DTMF, };
final String[] STREAM_NAMES = { "STREAM_ALARM", "STREAM_BLUETOOTH_SCO", "STREAM_MUSIC",
- "STREAM_NOTIFICATION", "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL" };
+ "STREAM_NOTIFICATION", "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL", "STREAM_DTMF" };
boolean localTestRes = true;
AudioTrack track = null;
@@ -303,7 +303,7 @@
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterInit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -324,7 +324,7 @@
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionIncrease";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -352,7 +352,7 @@
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -382,7 +382,7 @@
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterStop";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -413,7 +413,7 @@
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterPause";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -448,7 +448,7 @@
// constants for test
final String TEST_NAME = "testSetStereoVolumeMax";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -474,7 +474,7 @@
// constants for test
final String TEST_NAME = "testSetStereoVolumeMin";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -500,7 +500,7 @@
// constants for test
final String TEST_NAME = "testSetStereoVolumeMid";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -526,7 +526,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackRate";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -552,7 +552,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackRateZero";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -574,7 +574,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackRateTwiceOutputSR";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -601,7 +601,7 @@
// constants for test
final String TEST_NAME = "testSetGetPlaybackRate";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -628,7 +628,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackRateUninit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -655,7 +655,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionPlaying";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -682,7 +682,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionStopped";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -710,7 +710,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionPaused";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -738,7 +738,7 @@
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -770,7 +770,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsStream";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -794,7 +794,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsStartAfterEnd";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -818,7 +818,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsSuccess";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -842,7 +842,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsLoopTooLong";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -868,7 +868,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsStartTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -896,7 +896,7 @@
// constants for test
final String TEST_NAME = "testSetLoopPointsEndTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -929,7 +929,7 @@
// constants for test
final String TEST_NAME = "testWriteByteOffsetTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -953,7 +953,7 @@
// constants for test
final String TEST_NAME = "testWriteShortOffsetTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -977,7 +977,7 @@
// constants for test
final String TEST_NAME = "testWriteByteSizeTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1001,7 +1001,7 @@
// constants for test
final String TEST_NAME = "testWriteShortSizeTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1025,7 +1025,7 @@
// constants for test
final String TEST_NAME = "testWriteByteNegativeOffset";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1049,7 +1049,7 @@
// constants for test
final String TEST_NAME = "testWriteShortNegativeOffset";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1073,7 +1073,7 @@
// constants for test
final String TEST_NAME = "testWriteByteNegativeSize";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1097,7 +1097,7 @@
// constants for test
final String TEST_NAME = "testWriteShortNegativeSize";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1121,7 +1121,7 @@
// constants for test
final String TEST_NAME = "testWriteByte";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1145,7 +1145,7 @@
// constants for test
final String TEST_NAME = "testWriteShort";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1169,7 +1169,7 @@
// constants for test
final String TEST_NAME = "testWriteByte8bit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1193,7 +1193,7 @@
// constants for test
final String TEST_NAME = "testWriteShort8bit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1221,7 +1221,7 @@
// constant for test
final String TEST_NAME = "testGetMinBufferSizeTooLowSR";
final int TEST_SR = 3999;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1238,7 +1238,7 @@
// constant for testg
final String TEST_NAME = "testGetMinBufferSizeTooHighSR";
final int TEST_SR = 48001;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
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/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
new file mode 100644
index 0000000..ab8b311
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import android.media.MediaPlayer;
+import android.os.Parcel;
+
+import java.util.Calendar;
+import java.util.Random;
+
+// Tests for the invoke method in the MediaPlayer.
+public class MediaPlayerInvokeTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+ private static final String TAG = "MediaPlayerInvokeTest";
+ private MediaPlayer mPlayer;
+ private Random rnd;
+
+ public MediaPlayerInvokeTest() {
+ super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+ rnd = new Random(Calendar.getInstance().getTimeInMillis());
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mPlayer = new MediaPlayer();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mPlayer.release();
+ super.tearDown();
+ }
+
+ // Generate a random number, sends it to the ping test player.
+ @MediumTest
+ public void testPing() throws Exception {
+ mPlayer.setDataSource("test:invoke_mock_media_player.so?url=ping");
+
+ Parcel request = mPlayer.newRequest();
+ Parcel reply = Parcel.obtain();
+
+ int val = rnd.nextInt();
+ request.writeInt(val);
+ assertEquals(0, mPlayer.invoke(request, reply));
+ assertEquals(val, reply.readInt());
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 442c35b..01c0920 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -47,7 +47,7 @@
*/
public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private String TAG = "MediaFrameworkPerformance";
+ private String TAG = "MediaPlayerPerformance";
private SQLiteDatabase mDB;
private SurfaceHolder mSurfaceHolder = null;
@@ -76,9 +76,11 @@
public void createDB() {
mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db", null);
- mDB.execSQL("CREATE TABLE perfdata (_id INTEGER PRIMARY KEY," +
+ mDB.execSQL("CREATE TABLE IF NOT EXISTS perfdata (_id INTEGER PRIMARY KEY," +
"file TEXT," + "setdatatime LONG," + "preparetime LONG," +
"playtime LONG" + ");");
+ //clean the table before adding new data
+ mDB.execSQL("DELETE FROM perfdata");
}
public void audioPlaybackStartupTime(String[] testFile) {
@@ -137,6 +139,10 @@
audioPlaybackStartupTime(MediaNames.MP3FILES);
audioPlaybackStartupTime(MediaNames.AACFILES);
+ //close the database after all transactions
+ if (mDB.isOpen()) {
+ mDB.close();
+ }
}
public void wmametadatautility(String[] testFile) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
new file mode 100644
index 0000000..38f598a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
@@ -0,0 +1,432 @@
+/*
+ * 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 com.android.mediaframeworktest.unit;
+import android.media.Metadata;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/*
+ * Check the Java layer that parses serialized metadata in Parcel
+ * works as expected.
+ *
+ */
+
+public class MediaPlayerMetadataParserTest extends AndroidTestCase {
+ private static final String TAG = "MediaPlayerMetadataTest";
+ private static final int kMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+ private static final int kHeaderSize = 8;
+
+ private Metadata mMetadata = null;
+ private Parcel mParcel = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mMetadata = new Metadata();
+ mParcel = Parcel.obtain();
+
+ resetParcel();
+ }
+
+ // Check parsing of the parcel fails. Make sure the parser rewind
+ // the parcel properly.
+ private void assertParseFail() throws Exception {
+ mParcel.setDataPosition(0);
+ assertFalse(mMetadata.parse(mParcel));
+ assertEquals(0, mParcel.dataPosition());
+ }
+
+ // Check parsing of the parcel is successful.
+ private void assertParse() throws Exception {
+ mParcel.setDataPosition(0);
+ assertTrue(mMetadata.parse(mParcel));
+ }
+
+ // Write the number of bytes from the start of the parcel to the
+ // current position at the beginning of the parcel (offset 0).
+ private void adjustSize() {
+ adjustSize(0);
+ }
+
+ // Write the number of bytes from the offset to the current
+ // position at position pointed by offset.
+ private void adjustSize(int offset) {
+ final int pos = mParcel.dataPosition();
+
+ mParcel.setDataPosition(offset);
+ mParcel.writeInt(pos - offset);
+ mParcel.setDataPosition(pos);
+ }
+
+ // Rewind the parcel and insert the header.
+ private void resetParcel() {
+ mParcel.setDataPosition(0);
+ // Most tests will use a properly formed parcel with a size
+ // and the meta marker so we add them by default.
+ mParcel.writeInt(-1); // Placeholder for the size
+ mParcel.writeInt(kMarker);
+ }
+
+ // ----------------------------------------------------------------------
+ // START OF THE TESTS
+
+
+ // There should be at least 8 bytes in the parcel, 4 for the size
+ // and 4 for the 'M' 'E' 'T' 'A' marker.
+ @SmallTest
+ public void testMissingSizeAndMarker() throws Exception {
+ for (int i = 0; i < kHeaderSize; ++i) {
+ mParcel.setDataPosition(0);
+ mParcel.setDataSize(i);
+
+ assertEquals(i, mParcel.dataAvail());
+ assertParseFail();
+ }
+ }
+
+ // There should be at least 'size' bytes in the parcel.
+ @SmallTest
+ public void testMissingData() throws Exception {
+ final int size = 20;
+
+ mParcel.writeInt(size);
+ mParcel.setDataSize(size - 1);
+ assertParseFail();
+ }
+
+ // Empty parcel is fine
+ @SmallTest
+ public void testEmptyIsOk() throws Exception {
+ adjustSize();
+ assertParse();
+ }
+
+ // ----------------------------------------------------------------------
+ // RECORDS
+ // ----------------------------------------------------------------------
+
+ // A record header should be at least 12 bytes long
+ @SmallTest
+ public void testRecordMissingId() throws Exception {
+ mParcel.writeInt(13); // record length
+ // misses metadata id and metadata type.
+ adjustSize();
+ assertParseFail();
+ }
+
+ @SmallTest
+ public void testRecordMissingType() throws Exception {
+ mParcel.writeInt(13); // record length lies
+ mParcel.writeInt(Metadata.TITLE);
+ // misses metadata type
+ adjustSize();
+ assertParseFail();
+ }
+
+ @SmallTest
+ public void testRecordWithZeroPayload() throws Exception {
+ mParcel.writeInt(0);
+ adjustSize();
+ assertParseFail();
+ }
+
+ // A record cannot be empty.
+ @SmallTest
+ public void testRecordMissingPayload() throws Exception {
+ mParcel.writeInt(12);
+ mParcel.writeInt(Metadata.TITLE);
+ mParcel.writeInt(Metadata.STRING_VAL);
+ // misses payload
+ adjustSize();
+ assertParseFail();
+ }
+
+ // Check records can be found.
+ @SmallTest
+ public void testRecordsFound() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ writeStringRecord(Metadata.firstCustomId(), "custom");
+ adjustSize();
+ assertParse();
+ assertTrue(mMetadata.has(Metadata.TITLE));
+ assertTrue(mMetadata.has(Metadata.GENRE));
+ assertTrue(mMetadata.has(Metadata.firstCustomId()));
+ assertFalse(mMetadata.has(Metadata.DRM_CRIPPLED));
+ assertEquals(3, mMetadata.keySet().size());
+ }
+
+ // Detects bad metadata type
+ @SmallTest
+ public void testBadMetadataType() throws Exception {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(Metadata.TITLE);
+ mParcel.writeInt(0); // Invalid type.
+ mParcel.writeString("dummy");
+ adjustSize(start);
+
+ adjustSize();
+ assertParseFail();
+ }
+
+ // Check a Metadata instance can be reused, i.e the parse method
+ // wipes out the existing states/keys.
+ @SmallTest
+ public void testParseClearState() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ writeStringRecord(Metadata.firstCustomId(), "custom");
+ adjustSize();
+ assertParse();
+
+ resetParcel();
+ writeStringRecord(Metadata.MIME_TYPE, "audio/mpg");
+ adjustSize();
+ assertParse();
+
+ // Only the mime type metadata should be present.
+ assertEquals(1, mMetadata.keySet().size());
+ assertTrue(mMetadata.has(Metadata.MIME_TYPE));
+
+ assertFalse(mMetadata.has(Metadata.TITLE));
+ assertFalse(mMetadata.has(Metadata.GENRE));
+ assertFalse(mMetadata.has(Metadata.firstCustomId()));
+ }
+
+ // ----------------------------------------------------------------------
+ // GETTERS
+ // ----------------------------------------------------------------------
+
+ // getString
+ @SmallTest
+ public void testGetString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ adjustSize();
+ assertParse();
+
+ assertEquals("a title", mMetadata.getString(Metadata.TITLE));
+ assertEquals("comedy", mMetadata.getString(Metadata.GENRE));
+ }
+
+ // get an empty string.
+ @SmallTest
+ public void testGetEmptyString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "");
+ adjustSize();
+ assertParse();
+
+ assertEquals("", mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when a NULL value was in the parcel
+ @SmallTest
+ public void testGetNullString() throws Exception {
+ writeStringRecord(Metadata.TITLE, null);
+ adjustSize();
+ assertParse();
+
+ assertEquals(null, mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when an integer is actually present
+ @SmallTest
+ public void testWrongType() throws Exception {
+ writeIntRecord(Metadata.DURATION, 5);
+ adjustSize();
+ assertParse();
+
+ try {
+ mMetadata.getString(Metadata.DURATION);
+ } catch (IllegalStateException ise) {
+ return;
+ }
+ fail("Exception was not thrown");
+ }
+
+ // getInt
+ @SmallTest
+ public void testGetInt() throws Exception {
+ writeIntRecord(Metadata.CD_TRACK_NUM, 1);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1, mMetadata.getInt(Metadata.CD_TRACK_NUM));
+ }
+
+ // getBoolean
+ @SmallTest
+ public void testGetBoolean() throws Exception {
+ writeBooleanRecord(Metadata.DRM_CRIPPLED, true);
+ adjustSize();
+ assertParse();
+
+ assertEquals(true, mMetadata.getBoolean(Metadata.DRM_CRIPPLED));
+ }
+
+ // getLong
+ @SmallTest
+ public void testGetLong() throws Exception {
+ writeLongRecord(Metadata.DURATION, 1L);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1L, mMetadata.getLong(Metadata.DURATION));
+ }
+
+ // getDouble
+ @SmallTest
+ public void testGetDouble() throws Exception {
+ writeDoubleRecord(Metadata.VIDEO_FRAME_RATE, 29.97);
+ adjustSize();
+ assertParse();
+
+ assertEquals(29.97, mMetadata.getDouble(Metadata.VIDEO_FRAME_RATE));
+ }
+
+ // getByteArray
+ @SmallTest
+ public void testGetByteArray() throws Exception {
+ byte data[] = new byte[]{1,2,3,4,5};
+
+ writeByteArrayRecord(Metadata.ALBUM_ART, data);
+ adjustSize();
+ assertParse();
+
+ byte res[] = mMetadata.getByteArray(Metadata.ALBUM_ART);
+ for (int i = 0; i < data.length; ++i) {
+ assertEquals(data[i], res[i]);
+ }
+ }
+
+ // getDate
+ @SmallTest
+ public void testGetDate() throws Exception {
+ writeDateRecord(Metadata.DATE, 0, "PST");
+ adjustSize();
+ assertParse();
+
+ assertEquals(new Date(0), mMetadata.getDate(Metadata.DATE));
+ }
+
+ // getTimedText
+ @SmallTest
+ public void testGetTimedText() throws Exception {
+ Date now = Calendar.getInstance().getTime();
+ writeTimedTextRecord(Metadata.CAPTION, now.getTime(),
+ 10, "Some caption");
+ adjustSize();
+ assertParse();
+
+ Metadata.TimedText caption = mMetadata.getTimedText(Metadata.CAPTION);
+ assertEquals("" + now + "-" + 10 + ":Some caption", caption.toString());
+ }
+
+ // ----------------------------------------------------------------------
+ // HELPERS TO APPEND RECORDS
+ // ----------------------------------------------------------------------
+
+ // Insert a string record at the current position.
+ private void writeStringRecord(int metadataId, String val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.STRING_VAL);
+ mParcel.writeString(val);
+ adjustSize(start);
+ }
+
+ // Insert an int record at the current position.
+ private void writeIntRecord(int metadataId, int val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.INTEGER_VAL);
+ mParcel.writeInt(val);
+ adjustSize(start);
+ }
+
+ // Insert a boolean record at the current position.
+ private void writeBooleanRecord(int metadataId, boolean val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BOOLEAN_VAL);
+ mParcel.writeInt(val ? 1 : 0);
+ adjustSize(start);
+ }
+
+ // Insert a Long record at the current position.
+ private void writeLongRecord(int metadataId, long val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.LONG_VAL);
+ mParcel.writeLong(val);
+ adjustSize(start);
+ }
+
+ // Insert a Double record at the current position.
+ private void writeDoubleRecord(int metadataId, double val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DOUBLE_VAL);
+ mParcel.writeDouble(val);
+ adjustSize(start);
+ }
+
+ // Insert a ByteArray record at the current position.
+ private void writeByteArrayRecord(int metadataId, byte[] val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BYTE_ARRAY_VAL);
+ mParcel.writeByteArray(val);
+ adjustSize(start);
+ }
+
+ // Insert a Date record at the current position.
+ private void writeDateRecord(int metadataId, long time, String tz) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DATE_VAL);
+ mParcel.writeLong(time);
+ mParcel.writeString(tz);
+ adjustSize(start);
+ }
+
+ // Insert a TimedText record at the current position.
+ private void writeTimedTextRecord(int metadataId, long begin,
+ int duration, String text) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.TIMED_TEXT_VAL);
+ mParcel.writeLong(begin);
+ mParcel.writeInt(duration);
+ mParcel.writeString(text);
+ adjustSize(start);
+ }
+}
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
new file mode 100644
index 0000000..eb50a51
--- /dev/null
+++ b/media/tests/players/Android.mk
@@ -0,0 +1,29 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= invoke_mock_media_player.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+ libbinder \
+ libutils
+
+LOCAL_MODULE:= invoke_mock_media_player
+LOCAL_MODULE_TAGS := test eng
+LOCAL_PRELINK_MODULE:= false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/tests/players/README b/media/tests/players/README
new file mode 100644
index 0000000..edf9bd6
--- /dev/null
+++ b/media/tests/players/README
@@ -0,0 +1,8 @@
+Native test players for system tests.
+
+For functional/system/performance tests, a native test player can be used.
+This directory contains the sources of such players.
+The class TestPlayerStub uses the dynamic loader to load any of them.
+
+
+
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
new file mode 100644
index 0000000..77bb5b2
--- /dev/null
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "TestPlayerStub"
+#include "utils/Log.h"
+
+#include <string.h>
+
+#include <binder/Parcel.h>
+#include <media/MediaPlayerInterface.h>
+#include <utils/Errors.h>
+
+using android::INVALID_OPERATION;
+using android::ISurface;
+using android::MediaPlayerBase;
+using android::OK;
+using android::Parcel;
+using android::SortedVector;
+using android::TEST_PLAYER;
+using android::UNKNOWN_ERROR;
+using android::player_type;
+using android::sp;
+using android::status_t;
+
+// This file contains a test player that is loaded via the
+// TestPlayerStub class. The player contains various implementation
+// of the invoke method that java tests can use.
+
+namespace {
+const char *kPing = "ping";
+
+class Player: public MediaPlayerBase
+{
+ public:
+ enum TestType {TEST_UNKNOWN, PING};
+ Player() {}
+ virtual ~Player() {}
+
+ virtual status_t initCheck() {return OK;}
+ virtual bool hardwareOutput() {return true;}
+
+ virtual status_t setDataSource(const char *url) {
+ LOGV("setDataSource %s", url);
+ mTest = TEST_UNKNOWN;
+ if (strncmp(url, kPing, strlen(kPing)) == 0) {
+ mTest = PING;
+ }
+ return OK;
+ }
+
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
+ virtual status_t setVideoSurface(const sp<ISurface>& surface) {return OK;}
+ virtual status_t prepare() {return OK;}
+ virtual status_t prepareAsync() {return OK;}
+ virtual status_t start() {return OK;}
+ virtual status_t stop() {return OK;}
+ virtual status_t pause() {return OK;}
+ virtual bool isPlaying() {return true;}
+ virtual status_t seekTo(int msec) {return OK;}
+ virtual status_t getCurrentPosition(int *msec) {return OK;}
+ virtual status_t getDuration(int *msec) {return OK;}
+ virtual status_t reset() {return OK;}
+ virtual status_t setLooping(int loop) {return OK;}
+ virtual player_type playerType() {return TEST_PLAYER;}
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+
+ private:
+ // Take a request, copy it to the reply.
+ void ping(const Parcel& request, Parcel *reply);
+
+ status_t mStatus;
+ TestType mTest;
+};
+
+status_t Player::invoke(const Parcel& request, Parcel *reply)
+{
+ switch (mTest) {
+ case PING:
+ ping(request, reply);
+ break;
+ default: mStatus = UNKNOWN_ERROR;
+ }
+ return mStatus;
+}
+
+void Player::ping(const Parcel& request, Parcel *reply)
+{
+ const size_t len = request.dataAvail();
+
+ reply->setData(static_cast<const uint8_t*>(request.readInplace(len)), len);
+ mStatus = OK;
+}
+
+}
+
+extern "C" android::MediaPlayerBase* newPlayer()
+{
+ LOGD("New invoke test player");
+ return new Player();
+}
+
+extern "C" android::status_t deletePlayer(android::MediaPlayerBase *player)
+{
+ LOGD("Delete invoke test player");
+ delete player;
+ return OK;
+}
diff --git a/obex/Android.mk b/obex/Android.mk
new file mode 100644
index 0000000..fbfe9be
--- /dev/null
+++ b/obex/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= javax.obex
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java
new file mode 100644
index 0000000..a62210f
--- /dev/null
+++ b/obex/javax/obex/ApplicationParameter.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+/**
+ * @hide
+ */
+public final class ApplicationParameter {
+
+ private byte[] mArray;
+
+ private int mLength;
+
+ private int mMaxLength = 1000;
+
+ public static class TRIPLET_TAGID {
+ public static final byte ORDER_TAGID = 0x01;
+
+ public static final byte SEARCH_VALUE_TAGID = 0x02;
+
+ public static final byte SEARCH_ATTRIBUTE_TAGID = 0x03;
+
+ // if equals to "0", PSE only reply number of contacts
+ public static final byte MAXLISTCOUNT_TAGID = 0x04;
+
+ public static final byte LISTSTARTOFFSET_TAGID = 0x05;
+
+ public static final byte FILTER_TAGID = 0x06;
+
+ public static final byte FORMAT_TAGID = 0x07;
+
+ // only used if max list count = 0
+ public static final byte PHONEBOOKSIZE_TAGID = 0x08;
+
+ // only used in "mch" in response
+ public static final byte NEWMISSEDCALLS_TAGID = 0x09;
+ }
+
+ public static class TRIPLET_VALUE {
+ public static class ORDER {
+ public static final byte ORDER_BY_INDEX = 0x00;
+
+ public static final byte ORDER_BY_ALPHANUMERIC = 0x01;
+
+ public static final byte ORDER_BY_PHONETIC = 0x02;
+ }
+
+ public static class SEARCHATTRIBUTE {
+ public static final byte SEARCH_BY_NAME = 0x00;
+
+ public static final byte SEARCH_BY_NUMBER = 0x01;
+
+ public static final byte SEARCH_BY_SOUND = 0x02;
+ }
+
+ public static class FORMAT {
+ public static final byte VCARD_VERSION_21 = 0x00;
+
+ public static final byte VCARD_VERSION_30 = 0x01;
+ }
+ }
+
+ public static class TRIPLET_LENGTH {
+ public static final byte ORDER_LENGTH = 1;
+
+ public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
+
+ public static final byte MAXLISTCOUNT_LENGTH = 2;
+
+ public static final byte LISTSTARTOFFSET_LENGTH = 2;
+
+ public static final byte FILTER_LENGTH = 8;
+
+ public static final byte FORMAT_LENGTH = 1;
+
+ public static final byte PHONEBOOKSIZE_LENGTH = 2;
+
+ public static final byte NEWMISSEDCALLS_LENGTH = 1;
+ }
+
+ public ApplicationParameter() {
+ mArray = new byte[mMaxLength];
+ mLength = 0;
+ }
+
+ public void addAPPHeader(byte tag, byte len, byte[] value) {
+ if ((mLength + len + 2) > mMaxLength) {
+ byte[] array_tmp = new byte[mLength + 4 * len];
+ System.arraycopy(mArray, 0, array_tmp, 0, mLength);
+ mArray = array_tmp;
+ mMaxLength = mLength + 4 * len;
+ }
+ mArray[mLength++] = tag;
+ mArray[mLength++] = len;
+ System.arraycopy(value, 0, mArray, mLength, len);
+ mLength += len;
+ }
+
+ public byte[] getAPPparam() {
+ byte[] para = new byte[mLength];
+ System.arraycopy(mArray, 0, para, 0, mLength);
+ return para;
+ }
+}
diff --git a/obex/javax/obex/Authenticator.java b/obex/javax/obex/Authenticator.java
new file mode 100644
index 0000000..ec226fb
--- /dev/null
+++ b/obex/javax/obex/Authenticator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+/**
+ * This interface provides a way to respond to authentication challenge and
+ * authentication response headers. When a client or server receives an
+ * authentication challenge or authentication response header, the
+ * <code>onAuthenticationChallenge()</code> or
+ * <code>onAuthenticationResponse()</code> will be called, respectively, by the
+ * implementation.
+ * <P>
+ * For more information on how the authentication procedure works in OBEX,
+ * please review the IrOBEX specification at <A
+ * HREF="http://www.irda.org">http://www.irda.org</A>.
+ * <P>
+ * <STRONG>Authentication Challenges</STRONG>
+ * <P>
+ * When a client or server receives an authentication challenge header, the
+ * <code>onAuthenticationChallenge()</code> method will be invoked by the OBEX
+ * API implementation. The application will then return the user name (if
+ * needed) and password via a <code>PasswordAuthentication</code> object. The
+ * password in this object is not sent in the authentication response. Instead,
+ * the 16-byte challenge received in the authentication challenge is combined
+ * with the password returned from the <code>onAuthenticationChallenge()</code>
+ * method and passed through the MD5 hash algorithm. The resulting value is sent
+ * in the authentication response along with the user name if it was provided.
+ * <P>
+ * <STRONG>Authentication Responses</STRONG>
+ * <P>
+ * When a client or server receives an authentication response header, the
+ * <code>onAuthenticationResponse()</code> method is invoked by the API
+ * implementation with the user name received in the authentication response
+ * header. (The user name will be <code>null</code> if no user name was provided
+ * in the authentication response header.) The application must determine the
+ * correct password. This value should be returned from the
+ * <code>onAuthenticationResponse()</code> method. If the authentication request
+ * should fail without the implementation checking the password,
+ * <code>null</code> should be returned by the application. (This is needed for
+ * reasons like not recognizing the user name, etc.) If the returned value is
+ * not <code>null</code>, the OBEX API implementation will combine the password
+ * returned from the <code>onAuthenticationResponse()</code> method and
+ * challenge sent via the authentication challenge, apply the MD5 hash
+ * algorithm, and compare the result to the response hash received in the
+ * authentication response header. If the values are not equal, an
+ * <code>IOException</code> will be thrown if the client requested
+ * authentication. If the server requested authentication, the
+ * <code>onAuthenticationFailure()</code> method will be called on the
+ * <code>ServerRequestHandler</code> that failed authentication. The connection
+ * is <B>not</B> closed if authentication failed.
+ * @hide
+ */
+public interface Authenticator {
+
+ /**
+ * Called when a client or a server receives an authentication challenge
+ * header. It should respond to the challenge with a
+ * <code>PasswordAuthentication</code> that contains the correct user name
+ * and password for the challenge.
+ * @param description the description of which user name and password should
+ * be used; if no description is provided in the authentication
+ * challenge or the description is encoded in an encoding scheme that
+ * is not supported, an empty string will be provided
+ * @param isUserIdRequired <code>true</code> if the user ID is required;
+ * <code>false</code> if the user ID is not required
+ * @param isFullAccess <code>true</code> if full access to the server will
+ * be granted; <code>false</code> if read only access will be granted
+ * @return a <code>PasswordAuthentication</code> object containing the user
+ * name and password used for authentication
+ */
+ PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
+ boolean isFullAccess);
+
+ /**
+ * Called when a client or server receives an authentication response
+ * header. This method will provide the user name and expect the correct
+ * password to be returned.
+ * @param userName the user name provided in the authentication response; may
+ * be <code>null</code>
+ * @return the correct password for the user name provided; if
+ * <code>null</code> is returned then the authentication request
+ * failed
+ */
+ byte[] onAuthenticationResponse(byte[] userName);
+}
diff --git a/obex/javax/obex/BaseStream.java b/obex/javax/obex/BaseStream.java
new file mode 100644
index 0000000..022ad4f
--- /dev/null
+++ b/obex/javax/obex/BaseStream.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * This interface defines the methods needed by a parent that uses the
+ * PrivateInputStream and PrivateOutputStream objects defined in this package.
+ * @hide
+ */
+public interface BaseStream {
+
+ /**
+ * Verifies that this object is still open.
+ * @throws IOException if the object is closed
+ */
+ void ensureOpen() throws IOException;
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * @throws IOException if the operation is completed
+ */
+ void ensureNotDone() throws IOException;
+
+ /**
+ * Continues the operation since there is no data to read.
+ * @param sendEmpty <code>true</code> if the operation should send an empty
+ * packet or not send anything if there is no data to send
+ * @param inStream <code>true</code> if the stream is input stream or is
+ * output stream
+ * @return <code>true</code> if the operation was completed;
+ * <code>false</code> if no operation took place
+ * @throws IOException if an IO error occurs
+ */
+ boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
+
+ /**
+ * Called when the output or input stream is closed.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ void streamClosed(boolean inStream) throws IOException;
+}
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
new file mode 100644
index 0000000..65663b1
--- /dev/null
+++ b/obex/javax/obex/ClientOperation.java
@@ -0,0 +1,720 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class implements the <code>Operation</code> interface. It will read and
+ * write data via puts and gets.
+ * @hide
+ */
+public final class ClientOperation implements Operation, BaseStream {
+
+ private ClientSession mParent;
+
+ private boolean mInputOpen;
+
+ private PrivateInputStream mPrivateInput;
+
+ private boolean mPrivateInputOpen;
+
+ private PrivateOutputStream mPrivateOutput;
+
+ private boolean mPrivateOutputOpen;
+
+ private String mExceptionMessage;
+
+ private int mMaxPacketSize;
+
+ private boolean mOperationDone;
+
+ private boolean mGetOperation;
+
+ private HeaderSet mRequestHeader;
+
+ private HeaderSet mReplyHeader;
+
+ private boolean mEndOfBodySent;
+
+ /**
+ * Creates new OperationImpl to read and write data to a server
+ * @param maxSize the maximum packet size
+ * @param p the parent to this object
+ * @param type <code>true</code> if this is a get request;
+ * <code>false</code. if this is a put request
+ * @param header the header to set in the initial request
+ * @throws IOException if the an IO error occurred
+ */
+ public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
+ throws IOException {
+
+ mParent = p;
+ mEndOfBodySent = false;
+ mInputOpen = true;
+ mOperationDone = false;
+ mMaxPacketSize = maxSize;
+ mGetOperation = type;
+
+ mPrivateInputOpen = false;
+ mPrivateOutputOpen = false;
+ mPrivateInput = null;
+ mPrivateOutput = null;
+
+ mReplyHeader = new HeaderSet();
+
+ mRequestHeader = new HeaderSet();
+
+ int[] headerList = header.getHeaderList();
+
+ if (headerList != null) {
+
+ for (int i = 0; i < headerList.length; i++) {
+ mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
+ }
+ }
+
+ if ((header).mAuthChall != null) {
+ mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
+ System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
+ (header).mAuthChall.length);
+ }
+
+ if ((header).mAuthResp != null) {
+ mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
+ System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
+ (header).mAuthResp.length);
+
+ }
+ }
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server called this method
+ */
+ public synchronized void abort() throws IOException {
+ ensureOpen();
+ //no compatible with sun-ri
+ if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ throw new IOException("Operation has already ended");
+ }
+
+ mExceptionMessage = "Operation aborted";
+ if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ mOperationDone = true;
+ /*
+ * Since we are not sending any headers or returning any headers then
+ * we just need to write and read the same bytes
+ */
+ mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
+ throw new IOException("Invalid response code from server");
+ }
+
+ mExceptionMessage = null;
+ }
+
+ close();
+ }
+
+ /**
+ * Retrieves the response code retrieved from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> interface.
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet</code> in a <code>ClientSession</code>
+ * object
+ */
+ public synchronized int getResponseCode() throws IOException {
+ //avoid dup validateConnection
+ if ((mReplyHeader.responseCode == -1)
+ || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ validateConnection();
+ }
+
+ return mReplyHeader.responseCode;
+ }
+
+ /**
+ * This method will always return <code>null</code>
+ * @return <code>null</code>
+ */
+ public String getEncoding() {
+ return null;
+ }
+
+ /**
+ * Returns the type of content that the resource connected to is providing.
+ * E.g. if the connection is via HTTP, then the value of the content-type
+ * header field is returned.
+ * @return the content type of the resource that the URL references, or
+ * <code>null</code> if not known
+ */
+ public String getType() {
+ try {
+ return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the length of the content which is being provided. E.g. if the
+ * connection is via HTTP, then the value of the content-length header field
+ * is returned.
+ * @return the content length of the resource that this connection's URL
+ * references, or -1 if the content length is not known
+ */
+ public long getLength() {
+ try {
+ Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
+
+ if (temp == null) {
+ return -1;
+ } else {
+ return temp.longValue();
+ }
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Open and return an input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public InputStream openInputStream() throws IOException {
+
+ ensureOpen();
+
+ if (mPrivateInputOpen)
+ throw new IOException("no more input streams available");
+ if (mGetOperation) {
+ // send the GET request here
+ validateConnection();
+ } else {
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ }
+
+ mPrivateInputOpen = true;
+
+ return mPrivateInput;
+ }
+
+ /**
+ * Open and return a data input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ /**
+ * Open and return an output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public OutputStream openOutputStream() throws IOException {
+
+ ensureOpen();
+ ensureNotDone();
+
+ if (mPrivateOutputOpen)
+ throw new IOException("no more output streams available");
+
+ if (mPrivateOutput == null) {
+ // there are 3 bytes operation headers and 3 bytes body headers //
+ mPrivateOutput = new PrivateOutputStream(this, mMaxPacketSize - 6);
+ }
+
+ mPrivateOutputOpen = true;
+
+ return mPrivateOutput;
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketSize - 6;
+ }
+
+ /**
+ * Open and return a data output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ /**
+ * Closes the connection and ends the transaction
+ * @throws IOException if the operation has already ended or is closed
+ */
+ public void close() throws IOException {
+ mInputOpen = false;
+ mPrivateInputOpen = false;
+ mPrivateOutputOpen = false;
+ mParent.setRequestInactive();
+ }
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ public HeaderSet getReceivedHeader() throws IOException {
+ ensureOpen();
+
+ return mReplyHeader;
+ }
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ * @throws NullPointerException if <code>headers</code> is <code>null</code>
+ */
+ public void sendHeaders(HeaderSet headers) throws IOException {
+ ensureOpen();
+ if (mOperationDone) {
+ throw new IOException("Operation has already exchanged all data");
+ }
+
+ if (headers == null) {
+ throw new IOException("Headers may not be null");
+ }
+
+ int[] headerList = headers.getHeaderList();
+ if (headerList != null) {
+ for (int i = 0; i < headerList.length; i++) {
+ mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+ }
+ }
+ }
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * @throws IOException if the operation is completed
+ */
+ public void ensureNotDone() throws IOException {
+ if (mOperationDone) {
+ throw new IOException("Operation has completed");
+ }
+ }
+
+ /**
+ * Verifies that the connection is open and no exceptions should be thrown.
+ * @throws IOException if an exception needs to be thrown
+ */
+ public void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+
+ if (mExceptionMessage != null) {
+ throw new IOException(mExceptionMessage);
+ }
+ if (!mInputOpen) {
+ throw new IOException("Operation has already ended");
+ }
+ }
+
+ /**
+ * Verifies that the connection is open and the proper data has been read.
+ * @throws IOException if an IO error occurs
+ */
+ private void validateConnection() throws IOException {
+ ensureOpen();
+
+ // to sure only one privateInput object exist.
+ if (mPrivateInput == null) {
+ startProcessing();
+ }
+ }
+
+ /**
+ * Sends a request to the client of the specified type
+ * @param opCode the request code to send to the client
+ * @return <code>true</code> if there is more data to send;
+ * <code>false</code> if there is no more data to send
+ * @throws IOException if an IO error occurs
+ */
+ private boolean sendRequest(int opCode) throws IOException {
+ boolean returnValue = false;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int bodyLength = -1;
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
+ if (mPrivateOutput != null) {
+ bodyLength = mPrivateOutput.size();
+ }
+
+ /*
+ * Determine if there is space to add a body request. At present
+ * this method checks to see if there is room for at least a 17
+ * byte body header. This number needs to be at least 6 so that
+ * there is room for the header ID and length and the reply ID and
+ * length, but it is a waste of resources if we can't send much of
+ * the body.
+ */
+ if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
+ int end = 0;
+ int start = 0;
+ // split & send the headerArray in multiple packets.
+
+ while (end != headerArray.length) {
+ //split the headerArray
+ end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
+ - ObexHelper.BASE_PACKET_LENGTH);
+ // can not split
+ if (end == -1) {
+ mOperationDone = true;
+ abort();
+ mExceptionMessage = "Header larger then can be sent in a packet";
+ mInputOpen = false;
+
+ if (mPrivateInput != null) {
+ mPrivateInput.close();
+ }
+
+ if (mPrivateOutput != null) {
+ mPrivateOutput.close();
+ }
+ throw new IOException("OBEX Packet exceeds max packet size");
+ }
+
+ byte[] sendHeader = new byte[end - start];
+ System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+ if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput)) {
+ return false;
+ }
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ return false;
+ }
+
+ start = end;
+ }
+
+ if (bodyLength > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ out.write(headerArray);
+ }
+
+ if (bodyLength > 0) {
+ /*
+ * Determine if we can send the whole body or just part of
+ * the body. Remember that there is the 3 bytes for the
+ * response message and 3 bytes for the header ID and length
+ */
+ if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
+ returnValue = true;
+
+ bodyLength = mMaxPacketSize - headerArray.length - 6;
+ }
+
+ byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+ /*
+ * Since this is a put request if the final bit is set or
+ * the output stream is closed we need to send the 0x49
+ * (End of Body) otherwise, we need to send 0x48 (Body)
+ */
+ if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
+ && ((opCode & 0x80) != 0)) {
+ out.write(0x49);
+ mEndOfBodySent = true;
+ } else {
+ out.write(0x48);
+ }
+
+ bodyLength += 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+
+ if (body != null) {
+ out.write(body);
+ }
+ }
+
+ if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
+ // only 0x82 or 0x83 can send 0x49
+ if ((opCode & 0x80) == 0) {
+ out.write(0x48);
+ } else {
+ out.write(0x49);
+ mEndOfBodySent = true;
+
+ }
+
+ bodyLength = 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+ }
+
+ if (out.size() == 0) {
+ if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput)) {
+ return false;
+ }
+ return returnValue;
+ }
+ if ((out.size() > 0)
+ && (!mParent.sendRequest(opCode, out.toByteArray(), mReplyHeader, mPrivateInput))) {
+ return false;
+ }
+
+ // send all of the output data in 0x48,
+ // send 0x49 with empty body
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
+ returnValue = true;
+
+ return returnValue;
+ }
+
+ /**
+ * This method starts the processing thread results. It will send the
+ * initial request. If the response takes more then one packet, a thread
+ * will be started to handle additional requests
+ * @throws IOException if an IO error occurs
+ */
+ private synchronized void startProcessing() throws IOException {
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ boolean more = true;
+
+ if (mGetOperation) {
+ if (!mOperationDone) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x03);
+ }
+
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ }
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ } else {
+
+ if (!mOperationDone) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x02);
+
+ }
+ }
+
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
+ }
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ }
+
+ /**
+ * Continues the operation since there is no data to read.
+ * @param sendEmpty <code>true</code> if the operation should send an empty
+ * packet or not send anything if there is no data to send
+ * @param inStream <code>true</code> if the stream is input stream or is
+ * output stream
+ * @throws IOException if an IO error occurs
+ */
+ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+ throws IOException {
+
+ if (mGetOperation) {
+ if ((inStream) && (!mOperationDone)) {
+ // to deal with inputstream in get operation
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ /*
+ * Determine if that was not the last packet in the operation
+ */
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+
+ return true;
+
+ } else if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in get operation
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ sendRequest(0x03);
+ return true;
+
+ } else if (mOperationDone) {
+ return false;
+ }
+
+ } else {
+ if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in put operation
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+ sendRequest(0x02);
+ return true;
+ } else if ((inStream) && (!mOperationDone)) {
+ // How to deal with inputstream in put operation ?
+ return false;
+
+ } else if (mOperationDone) {
+ return false;
+ }
+
+ }
+ return false;
+ }
+
+ /**
+ * Called when the output or input stream is closed.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ public void streamClosed(boolean inStream) throws IOException {
+ if (!mGetOperation) {
+ if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in put operation
+
+ boolean more = true;
+
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+ if (headerArray.length <= 0)
+ more = false;
+ }
+ // If have not sent any data so send all now
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x02);
+ }
+
+ /*
+ * According to the IrOBEX specification, after the final put, you
+ * only have a single reply to send. so we don't need the while
+ * loop.
+ */
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+
+ sendRequest(0x82);
+ }
+ mOperationDone = true;
+ } else if ((inStream) && (mOperationDone)) {
+ // how to deal with input stream in put stream ?
+ mOperationDone = true;
+ }
+ } else {
+ if ((inStream) && (!mOperationDone)) {
+
+ // to deal with inputstream in get operation
+ // Have not sent any data so send it all now
+
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ if (!sendRequest(0x83)) {
+ break;
+ }
+ }
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ }
+ mOperationDone = true;
+ } else if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in get operation
+ // part of the data may have been sent in continueOperation.
+
+ boolean more = true;
+
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+ if (headerArray.length <= 0)
+ more = false;
+ }
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
+ more = false;
+
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x03);
+ }
+ sendRequest(0x83);
+ // parent.sendRequest(0x83, null, replyHeaders, privateInput);
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ }
+ }
+}
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
new file mode 100644
index 0000000..0935383
--- /dev/null
+++ b/obex/javax/obex/ClientSession.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This class in an implementation of the OBEX ClientSession.
+ * @hide
+ */
+public final class ClientSession extends ObexSession {
+
+ private boolean mOpen;
+
+ // Determines if an OBEX layer connection has been established
+ private boolean mObexConnected;
+
+ private byte[] mConnectionId = null;
+
+ /*
+ * The max Packet size must be at least 256 according to the OBEX
+ * specification.
+ */
+ private int maxPacketSize = 256;
+
+ private boolean mRequestActive;
+
+ private final InputStream mInput;
+
+ private final OutputStream mOutput;
+
+ public ClientSession(final ObexTransport trans) throws IOException {
+ mInput = trans.openInputStream();
+ mOutput = trans.openOutputStream();
+ mOpen = true;
+ mRequestActive = false;
+ }
+
+ public HeaderSet connect(final HeaderSet header) throws IOException {
+ ensureOpen();
+ if (mObexConnected) {
+ throw new IOException("Already connected to server");
+ }
+ setRequestActive();
+
+ int totalLength = 4;
+ byte[] head = null;
+
+ // Determine the header byte array
+ if (header != null) {
+ if (header.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ head = ObexHelper.createHeader(header, false);
+ totalLength += head.length;
+ }
+ /*
+ * Write the OBEX CONNECT packet to the server.
+ * Byte 0: 0x80
+ * Byte 1&2: Connect Packet Length
+ * Byte 3: OBEX Version Number (Presently, 0x10)
+ * Byte 4: Flags (For TCP 0x00)
+ * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
+ * Byte 7 to n: headers
+ */
+ byte[] requestPacket = new byte[totalLength];
+ // We just need to start at byte 3 since the sendRequest() method will
+ // handle the length and 0x80.
+ requestPacket[0] = (byte)0x10;
+ requestPacket[1] = (byte)0x00;
+ requestPacket[2] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
+ requestPacket[3] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+ if (head != null) {
+ System.arraycopy(head, 0, requestPacket, 4, head.length);
+ }
+
+ // check with local max packet size
+ if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
+
+ /*
+ * Read the response from the OBEX server.
+ * Byte 0: Response Code (If successful then OBEX_HTTP_OK)
+ * Byte 1&2: Packet Length
+ * Byte 3: OBEX Version Number
+ * Byte 4: Flags3
+ * Byte 5&6: Max OBEX packet Length
+ * Byte 7 to n: Optional HeaderSet
+ */
+ if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
+ mObexConnected = true;
+ }
+ setRequestInactive();
+
+ return returnHeaderSet;
+ }
+
+ public Operation get(HeaderSet header) throws IOException {
+
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+
+ HeaderSet head;
+ if (header == null) {
+ head = new HeaderSet();
+ } else {
+ head = header;
+ if (head.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ head.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+ }
+
+ return new ClientOperation(maxPacketSize, this, head, true);
+ }
+
+ /**
+ * 0xCB Connection Id an identifier used for OBEX connection multiplexing
+ */
+ public void setConnectionID(long id) {
+ if ((id < 0) || (id > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Connection ID is not in a valid range");
+ }
+ mConnectionId = ObexHelper.convertToByteArray(id);
+ }
+
+ public HeaderSet delete(HeaderSet header) throws IOException {
+
+ Operation op = put(header);
+ op.getResponseCode();
+ HeaderSet returnValue = op.getReceivedHeader();
+ op.close();
+
+ return returnValue;
+ }
+
+ public HeaderSet disconnect(HeaderSet header) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+ // Determine the header byte array
+ byte[] head = null;
+ if (header != null) {
+ if (header.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ header.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
+ }
+ head = ObexHelper.createHeader(header, false);
+
+ if ((head.length + 3) > maxPacketSize) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+ } else {
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ head = new byte[5];
+ head[0] = (byte)HeaderSet.CONNECTION_ID;
+ System.arraycopy(mConnectionId, 0, head, 1, 4);
+ }
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
+
+ /*
+ * An OBEX DISCONNECT reply from the server:
+ * Byte 1: Response code
+ * Bytes 2 & 3: packet size
+ * Bytes 4 & up: headers
+ */
+
+ /* response code , and header are ignored
+ * */
+
+ synchronized (this) {
+ mObexConnected = false;
+ setRequestInactive();
+ }
+
+ return returnHeaderSet;
+ }
+
+ public long getConnectionID() {
+
+ if (mConnectionId == null) {
+ return -1;
+ }
+ return ObexHelper.convertToLong(mConnectionId);
+ }
+
+ public Operation put(HeaderSet header) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+ HeaderSet head;
+ if (header == null) {
+ head = new HeaderSet();
+ } else {
+ head = header;
+ // when auth is initiated by client ,save the digest
+ if (head.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+
+ head.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+ }
+
+ return new ClientOperation(maxPacketSize, this, head, false);
+ }
+
+ public void setAuthenticator(Authenticator auth) throws IOException {
+ if (auth == null) {
+ throw new IOException("Authenticator may not be null");
+ }
+ mAuthenticator = auth;
+ }
+
+ public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+ ensureOpen();
+
+ int totalLength = 2;
+ byte[] head = null;
+ HeaderSet headset;
+ if (header == null) {
+ headset = new HeaderSet();
+ } else {
+ headset = header;
+ if (headset.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+
+ // when auth is initiated by client ,save the digest
+ if (headset.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+ }
+
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ headset.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
+ }
+
+ head = ObexHelper.createHeader(headset, false);
+ totalLength += head.length;
+
+ if (totalLength > maxPacketSize) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+
+ int flags = 0;
+ /*
+ * The backup flag bit is bit 0 so if we add 1, this will set that bit
+ */
+ if (backup) {
+ flags++;
+ }
+ /*
+ * The create bit is bit 1 so if we or with 2 the bit will be set.
+ */
+ if (!create) {
+ flags |= 2;
+ }
+
+ /*
+ * An OBEX SETPATH packet to the server:
+ * Byte 1: 0x85
+ * Byte 2 & 3: packet size
+ * Byte 4: flags
+ * Byte 5: constants
+ * Byte 6 & up: headers
+ */
+ byte[] packet = new byte[totalLength];
+ packet[0] = (byte)flags;
+ packet[1] = (byte)0x00;
+ if (headset != null) {
+ System.arraycopy(head, 0, packet, 2, head.length);
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
+
+ /*
+ * An OBEX SETPATH reply from the server:
+ * Byte 1: Response code
+ * Bytes 2 & 3: packet size
+ * Bytes 4 & up: headers
+ */
+
+ setRequestInactive();
+
+ return returnHeaderSet;
+ }
+
+ /**
+ * Verifies that the connection is open.
+ * @throws IOException if the connection is closed
+ */
+ public synchronized void ensureOpen() throws IOException {
+ if (!mOpen) {
+ throw new IOException("Connection closed");
+ }
+ }
+
+ /**
+ * Set request inactive. Allows Put and get operation objects to tell this
+ * object when they are done.
+ */
+ /*package*/synchronized void setRequestInactive() {
+ mRequestActive = false;
+ }
+
+ /**
+ * Set request to active.
+ * @throws IOException if already active
+ */
+ private synchronized void setRequestActive() throws IOException {
+ if (mRequestActive) {
+ throw new IOException("OBEX request is already being performed");
+ }
+ mRequestActive = true;
+ }
+
+ /**
+ * Sends a standard request to the client. It will then wait for the reply
+ * and update the header set object provided. If any authentication headers
+ * (i.e. authentication challenge or authentication response) are received,
+ * they will be processed.
+ * @param opCode the type of request to send to the client
+ * @param head the headers to send to the client
+ * @param header the header object to update with the response
+ * @param privateInput the input stream used by the Operation object; null
+ * if this is called on a CONNECT, SETPATH or DISCONNECT return
+ * <code>true</code> if the operation completed successfully;
+ * <code>false</code> if an authentication response failed to pass
+ * @throws IOException if an IO error occurs
+ */
+ public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
+ PrivateInputStream privateInput) throws IOException {
+ //check header length with local max size
+ if (head != null) {
+ if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("header too large ");
+ }
+ }
+
+ int bytesReceived;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ out.write((byte)opCode);
+
+ // Determine if there are any headers to send
+ if (head == null) {
+ out.write(0x00);
+ out.write(0x03);
+ } else {
+ out.write((byte)((head.length + 3) >> 8));
+ out.write((byte)(head.length + 3));
+ out.write(head);
+ }
+
+ // Write the request to the output stream and flush the stream
+ mOutput.write(out.toByteArray());
+ mOutput.flush();
+
+ header.responseCode = mInput.read();
+
+ int length = ((mInput.read() << 8) | (mInput.read()));
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("Packet received exceeds packet size limit");
+ }
+ if (length > ObexHelper.BASE_PACKET_LENGTH) {
+ byte[] data = null;
+ if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
+ @SuppressWarnings("unused")
+ int version = mInput.read();
+ @SuppressWarnings("unused")
+ int flags = mInput.read();
+ maxPacketSize = (mInput.read() << 8) + mInput.read();
+
+ //check with local max size
+ if (maxPacketSize > ObexHelper.MAX_PACKET_SIZE_INT) {
+ maxPacketSize = ObexHelper.MAX_PACKET_SIZE_INT;
+ }
+
+ if (length > 7) {
+ data = new byte[length - 7];
+
+ bytesReceived = mInput.read(data);
+ while (bytesReceived != (length - 7)) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length
+ - bytesReceived);
+ }
+ } else {
+ return true;
+ }
+ } else {
+ data = new byte[length - 3];
+ bytesReceived = mInput.read(data);
+
+ while (bytesReceived != (length - 3)) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
+ }
+ if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
+ return true;
+ }
+ }
+
+ byte[] body = ObexHelper.updateHeaderSet(header, data);
+ if ((privateInput != null) && (body != null)) {
+ privateInput.writeBytes(body, 1);
+ }
+
+ if (header.mConnectionID != null) {
+ mConnectionId = new byte[4];
+ System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
+ }
+
+ if (header.mAuthResp != null) {
+ if (!handleAuthResp(header.mAuthResp)) {
+ setRequestInactive();
+ throw new IOException("Authentication Failed");
+ }
+ }
+
+ if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
+ && (header.mAuthChall != null)) {
+
+ if (handleAuthChall(header)) {
+ out.write((byte)HeaderSet.AUTH_RESPONSE);
+ out.write((byte)((header.mAuthResp.length + 3) >> 8));
+ out.write((byte)(header.mAuthResp.length + 3));
+ out.write(header.mAuthResp);
+ header.mAuthChall = null;
+ header.mAuthResp = null;
+
+ byte[] sendHeaders = new byte[out.size() - 3];
+ System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
+
+ return sendRequest(opCode, sendHeaders, header, privateInput);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void close() throws IOException {
+ mOpen = false;
+ mInput.close();
+ mOutput.close();
+ }
+}
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
new file mode 100644
index 0000000..8b457f6
--- /dev/null
+++ b/obex/javax/obex/HeaderSet.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Random;
+
+/**
+ * This class implements the javax.obex.HeaderSet interface for OBEX over
+ * RFCOMM.
+ * @hide
+ */
+public final class HeaderSet {
+
+ /**
+ * Represents the OBEX Count header. This allows the connection statement to
+ * tell the server how many objects it plans to send or retrieve.
+ * <P>
+ * The value of <code>COUNT</code> is 0xC0 (192).
+ */
+ public static final int COUNT = 0xC0;
+
+ /**
+ * Represents the OBEX Name header. This specifies the name of the object.
+ * <P>
+ * The value of <code>NAME</code> is 0x01 (1).
+ */
+ public static final int NAME = 0x01;
+
+ /**
+ * Represents the OBEX Type header. This allows a request to specify the
+ * type of the object (e.g. text, html, binary, etc.).
+ * <P>
+ * The value of <code>TYPE</code> is 0x42 (66).
+ */
+ public static final int TYPE = 0x42;
+
+ /**
+ * Represents the OBEX Length header. This is the length of the object in
+ * bytes.
+ * <P>
+ * The value of <code>LENGTH</code> is 0xC3 (195).
+ */
+ public static final int LENGTH = 0xC3;
+
+ /**
+ * Represents the OBEX Time header using the ISO 8601 standards. This is the
+ * preferred time header.
+ * <P>
+ * The value of <code>TIME_ISO_8601</code> is 0x44 (68).
+ */
+ public static final int TIME_ISO_8601 = 0x44;
+
+ /**
+ * Represents the OBEX Time header using the 4 byte representation. This is
+ * only included for backwards compatibility. It represents the number of
+ * seconds since January 1, 1970.
+ * <P>
+ * The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
+ */
+ public static final int TIME_4_BYTE = 0xC4;
+
+ /**
+ * Represents the OBEX Description header. This is a text description of the
+ * object.
+ * <P>
+ * The value of <code>DESCRIPTION</code> is 0x05 (5).
+ */
+ public static final int DESCRIPTION = 0x05;
+
+ /**
+ * Represents the OBEX Target header. This is the name of the service an
+ * operation is targeted to.
+ * <P>
+ * The value of <code>TARGET</code> is 0x46 (70).
+ */
+ public static final int TARGET = 0x46;
+
+ /**
+ * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
+ * included in a request or reply.
+ * <P>
+ * The value of <code>HTTP</code> is 0x47 (71).
+ */
+ public static final int HTTP = 0x47;
+
+ /**
+ * Represents the OBEX BODY header.
+ * <P>
+ * The value of <code>BODY</code> is 0x48 (72).
+ */
+ public static final int BODY = 0x48;
+
+ /**
+ * Represents the OBEX End of BODY header.
+ * <P>
+ * The value of <code>BODY</code> is 0x49 (73).
+ */
+ public static final int END_OF_BODY = 0x49;
+
+ /**
+ * Represents the OBEX Who header. Identifies the OBEX application to
+ * determine if the two peers are talking to each other.
+ * <P>
+ * The value of <code>WHO</code> is 0x4A (74).
+ */
+ public static final int WHO = 0x4A;
+
+ /**
+ * Represents the OBEX Connection ID header. Identifies used for OBEX
+ * connection multiplexing.
+ * <P>
+ * The value of <code>CONNECTION_ID</code> is 0xCB (203).
+ */
+
+ public static final int CONNECTION_ID = 0xCB;
+
+ /**
+ * Represents the OBEX Application Parameter header. This header specifies
+ * additional application request and response information.
+ * <P>
+ * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
+ */
+ public static final int APPLICATION_PARAMETER = 0x4C;
+
+ /**
+ * Represents the OBEX authentication digest-challenge.
+ * <P>
+ * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
+ */
+ public static final int AUTH_CHALLENGE = 0x4D;
+
+ /**
+ * Represents the OBEX authentication digest-response.
+ * <P>
+ * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
+ */
+ public static final int AUTH_RESPONSE = 0x4E;
+
+ /**
+ * Represents the OBEX Object Class header. This header specifies the OBEX
+ * object class of the object.
+ * <P>
+ * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
+ */
+ public static final int OBJECT_CLASS = 0x4F;
+
+ private Long mCount; // 4 byte unsigned integer
+
+ private String mName; // null terminated Unicode text string
+
+ private String mType; // null terminated ASCII text string
+
+ private Long mLength; // 4 byte unsigend integer
+
+ private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
+
+ private Calendar mByteTime; // 4 byte unsigned integer
+
+ private String mDescription; // null terminated Unicode text String
+
+ private byte[] mTarget; // byte sequence
+
+ private byte[] mHttpHeader; // byte sequence
+
+ private byte[] mWho; // length prefixed byte sequence
+
+ private byte[] mAppParam; // byte sequence of the form tag length value
+
+ private byte[] mObjectClass; // byte sequence
+
+ private String[] mUnicodeUserDefined; //null terminated unicode string
+
+ private byte[][] mSequenceUserDefined; // byte sequence user defined
+
+ private Byte[] mByteUserDefined; // 1 byte
+
+ private Long[] mIntegerUserDefined; // 4 byte unsigned integer
+
+ private final Random mRandom;
+
+ /*package*/ byte[] nonce;
+
+ public byte[] mAuthChall; // The authentication challenge header
+
+ public byte[] mAuthResp; // The authentication response header
+
+ public byte[] mConnectionID; // THe connection ID
+
+ public int responseCode;
+
+ /**
+ * Creates new <code>HeaderSet</code> object.
+ * @param size the max packet size for this connection
+ */
+ public HeaderSet() {
+ mUnicodeUserDefined = new String[16];
+ mSequenceUserDefined = new byte[16][];
+ mByteUserDefined = new Byte[16];
+ mIntegerUserDefined = new Long[16];
+ responseCode = -1;
+ mRandom = new Random();
+ }
+
+ /**
+ * Sets the value of the header identifier to the value provided. The type
+ * of object must correspond to the Java type defined in the description of
+ * this interface. If <code>null</code> is passed as the
+ * <code>headerValue</code> then the header will be removed from the set of
+ * headers to include in the next request.
+ * @param headerID the identifier to include in the message
+ * @param headerValue the value of the header identifier
+ * @throws IllegalArgumentException if the header identifier provided is not
+ * one defined in this interface or a user-defined header; if the
+ * type of <code>headerValue</code> is not the correct Java type as
+ * defined in the description of this interface\
+ */
+ public void setHeader(int headerID, Object headerValue) {
+ long temp = -1;
+
+ switch (headerID) {
+ case COUNT:
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mCount = null;
+ break;
+ }
+ throw new IllegalArgumentException("Count must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
+ }
+ mCount = (Long)headerValue;
+ break;
+ case NAME:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Name must be a String");
+ }
+ mName = (String)headerValue;
+ break;
+ case TYPE:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Type must be a String");
+ }
+ mType = (String)headerValue;
+ break;
+ case LENGTH:
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mLength = null;
+ break;
+ }
+ throw new IllegalArgumentException("Length must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
+ }
+ mLength = (Long)headerValue;
+ break;
+ case TIME_ISO_8601:
+ if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+ throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
+ }
+ mIsoTime = (Calendar)headerValue;
+ break;
+ case TIME_4_BYTE:
+ if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+ throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
+ }
+ mByteTime = (Calendar)headerValue;
+ break;
+ case DESCRIPTION:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Description must be a String");
+ }
+ mDescription = (String)headerValue;
+ break;
+ case TARGET:
+ if (headerValue == null) {
+ mTarget = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("Target must be a byte array");
+ } else {
+ mTarget = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
+ }
+ }
+ break;
+ case HTTP:
+ if (headerValue == null) {
+ mHttpHeader = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("HTTP must be a byte array");
+ } else {
+ mHttpHeader = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
+ }
+ }
+ break;
+ case WHO:
+ if (headerValue == null) {
+ mWho = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("WHO must be a byte array");
+ } else {
+ mWho = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
+ }
+ }
+ break;
+ case OBJECT_CLASS:
+ if (headerValue == null) {
+ mObjectClass = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("Object Class must be a byte array");
+ } else {
+ mObjectClass = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
+ }
+ }
+ break;
+ case APPLICATION_PARAMETER:
+ if (headerValue == null) {
+ mAppParam = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException(
+ "Application Parameter must be a byte array");
+ } else {
+ mAppParam = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
+ }
+ }
+ break;
+ default:
+ // Verify that it was not a Unicode String user Defined
+ if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException(
+ "Unicode String User Defined must be a String");
+ }
+ mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
+
+ break;
+ }
+ // Verify that it was not a byte sequence user defined value
+ if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+
+ if (headerValue == null) {
+ mSequenceUserDefined[headerID - 0x70] = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException(
+ "Byte Sequence User Defined must be a byte array");
+ } else {
+ mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
+ 0, mSequenceUserDefined[headerID - 0x70].length);
+ }
+ }
+ break;
+ }
+ // Verify that it was not a Byte user Defined
+ if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+ if ((headerValue != null) && (!(headerValue instanceof Byte))) {
+ throw new IllegalArgumentException("ByteUser Defined must be a Byte");
+ }
+ mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
+
+ break;
+ }
+ // Verify that is was not the 4 byte unsigned integer user
+ // defined header
+ if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mIntegerUserDefined[headerID - 0xF0] = null;
+ break;
+ }
+ throw new IllegalArgumentException("Integer User Defined must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException(
+ "Integer User Defined must be between 0 and 0xFFFFFFFF");
+ }
+ mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
+ break;
+ }
+ throw new IllegalArgumentException("Invalid Header Identifier");
+ }
+ }
+
+ /**
+ * Retrieves the value of the header identifier provided. The type of the
+ * Object returned is defined in the description of this interface.
+ * @param headerID the header identifier whose value is to be returned
+ * @return the value of the header provided or <code>null</code> if the
+ * header identifier specified is not part of this
+ * <code>HeaderSet</code> object
+ * @throws IllegalArgumentException if the <code>headerID</code> is not one
+ * defined in this interface or any of the user-defined headers
+ * @throws IOException if an error occurred in the transport layer during
+ * the operation or if the connection has been closed
+ */
+ public Object getHeader(int headerID) throws IOException {
+
+ switch (headerID) {
+ case COUNT:
+ return mCount;
+ case NAME:
+ return mName;
+ case TYPE:
+ return mType;
+ case LENGTH:
+ return mLength;
+ case TIME_ISO_8601:
+ return mIsoTime;
+ case TIME_4_BYTE:
+ return mByteTime;
+ case DESCRIPTION:
+ return mDescription;
+ case TARGET:
+ return mTarget;
+ case HTTP:
+ return mHttpHeader;
+ case WHO:
+ return mWho;
+ case OBJECT_CLASS:
+ return mObjectClass;
+ case APPLICATION_PARAMETER:
+ return mAppParam;
+ default:
+ // Verify that it was not a Unicode String user Defined
+ if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+ return mUnicodeUserDefined[headerID - 0x30];
+ }
+ // Verify that it was not a byte sequence user defined header
+ if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+ return mSequenceUserDefined[headerID - 0x70];
+ }
+ // Verify that it was not a byte user defined header
+ if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+ return mByteUserDefined[headerID - 0xB0];
+ }
+ // Verify that it was not a integer user defined header
+ if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+ return mIntegerUserDefined[headerID - 0xF0];
+ }
+ throw new IllegalArgumentException("Invalid Header Identifier");
+ }
+ }
+
+ /**
+ * Retrieves the list of headers that may be retrieved via the
+ * <code>getHeader</code> method that will not return <code>null</code>. In
+ * other words, this method returns all the headers that are available in
+ * this object.
+ * @see #getHeader
+ * @return the array of headers that are set in this object or
+ * <code>null</code> if no headers are available
+ * @throws IOException if an error occurred in the transport layer during
+ * the operation or the connection has been closed
+ */
+ public int[] getHeaderList() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ if (mCount != null) {
+ out.write(COUNT);
+ }
+ if (mName != null) {
+ out.write(NAME);
+ }
+ if (mType != null) {
+ out.write(TYPE);
+ }
+ if (mLength != null) {
+ out.write(LENGTH);
+ }
+ if (mIsoTime != null) {
+ out.write(TIME_ISO_8601);
+ }
+ if (mByteTime != null) {
+ out.write(TIME_4_BYTE);
+ }
+ if (mDescription != null) {
+ out.write(DESCRIPTION);
+ }
+ if (mTarget != null) {
+ out.write(TARGET);
+ }
+ if (mHttpHeader != null) {
+ out.write(HTTP);
+ }
+ if (mWho != null) {
+ out.write(WHO);
+ }
+ if (mAppParam != null) {
+ out.write(APPLICATION_PARAMETER);
+ }
+ if (mObjectClass != null) {
+ out.write(OBJECT_CLASS);
+ }
+
+ for (int i = 0x30; i < 0x40; i++) {
+ if (mUnicodeUserDefined[i - 0x30] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0x70; i < 0x80; i++) {
+ if (mSequenceUserDefined[i - 0x70] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0xB0; i < 0xC0; i++) {
+ if (mByteUserDefined[i - 0xB0] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0xF0; i < 0x100; i++) {
+ if (mIntegerUserDefined[i - 0xF0] != null) {
+ out.write(i);
+ }
+ }
+
+ byte[] headers = out.toByteArray();
+ out.close();
+
+ if ((headers == null) || (headers.length == 0)) {
+ return null;
+ }
+
+ int[] result = new int[headers.length];
+ for (int i = 0; i < headers.length; i++) {
+ // Convert the byte to a positive integer. That is, an integer
+ // between 0 and 256.
+ result[i] = headers[i] & 0xFF;
+ }
+
+ return result;
+ }
+
+ /**
+ * Sets the authentication challenge header. The <code>realm</code> will be
+ * encoded based upon the default encoding scheme used by the implementation
+ * to encode strings. Therefore, the encoding scheme used to encode the
+ * <code>realm</code> is application dependent.
+ * @param realm a short description that describes what password to use; if
+ * <code>null</code> no realm will be sent in the authentication
+ * challenge header
+ * @param userID if <code>true</code>, a user ID is required in the reply;
+ * if <code>false</code>, no user ID is required
+ * @param access if <code>true</code> then full access will be granted if
+ * successful; if <code>false</code> then read-only access will be
+ * granted if successful
+ * @throws IOException
+ */
+ public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
+ throws IOException {
+
+ nonce = new byte[16];
+ for (int i = 0; i < 16; i++) {
+ nonce[i] = (byte)mRandom.nextInt();
+ }
+
+ mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
+ }
+
+ /**
+ * Returns the response code received from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> class.
+ * @see ResponseCodes
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet()</code> in a <code>ClientSession</code>
+ * object; if this object was created by an OBEX server
+ */
+ public int getResponseCode() throws IOException {
+ if (responseCode == -1) {
+ throw new IOException("May not be called on a server");
+ } else {
+ return responseCode;
+ }
+ }
+}
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
new file mode 100644
index 0000000..f569595
--- /dev/null
+++ b/obex/javax/obex/ObexHelper.java
@@ -0,0 +1,990 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import android.security.Md5MessageDigest;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * This class defines a set of helper methods for the implementation of Obex.
+ * @hide
+ */
+public final class ObexHelper {
+
+ /**
+ * Defines the basic packet length used by OBEX. Every OBEX packet has the
+ * same basic format:<BR>
+ * Byte 0: Request or Response Code Byte 1&2: Length of the packet.
+ */
+ public static final int BASE_PACKET_LENGTH = 3;
+
+ /** Prevent object construction of helper class */
+ private ObexHelper() {
+ }
+
+ /**
+ * The maximum packet size for OBEX packets that this client can handle. At
+ * present, this must be changed for each port. TODO: The max packet size
+ * should be the Max incoming MTU minus TODO: L2CAP package headers and
+ * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
+ * LocalDevice.getProperty().
+ */
+ /*
+ * android note set as 0xFFFE to match remote MPS
+ */
+ public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
+
+ public static final int OBEX_OPCODE_CONNECT = 0x80;
+
+ public static final int OBEX_OPCODE_DISCONNECT = 0x81;
+
+ public static final int OBEX_OPCODE_PUT = 0x02;
+
+ public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
+
+ public static final int OBEX_OPCODE_GET = 0x03;
+
+ public static final int OBEX_OPCODE_GET_FINAL = 0x83;
+
+ public static final int OBEX_OPCODE_RESERVED = 0x04;
+
+ public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
+
+ public static final int OBEX_OPCODE_SETPATH = 0x85;
+
+ public static final int OBEX_OPCODE_ABORT = 0xFF;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
+
+ /**
+ * Updates the HeaderSet with the headers received in the byte array
+ * provided. Invalid headers are ignored.
+ * <P>
+ * The first two bits of an OBEX Header specifies the type of object that is
+ * being sent. The table below specifies the meaning of the high bits.
+ * <TABLE>
+ * <TR>
+ * <TH>Bits 8 and 7</TH>
+ * <TH>Value</TH>
+ * <TH>Description</TH>
+ * </TR>
+ * <TR>
+ * <TD>00</TD>
+ * <TD>0x00</TD>
+ * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
+ * </TR>
+ * <TR>
+ * <TD>01</TD>
+ * <TD>0x40</TD>
+ * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
+ * </TR>
+ * <TR>
+ * <TD>10</TD>
+ * <TD>0x80</TD>
+ * <TD>1 byte quantity</TD>
+ * </TR>
+ * <TR>
+ * <TD>11</TD>
+ * <TD>0xC0</TD>
+ * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
+ * </TR>
+ * </TABLE>
+ * This method uses the information in this table to determine the type of
+ * Java object to create and passes that object with the full header to
+ * setHeader() to update the HeaderSet object. Invalid headers will cause an
+ * exception to be thrown. When it is thrown, it is ignored.
+ * @param header the HeaderSet to update
+ * @param headerArray the byte array containing headers
+ * @return the result of the last start body or end body header provided;
+ * the first byte in the result will specify if a body or end of
+ * body is received
+ * @throws IOException if an invalid header was found
+ */
+ public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
+ int index = 0;
+ int length = 0;
+ int headerID;
+ byte[] value = null;
+ byte[] body = null;
+ HeaderSet headerImpl = header;
+ try {
+ while (index < headerArray.length) {
+ headerID = 0xFF & headerArray[index];
+ switch (headerID & (0xC0)) {
+
+ /*
+ * 0x00 is a unicode null terminate string with the first
+ * two bytes after the header identifier being the length
+ */
+ case 0x00:
+ // Fall through
+ /*
+ * 0x40 is a byte sequence with the first
+ * two bytes after the header identifier being the length
+ */
+ case 0x40:
+ boolean trimTail = true;
+ index++;
+ length = 0xFF & headerArray[index];
+ length = length << 8;
+ index++;
+ length += 0xFF & headerArray[index];
+ length -= 3;
+ index++;
+ value = new byte[length];
+ System.arraycopy(headerArray, index, value, 0, length);
+ if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
+ trimTail = false;
+ }
+ switch (headerID) {
+ case HeaderSet.TYPE:
+ try {
+ // Remove trailing null
+ if (trimTail == false) {
+ headerImpl.setHeader(headerID, new String(value, 0,
+ value.length, "ISO8859_1"));
+ } else {
+ headerImpl.setHeader(headerID, new String(value, 0,
+ value.length - 1, "ISO8859_1"));
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+ break;
+
+ case HeaderSet.AUTH_CHALLENGE:
+ headerImpl.mAuthChall = new byte[length];
+ System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
+ length);
+ break;
+
+ case HeaderSet.AUTH_RESPONSE:
+ headerImpl.mAuthResp = new byte[length];
+ System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
+ length);
+ break;
+
+ case HeaderSet.BODY:
+ /* Fall Through */
+ case HeaderSet.END_OF_BODY:
+ body = new byte[length + 1];
+ body[0] = (byte)headerID;
+ System.arraycopy(headerArray, index, body, 1, length);
+ break;
+
+ case HeaderSet.TIME_ISO_8601:
+ try {
+ String dateString = new String(value, "ISO8859_1");
+ Calendar temp = Calendar.getInstance();
+ if ((dateString.length() == 16)
+ && (dateString.charAt(15) == 'Z')) {
+ temp.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+ temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
+ 0, 4)));
+ temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
+ 4, 6)));
+ temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
+ .substring(6, 8)));
+ temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
+ .substring(9, 11)));
+ temp.set(Calendar.MINUTE, Integer.parseInt(dateString
+ .substring(11, 13)));
+ temp.set(Calendar.SECOND, Integer.parseInt(dateString
+ .substring(13, 15)));
+ headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+ break;
+
+ default:
+ if ((headerID & 0xC0) == 0x00) {
+ headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
+ value, true));
+ } else {
+ headerImpl.setHeader(headerID, value);
+ }
+ }
+
+ index += length;
+ break;
+
+ /*
+ * 0x80 is a byte header. The only valid byte headers are
+ * the 16 user defined byte headers.
+ */
+ case 0x80:
+ index++;
+ try {
+ headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
+ } catch (Exception e) {
+ // Not a valid header so ignore
+ }
+ index++;
+ break;
+
+ /*
+ * 0xC0 is a 4 byte unsigned integer header and with the
+ * exception of TIME_4_BYTE will be converted to a Long
+ * and added.
+ */
+ case 0xC0:
+ index++;
+ value = new byte[4];
+ System.arraycopy(headerArray, index, value, 0, 4);
+ try {
+ if (headerID != HeaderSet.TIME_4_BYTE) {
+ // Determine if it is a connection ID. These
+ // need to be handled differently
+ if (headerID == HeaderSet.CONNECTION_ID) {
+ headerImpl.mConnectionID = new byte[4];
+ System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
+ } else {
+ headerImpl.setHeader(headerID, Long
+ .valueOf(convertToLong(value)));
+ }
+ } else {
+ Calendar temp = Calendar.getInstance();
+ temp.setTime(new Date(convertToLong(value) * 1000L));
+ headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
+ }
+ } catch (Exception e) {
+ // Not a valid header so ignore
+ throw new IOException("Header was not formatted properly");
+ }
+ index += 4;
+ break;
+ }
+
+ }
+ } catch (IOException e) {
+ throw new IOException("Header was not formatted properly");
+ }
+
+ return body;
+ }
+
+ /**
+ * Creates the header part of OBEX packet based on the header provided.
+ * TODO: Could use getHeaderList() to get the array of headers to include
+ * and then use the high two bits to determine the the type of the object
+ * and construct the byte array from that. This will make the size smaller.
+ * @param head the header used to construct the byte array
+ * @param nullOut <code>true</code> if the header should be set to
+ * <code>null</code> once it is added to the array or
+ * <code>false</code> if it should not be nulled out
+ * @return the header of an OBEX packet
+ */
+ public static byte[] createHeader(HeaderSet head, boolean nullOut) {
+ Long intHeader = null;
+ String stringHeader = null;
+ Calendar dateHeader = null;
+ Byte byteHeader = null;
+ StringBuffer buffer = null;
+ byte[] value = null;
+ byte[] result = null;
+ byte[] lengthArray = new byte[2];
+ int length;
+ HeaderSet headImpl = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ headImpl = head;
+
+ try {
+ /*
+ * Determine if there is a connection ID to send. If there is,
+ * then it should be the first header in the packet.
+ */
+ if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
+
+ out.write((byte)HeaderSet.CONNECTION_ID);
+ out.write(headImpl.mConnectionID);
+ }
+
+ // Count Header
+ intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
+ if (intHeader != null) {
+ out.write((byte)HeaderSet.COUNT);
+ value = ObexHelper.convertToByteArray(intHeader.longValue());
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.COUNT, null);
+ }
+ }
+
+ // Name Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.NAME);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(0xFF & (length >> 8));
+ lengthArray[1] = (byte)(0xFF & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.NAME, null);
+ }
+ }
+
+ // Type Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.TYPE);
+ try {
+ value = stringHeader.getBytes("ISO8859_1");
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+
+ length = value.length + 4;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ out.write(0x00);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TYPE, null);
+ }
+ }
+
+ // Length Header
+ intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
+ if (intHeader != null) {
+ out.write((byte)HeaderSet.LENGTH);
+ value = ObexHelper.convertToByteArray(intHeader.longValue());
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.LENGTH, null);
+ }
+ }
+
+ // Time ISO Header
+ dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
+ if (dateHeader != null) {
+
+ /*
+ * The ISO Header should take the form YYYYMMDDTHHMMSSZ. The
+ * 'Z' will only be included if it is a UTC time.
+ */
+ buffer = new StringBuffer();
+ int temp = dateHeader.get(Calendar.YEAR);
+ for (int i = temp; i < 1000; i = i * 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.MONTH);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.DAY_OF_MONTH);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ buffer.append("T");
+ temp = dateHeader.get(Calendar.HOUR_OF_DAY);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.MINUTE);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.SECOND);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+
+ if (dateHeader.getTimeZone().getID().equals("UTC")) {
+ buffer.append("Z");
+ }
+
+ try {
+ value = buffer.toString().getBytes("ISO8859_1");
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(HeaderSet.TIME_ISO_8601);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
+ }
+ }
+
+ // Time 4 Byte Header
+ dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
+ if (dateHeader != null) {
+ out.write(HeaderSet.TIME_4_BYTE);
+
+ /*
+ * Need to call getTime() twice. The first call will return
+ * a java.util.Date object. The second call returns the number
+ * of milliseconds since January 1, 1970. We need to convert
+ * it to seconds since the TIME_4_BYTE expects the number of
+ * seconds since January 1, 1970.
+ */
+ value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
+ }
+ }
+
+ // Description Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.DESCRIPTION);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.DESCRIPTION, null);
+ }
+ }
+
+ // Target Header
+ value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
+ if (value != null) {
+ out.write((byte)HeaderSet.TARGET);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TARGET, null);
+ }
+ }
+
+ // HTTP Header
+ value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
+ if (value != null) {
+ out.write((byte)HeaderSet.HTTP);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.HTTP, null);
+ }
+ }
+
+ // Who Header
+ value = (byte[])headImpl.getHeader(HeaderSet.WHO);
+ if (value != null) {
+ out.write((byte)HeaderSet.WHO);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.WHO, null);
+ }
+ }
+
+ // Connection ID Header
+ value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ if (value != null) {
+ out.write((byte)HeaderSet.APPLICATION_PARAMETER);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
+ }
+ }
+
+ // Object Class Header
+ value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
+ if (value != null) {
+ out.write((byte)HeaderSet.OBJECT_CLASS);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
+ }
+ }
+
+ // Check User Defined Headers
+ for (int i = 0; i < 16; i++) {
+
+ //Unicode String Header
+ stringHeader = (String)headImpl.getHeader(i + 0x30);
+ if (stringHeader != null) {
+ out.write((byte)i + 0x30);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(i + 0x30, null);
+ }
+ }
+
+ // Byte Sequence Header
+ value = (byte[])headImpl.getHeader(i + 0x70);
+ if (value != null) {
+ out.write((byte)i + 0x70);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(i + 0x70, null);
+ }
+ }
+
+ // Byte Header
+ byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
+ if (byteHeader != null) {
+ out.write((byte)i + 0xB0);
+ out.write(byteHeader.byteValue());
+ if (nullOut) {
+ headImpl.setHeader(i + 0xB0, null);
+ }
+ }
+
+ // Integer header
+ intHeader = (Long)headImpl.getHeader(i + 0xF0);
+ if (intHeader != null) {
+ out.write((byte)i + 0xF0);
+ out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
+ if (nullOut) {
+ headImpl.setHeader(i + 0xF0, null);
+ }
+ }
+ }
+
+ // Add the authentication challenge header
+ if (headImpl.mAuthChall != null) {
+ out.write((byte)HeaderSet.AUTH_CHALLENGE);
+ length = headImpl.mAuthChall.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(headImpl.mAuthChall);
+ if (nullOut) {
+ headImpl.mAuthChall = null;
+ }
+ }
+
+ // Add the authentication response header
+ if (headImpl.mAuthResp != null) {
+ out.write((byte)HeaderSet.AUTH_RESPONSE);
+ length = headImpl.mAuthResp.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(headImpl.mAuthResp);
+ if (nullOut) {
+ headImpl.mAuthResp = null;
+ }
+ }
+
+ } catch (IOException e) {
+ } finally {
+ result = out.toByteArray();
+ try {
+ out.close();
+ } catch (Exception ex) {
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Determines where the maximum divide is between headers. This method is
+ * used by put and get operations to separate headers to a size that meets
+ * the max packet size allowed.
+ * @param headerArray the headers to separate
+ * @param start the starting index to search
+ * @param maxSize the maximum size of a packet
+ * @return the index of the end of the header block to send or -1 if the
+ * header could not be divided because the header is too large
+ */
+ public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
+
+ int fullLength = 0;
+ int lastLength = -1;
+ int index = start;
+ int length = 0;
+
+ while ((fullLength < maxSize) && (index < headerArray.length)) {
+ int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
+ lastLength = fullLength;
+
+ switch (headerID & (0xC0)) {
+
+ case 0x00:
+ // Fall through
+ case 0x40:
+
+ index++;
+ length = (headerArray[index] < 0 ? headerArray[index] + 256
+ : headerArray[index]);
+ length = length << 8;
+ index++;
+ length += (headerArray[index] < 0 ? headerArray[index] + 256
+ : headerArray[index]);
+ length -= 3;
+ index++;
+ index += length;
+ fullLength += length + 3;
+ break;
+
+ case 0x80:
+
+ index++;
+ index++;
+ fullLength += 2;
+ break;
+
+ case 0xC0:
+
+ index += 5;
+ fullLength += 5;
+ break;
+
+ }
+
+ }
+
+ /*
+ * Determine if this is the last header or not
+ */
+ if (lastLength == 0) {
+ /*
+ * Since this is the last header, check to see if the size of this
+ * header is less then maxSize. If it is, return the length of the
+ * header, otherwise return -1. The length of the header is
+ * returned since it would be the start of the next header
+ */
+ if (fullLength < maxSize) {
+ return headerArray.length;
+ } else {
+ return -1;
+ }
+ } else {
+ return lastLength + start;
+ }
+ }
+
+ /**
+ * Converts the byte array to a long.
+ * @param b the byte array to convert to a long
+ * @return the byte array as a long
+ */
+ public static long convertToLong(byte[] b) {
+ long result = 0;
+ long value = 0;
+ long power = 0;
+
+ for (int i = (b.length - 1); i >= 0; i--) {
+ value = b[i];
+ if (value < 0) {
+ value += 256;
+ }
+
+ result = result | (value << power);
+ power += 8;
+ }
+
+ return result;
+ }
+
+ /**
+ * Converts the long to a 4 byte array. The long must be non negative.
+ * @param l the long to convert
+ * @return a byte array that is the same as the long
+ */
+ public static byte[] convertToByteArray(long l) {
+ byte[] b = new byte[4];
+
+ b[0] = (byte)(255 & (l >> 24));
+ b[1] = (byte)(255 & (l >> 16));
+ b[2] = (byte)(255 & (l >> 8));
+ b[3] = (byte)(255 & l);
+
+ return b;
+ }
+
+ /**
+ * Converts the String to a UNICODE byte array. It will also add the ending
+ * null characters to the end of the string.
+ * @param s the string to convert
+ * @return the unicode byte array of the string
+ */
+ public static byte[] convertToUnicodeByteArray(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ char c[] = s.toCharArray();
+ byte[] result = new byte[(c.length * 2) + 2];
+ for (int i = 0; i < c.length; i++) {
+ result[(i * 2)] = (byte)(c[i] >> 8);
+ result[((i * 2) + 1)] = (byte)c[i];
+ }
+
+ // Add the UNICODE null character
+ result[result.length - 2] = 0;
+ result[result.length - 1] = 0;
+
+ return result;
+ }
+
+ /**
+ * Retrieves the value from the byte array for the tag value specified. The
+ * array should be of the form Tag - Length - Value triplet.
+ * @param tag the tag to retrieve from the byte array
+ * @param triplet the byte sequence containing the tag length value form
+ * @return the value of the specified tag
+ */
+ public static byte[] getTagValue(byte tag, byte[] triplet) {
+
+ int index = findTag(tag, triplet);
+ if (index == -1) {
+ return null;
+ }
+
+ index++;
+ int length = triplet[index] & 0xFF;
+
+ byte[] result = new byte[length];
+ index++;
+ System.arraycopy(triplet, index, result, 0, length);
+
+ return result;
+ }
+
+ /**
+ * Finds the index that starts the tag value pair in the byte array provide.
+ * @param tag the tag to look for
+ * @param value the byte array to search
+ * @return the starting index of the tag or -1 if the tag could not be found
+ */
+ public static int findTag(byte tag, byte[] value) {
+ int length = 0;
+
+ if (value == null) {
+ return -1;
+ }
+
+ int index = 0;
+
+ while ((index < value.length) && (value[index] != tag)) {
+ length = value[index + 1] & 0xFF;
+ index += length + 2;
+ }
+
+ if (index >= value.length) {
+ return -1;
+ }
+
+ return index;
+ }
+
+ /**
+ * Converts the byte array provided to a unicode string.
+ * @param b the byte array to convert to a string
+ * @param includesNull determine if the byte string provided contains the
+ * UNICODE null character at the end or not; if it does, it will be
+ * removed
+ * @return a Unicode string
+ * @throws IllegalArgumentException if the byte array has an odd length
+ */
+ public static String convertToUnicode(byte[] b, boolean includesNull) {
+ if (b == null || b.length == 0) {
+ return null;
+ }
+ int arrayLength = b.length;
+ if (!((arrayLength % 2) == 0)) {
+ throw new IllegalArgumentException("Byte array not of a valid form");
+ }
+ arrayLength = (arrayLength >> 1);
+ if (includesNull) {
+ arrayLength -= 1;
+ }
+
+ char[] c = new char[arrayLength];
+ for (int i = 0; i < arrayLength; i++) {
+ int upper = b[2 * i];
+ int lower = b[(2 * i) + 1];
+ if (upper < 0) {
+ upper += 256;
+ }
+ if (lower < 0) {
+ lower += 256;
+ }
+
+ c[i] = (char)((upper << 8) | lower);
+ }
+
+ return new String(c);
+ }
+
+ /**
+ * Compute the MD5 hash of the byte array provided. Does not accumulate
+ * input.
+ * @param in the byte array to hash
+ * @return the MD5 hash of the byte array
+ */
+ public static byte[] computeMd5Hash(byte[] in) {
+ Md5MessageDigest md5 = new Md5MessageDigest();
+ return md5.digest(in);
+ }
+
+ /**
+ * Computes an authentication challenge header.
+ * @param nonce the challenge that will be provided to the peer; the
+ * challenge must be 16 bytes long
+ * @param realm a short description that describes what password to use
+ * @param access if <code>true</code> then full access will be granted if
+ * successful; if <code>false</code> then read only access will be
+ * granted if successful
+ * @param userID if <code>true</code>, a user ID is required in the reply;
+ * if <code>false</code>, no user ID is required
+ * @throws IllegalArgumentException if the challenge is not 16 bytes long;
+ * if the realm can not be encoded in less then 255 bytes
+ * @throws IOException if the encoding scheme ISO 8859-1 is not supported
+ */
+ public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
+ boolean userID) throws IOException {
+ byte[] authChall = null;
+
+ if (nonce.length != 16) {
+ throw new IllegalArgumentException("Nonce must be 16 bytes long");
+ }
+
+ /*
+ * The authentication challenge is a byte sequence of the following form
+ * byte 0: 0x00 - the tag for the challenge
+ * byte 1: 0x10 - the length of the challenge; must be 16
+ * byte 2-17: the authentication challenge
+ * byte 18: 0x01 - the options tag; this is optional in the spec, but
+ * we are going to include it in every message
+ * byte 19: 0x01 - length of the options; must be 1
+ * byte 20: the value of the options; bit 0 is set if user ID is
+ * required; bit 1 is set if access mode is read only
+ * byte 21: 0x02 - the tag for authentication realm; only included if
+ * an authentication realm is specified
+ * byte 22: the length of the authentication realm; only included if
+ * the authentication realm is specified
+ * byte 23: the encoding scheme of the authentication realm; we will use
+ * the ISO 8859-1 encoding scheme since it is part of the KVM
+ * byte 24 & up: the realm if one is specified.
+ */
+ if (realm == null) {
+ authChall = new byte[21];
+ } else {
+ if (realm.length() >= 255) {
+ throw new IllegalArgumentException("Realm must be less then 255 bytes");
+ }
+ authChall = new byte[24 + realm.length()];
+ authChall[21] = 0x02;
+ authChall[22] = (byte)(realm.length() + 1);
+ authChall[23] = 0x01; // ISO 8859-1 Encoding
+ System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
+ }
+
+ // Include the nonce field in the header
+ authChall[0] = 0x00;
+ authChall[1] = 0x10;
+ System.arraycopy(nonce, 0, authChall, 2, 16);
+
+ // Include the options header
+ authChall[18] = 0x01;
+ authChall[19] = 0x01;
+ authChall[20] = 0x00;
+
+ if (!access) {
+ authChall[20] = (byte)(authChall[20] | 0x02);
+ }
+ if (userID) {
+ authChall[20] = (byte)(authChall[20] | 0x01);
+ }
+
+ return authChall;
+ }
+}
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
new file mode 100644
index 0000000..a7daeb5
--- /dev/null
+++ b/obex/javax/obex/ObexSession.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * The <code>ObexSession</code> interface characterizes the term
+ * "OBEX Connection" as defined in the IrDA Object Exchange Protocol v1.2, which
+ * could be the server-side view of an OBEX connection, or the client-side view
+ * of the same connection, which is established by server's accepting of a
+ * client issued "CONNECT".
+ * <P>
+ * This interface serves as the common super class for
+ * <CODE>ClientSession</CODE> and <CODE>ServerSession</CODE>.
+ * @hide
+ */
+public class ObexSession {
+
+ protected Authenticator mAuthenticator;
+
+ protected byte[] mChallengeDigest;
+
+ /**
+ * Called when the server received an authentication challenge header. This
+ * will cause the authenticator to handle the authentication challenge.
+ * @param header the header with the authentication challenge
+ * @return <code>true</code> if the last request should be resent;
+ * <code>false</code> if the last request should not be resent
+ * @throws IOException
+ */
+ public boolean handleAuthChall(HeaderSet header) throws IOException {
+ if (mAuthenticator == null) {
+ return false;
+ }
+
+ /*
+ * An authentication challenge is made up of one required and two
+ * optional tag length value triplets. The tag 0x00 is required to be in
+ * the authentication challenge and it represents the challenge digest
+ * that was received. The tag 0x01 is the options tag. This tag tracks
+ * if user ID is required and if full access will be granted. The tag
+ * 0x02 is the realm, which provides a description of which user name
+ * and password to use.
+ */
+ byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
+ byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
+ byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
+
+ String realm = null;
+ if (description != null) {
+ byte[] realmString = new byte[description.length - 1];
+ System.arraycopy(description, 1, realmString, 0, realmString.length);
+
+ switch (description[0] & 0xFF) {
+
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
+ // ASCII encoding
+ // Fall through
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
+ // ISO-8859-1 encoding
+ try {
+ realm = new String(realmString, "ISO8859_1");
+ } catch (Exception e) {
+ throw new IOException("Unsupported Encoding Scheme");
+ }
+ break;
+
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
+ // UNICODE Encoding
+ realm = ObexHelper.convertToUnicode(realmString, false);
+ break;
+
+ default:
+ throw new IOException("Unsupported Encoding Scheme");
+ }
+ }
+
+ boolean isUserIDRequired = false;
+ boolean isFullAccess = true;
+ if (option != null) {
+ if ((option[0] & 0x01) != 0) {
+ isUserIDRequired = true;
+ }
+
+ if ((option[0] & 0x02) != 0) {
+ isFullAccess = false;
+ }
+ }
+
+ PasswordAuthentication result = null;
+ header.mAuthChall = null;
+
+ try {
+ result = mAuthenticator
+ .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
+ } catch (Exception e) {
+ return false;
+ }
+
+ /*
+ * If no password is provided then we not resent the request
+ */
+ if (result == null) {
+ return false;
+ }
+
+ byte[] password = result.getPassword();
+ if (password == null) {
+ return false;
+ }
+
+ byte[] userName = result.getUserName();
+
+ /*
+ * Create the authentication response header. It includes 1 required and
+ * 2 option tag length value triples. The required triple has a tag of
+ * 0x00 and is the response digest. The first optional tag is 0x01 and
+ * represents the user ID. If no user ID is provided, then no user ID
+ * will be sent. The second optional tag is 0x02 and is the challenge
+ * that was received. This will always be sent
+ */
+ if (userName != null) {
+ header.mAuthResp = new byte[38 + userName.length];
+ header.mAuthResp[36] = (byte)0x01;
+ header.mAuthResp[37] = (byte)userName.length;
+ System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
+ } else {
+ header.mAuthResp = new byte[36];
+ }
+
+ // Create the secret String
+ byte[] digest = new byte[challenge.length + password.length + 1];
+ System.arraycopy(challenge, 0, digest, 0, challenge.length);
+ // Insert colon between challenge and password
+ digest[challenge.length] = (byte)0x3A;
+ System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
+
+ // Add the Response Digest
+ header.mAuthResp[0] = (byte)0x00;
+ header.mAuthResp[1] = (byte)0x10;
+
+ System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
+
+ // Add the challenge
+ header.mAuthResp[18] = (byte)0x02;
+ header.mAuthResp[19] = (byte)0x10;
+ System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
+
+ return true;
+ }
+
+ /**
+ * Called when the server received an authentication response header. This
+ * will cause the authenticator to handle the authentication response.
+ * @param authResp the authentication response
+ * @return <code>true</code> if the response passed; <code>false</code> if
+ * the response failed
+ */
+ public boolean handleAuthResp(byte[] authResp) {
+ if (mAuthenticator == null) {
+ return false;
+ }
+ // get the correct password from the application
+ byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
+ (byte)0x01, authResp));
+ if (correctPassword == null) {
+ return false;
+ }
+
+ byte[] temp = new byte[correctPassword.length + 16];
+
+ System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
+ System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
+
+ byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
+ byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
+
+ // compare the MD5 hash array .
+ for (int i = 0; i < 16; i++) {
+ if (correctResponse[i] != actualResponse[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java
new file mode 100644
index 0000000..445e267
--- /dev/null
+++ b/obex/javax/obex/ObexTransport.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>ObexTransport</code> interface defines the underlying transport
+ * connection which carries the OBEX protocol( such as TCP, RFCOMM device file
+ * exposed by Bluetooth or USB in kernel, RFCOMM socket emulated in Android
+ * platform, Irda). This interface provides an abstract layer to be used by the
+ * <code>ObexConnection</code>. Each kind of medium shall have its own
+ * implementation to wrap and follow the same interface.
+ * <P>
+ * See section 1.2.2 of IrDA Object Exchange Protocol specification.
+ * <P>
+ * Different kind of medium may have different construction - for example, the
+ * RFCOMM device file medium may be constructed from a file descriptor or simply
+ * a string while the TCP medium usually from a socket.
+ * @hide
+ */
+public interface ObexTransport {
+
+ void create() throws IOException;
+
+ void listen() throws IOException;
+
+ void close() throws IOException;
+
+ void connect() throws IOException;
+
+ void disconnect() throws IOException;
+
+ InputStream openInputStream() throws IOException;
+
+ OutputStream openOutputStream() throws IOException;
+
+ DataInputStream openDataInputStream() throws IOException;
+
+ DataOutputStream openDataOutputStream() throws IOException;
+
+}
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
new file mode 100644
index 0000000..20653f2
--- /dev/null
+++ b/obex/javax/obex/Operation.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>Operation</code> interface provides ways to manipulate a single
+ * OBEX PUT or GET operation. The implementation of this interface sends OBEX
+ * packets as they are built. If during the operation the peer in the operation
+ * ends the operation, an <code>IOException</code> is thrown on the next read
+ * from the input stream, write to the output stream, or call to
+ * <code>sendHeaders()</code>.
+ * <P>
+ * <STRONG>Definition of methods inherited from <code>ContentConnection</code>
+ * </STRONG>
+ * <P>
+ * <code>getEncoding()</code> will always return <code>null</code>. <BR>
+ * <code>getLength()</code> will return the length specified by the OBEX Length
+ * header or -1 if the OBEX Length header was not included. <BR>
+ * <code>getType()</code> will return the value specified in the OBEX Type
+ * header or <code>null</code> if the OBEX Type header was not included.<BR>
+ * <P>
+ * <STRONG>How Headers are Handled</STRONG>
+ * <P>
+ * As headers are received, they may be retrieved through the
+ * <code>getReceivedHeaders()</code> method. If new headers are set during the
+ * operation, the new headers will be sent during the next packet exchange.
+ * <P>
+ * <STRONG>PUT example</STRONG>
+ * <P>
+ * <PRE>
+ * void putObjectViaOBEX(ClientSession conn, HeaderSet head, byte[] obj) throws IOException {
+ * // Include the length header
+ * head.setHeader(head.LENGTH, new Long(obj.length));
+ * // Initiate the PUT request
+ * Operation op = conn.put(head);
+ * // Open the output stream to put the object to it
+ * DataOutputStream out = op.openDataOutputStream();
+ * // Send the object to the server
+ * out.write(obj);
+ * // End the transaction
+ * out.close();
+ * op.close();
+ * }
+ * </PRE>
+ * <P>
+ * <STRONG>GET example</STRONG>
+ * <P>
+ * <PRE>
+ * byte[] getObjectViaOBEX(ClientSession conn, HeaderSet head) throws IOException {
+ * // Send the initial GET request to the server
+ * Operation op = conn.get(head);
+ * // Retrieve the length of the object being sent back
+ * int length = op.getLength();
+ * // Create space for the object
+ * byte[] obj = new byte[length];
+ * // Get the object from the input stream
+ * DataInputStream in = trans.openDataInputStream();
+ * in.read(obj);
+ * // End the transaction
+ * in.close();
+ * op.close();
+ * return obj;
+ * }
+ * </PRE>
+ *
+ * <H3>Client PUT Operation Flow</H3> For PUT operations, a call to
+ * <code>close()</code> the <code>OutputStream</code> returned from
+ * <code>openOutputStream()</code> or <code>openDataOutputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the End-Of-Body header
+ * should be sent and the final bit in the request will be set.) At this point,
+ * the reply from the server may begin to be processed. A call to
+ * <code>getResponseCode()</code> will do an implicit close on the
+ * <code>OutputStream</code> and therefore signal that the request is done.
+ * <H3>Client GET Operation Flow</H3> For GET operation, a call to
+ * <code>openInputStream()</code> or <code>openDataInputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the final bit in the request
+ * will be set.) A call to <code>getResponseCode()</code> will cause an implicit
+ * close on the <code>InputStream</code>. No further data may be read at this
+ * point.
+ * @hide
+ */
+public interface Operation {
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object. No headers are sent in the abort request. This will end the
+ * operation since <code>close()</code> will be called by this method.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server calls this method
+ */
+ void abort() throws IOException;
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ HeaderSet getReceivedHeader() throws IOException;
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ * or <code>ClientSession.createHeaderSet()</code>
+ * @throws NullPointerException if <code>headers</code> if <code>null</code>
+ */
+ void sendHeaders(HeaderSet headers) throws IOException;
+
+ /**
+ * Returns the response code received from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> class.
+ * @see ResponseCodes
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this object was created by an OBEX server
+ */
+ int getResponseCode() throws IOException;
+
+ String getEncoding();
+
+ long getLength();
+
+ String getType();
+
+ InputStream openInputStream() throws IOException;
+
+ DataInputStream openDataInputStream() throws IOException;
+
+ OutputStream openOutputStream() throws IOException;
+
+ DataOutputStream openDataOutputStream() throws IOException;
+
+ void close() throws IOException;
+
+ int getMaxPacketSize();
+}
diff --git a/obex/javax/obex/PasswordAuthentication.java b/obex/javax/obex/PasswordAuthentication.java
new file mode 100644
index 0000000..326b1ff
--- /dev/null
+++ b/obex/javax/obex/PasswordAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+/**
+ * This class holds user name and password combinations.
+ * @hide
+ */
+public final class PasswordAuthentication {
+
+ private byte[] mUserName;
+
+ private final byte[] mPassword;
+
+ /**
+ * Creates a new <code>PasswordAuthentication</code> with the user name and
+ * password provided.
+ * @param userName the user name to include; this may be <code>null</code>
+ * @param password the password to include in the response
+ * @throws NullPointerException if <code>password</code> is
+ * <code>null</code>
+ */
+ public PasswordAuthentication(final byte[] userName, final byte[] password) {
+ if (userName != null) {
+ mUserName = new byte[userName.length];
+ System.arraycopy(userName, 0, mUserName, 0, userName.length);
+ }
+
+ mPassword = new byte[password.length];
+ System.arraycopy(password, 0, mPassword, 0, password.length);
+ }
+
+ /**
+ * Retrieves the user name that was specified in the constructor. The user
+ * name may be <code>null</code>.
+ * @return the user name
+ */
+ public byte[] getUserName() {
+ return mUserName;
+ }
+
+ /**
+ * Retrieves the password.
+ * @return the password
+ */
+ public byte[] getPassword() {
+ return mPassword;
+ }
+}
diff --git a/obex/javax/obex/PrivateInputStream.java b/obex/javax/obex/PrivateInputStream.java
new file mode 100644
index 0000000..5daee72
--- /dev/null
+++ b/obex/javax/obex/PrivateInputStream.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This object provides an input stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateInputStream extends InputStream {
+
+ private BaseStream mParent;
+
+ private byte[] mData;
+
+ private int mIndex;
+
+ private boolean mOpen;
+
+ /**
+ * Creates an input stream for the <code>Operation</code> to read from
+ * @param p the connection this input stream is for
+ */
+ public PrivateInputStream(BaseStream p) {
+ mParent = p;
+ mData = new byte[0];
+ mIndex = 0;
+ mOpen = true;
+ }
+
+ /**
+ * Returns the number of bytes that can be read (or skipped over) from this
+ * input stream without blocking by the next caller of a method for this
+ * input stream. The next caller might be the same thread or or another
+ * thread.
+ * @return the number of bytes that can be read from this input stream
+ * without blocking
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized int available() throws IOException {
+ ensureOpen();
+ return mData.length - mIndex;
+ }
+
+ /**
+ * Reads the next byte of data from the input stream. The value byte is
+ * returned as an int in the range 0 to 255. If no byte is available because
+ * the end of the stream has been reached, the value -1 is returned. This
+ * method blocks until input data is available, the end of the stream is
+ * detected, or an exception is thrown.
+ * @return the byte read from the input stream or -1 if it reaches the end of
+ * stream
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized int read() throws IOException {
+ ensureOpen();
+ while (mData.length == mIndex) {
+ if (!mParent.continueOperation(true, true)) {
+ return -1;
+ }
+ }
+ return (mData[mIndex++] & 0xFF);
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public synchronized int read(byte[] b, int offset, int length) throws IOException {
+
+ if (b == null) {
+ throw new IOException("buffer is null");
+ }
+ if ((offset | length) < 0 || length > b.length - offset) {
+ throw new ArrayIndexOutOfBoundsException("index outof bound");
+ }
+ ensureOpen();
+
+ int currentDataLength = mData.length - mIndex;
+ int remainReadLength = length;
+ int offset1 = offset;
+ int result = 0;
+
+ while (currentDataLength <= remainReadLength) {
+ System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
+ mIndex += currentDataLength;
+ offset1 += currentDataLength;
+ result += currentDataLength;
+ remainReadLength -= currentDataLength;
+
+ if (!mParent.continueOperation(true, true)) {
+ return result == 0 ? -1 : result;
+ }
+ currentDataLength = mData.length - mIndex;
+ }
+ if (remainReadLength > 0) {
+ System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
+ mIndex += remainReadLength;
+ result += remainReadLength;
+ }
+ return result;
+ }
+
+ /**
+ * Allows the <code>OperationImpl</code> thread to add body data to the
+ * input stream.
+ * @param body the data to add to the stream
+ * @param start the start of the body to array to copy
+ */
+ public synchronized void writeBytes(byte[] body, int start) {
+
+ int length = (body.length - start) + (mData.length - mIndex);
+ byte[] temp = new byte[length];
+
+ System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
+ System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
+
+ mData = temp;
+ mIndex = 0;
+ notifyAll();
+ }
+
+ /**
+ * Verifies that this stream is open
+ * @throws IOException if the stream is not open
+ */
+ private void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+ if (!mOpen) {
+ throw new IOException("Input stream is closed");
+ }
+ }
+
+ /**
+ * Closes the input stream. If the input stream is already closed, do
+ * nothing.
+ * @throws IOException this will never happen
+ */
+ @Override
+ public void close() throws IOException {
+ mOpen = false;
+ mParent.streamClosed(true);
+ }
+}
diff --git a/obex/javax/obex/PrivateOutputStream.java b/obex/javax/obex/PrivateOutputStream.java
new file mode 100644
index 0000000..ca420af
--- /dev/null
+++ b/obex/javax/obex/PrivateOutputStream.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This object provides an output stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateOutputStream extends OutputStream {
+
+ private BaseStream mParent;
+
+ private ByteArrayOutputStream mArray;
+
+ private boolean mOpen;
+
+ private int mMaxPacketSize;
+
+ /**
+ * Creates an empty <code>PrivateOutputStream</code> to write to.
+ * @param p the connection that this stream runs over
+ */
+ public PrivateOutputStream(BaseStream p, int maxSize) {
+ mParent = p;
+ mArray = new ByteArrayOutputStream();
+ mMaxPacketSize = maxSize;
+ mOpen = true;
+ }
+
+ /**
+ * Determines how many bytes have been written to the output stream.
+ * @return the number of bytes written to the output stream
+ */
+ public int size() {
+ return mArray.size();
+ }
+
+ /**
+ * Writes the specified byte to this output stream. The general contract for
+ * write is that one byte is written to the output stream. The byte to be
+ * written is the eight low-order bits of the argument b. The 24 high-order
+ * bits of b are ignored.
+ * @param b the byte to write
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized void write(int b) throws IOException {
+ ensureOpen();
+ mParent.ensureNotDone();
+ mArray.write(b);
+ if (mArray.size() == mMaxPacketSize) {
+ mParent.continueOperation(true, false);
+ }
+ }
+
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ write(buffer, 0, buffer.length);
+ }
+
+ @Override
+ public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
+ int offset1 = offset;
+ int remainLength = count;
+
+ if (buffer == null) {
+ throw new IOException("buffer is null");
+ }
+ if ((offset | count) < 0 || count > buffer.length - offset) {
+ throw new IndexOutOfBoundsException("index outof bound");
+ }
+
+ ensureOpen();
+ mParent.ensureNotDone();
+ if (count < mMaxPacketSize) {
+ mArray.write(buffer, offset, count);
+ } else {
+ while (remainLength >= mMaxPacketSize) {
+ mArray.write(buffer, offset1, mMaxPacketSize);
+ offset1 += mMaxPacketSize;
+ remainLength = count - offset1;
+ mParent.continueOperation(true, false);
+ }
+ if (remainLength > 0) {
+ mArray.write(buffer, offset1, remainLength);
+ }
+ }
+ }
+
+ /**
+ * Reads the bytes that have been written to this stream.
+ * @param size the size of the array to return
+ * @return the byte array that is written
+ */
+ public synchronized byte[] readBytes(int size) {
+ if (mArray.size() > 0) {
+ byte[] temp = mArray.toByteArray();
+ mArray.reset();
+ byte[] result = new byte[size];
+ System.arraycopy(temp, 0, result, 0, size);
+ if (temp.length != size) {
+ mArray.write(temp, size, temp.length - size);
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies that this stream is open
+ * @throws IOException if the stream is not open
+ */
+ private void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+ if (!mOpen) {
+ throw new IOException("Output stream is closed");
+ }
+ }
+
+ /**
+ * Closes the output stream. If the input stream is already closed, do
+ * nothing.
+ * @throws IOException this will never happen
+ */
+ @Override
+ public void close() throws IOException {
+ mOpen = false;
+ mParent.streamClosed(false);
+ }
+
+ /**
+ * Determines if the connection is closed
+ * @return <code>true</code> if the connection is closed; <code>false</code>
+ * if the connection is open
+ */
+ public boolean isClosed() {
+ return !mOpen;
+ }
+}
diff --git a/obex/javax/obex/ResponseCodes.java b/obex/javax/obex/ResponseCodes.java
new file mode 100644
index 0000000..a2b9a37
--- /dev/null
+++ b/obex/javax/obex/ResponseCodes.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+/**
+ * The <code>ResponseCodes</code> class contains the list of valid response
+ * codes a server may send to a client.
+ * <P>
+ * <STRONG>IMPORTANT NOTE</STRONG>
+ * <P>
+ * The values in this interface represent the values defined in the IrOBEX
+ * specification, which is different with the HTTP specification.
+ * <P>
+ * <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
+ * further description since they are not defined in HTTP. The server will send
+ * an <code>OBEX_DATABASE_FULL</code> message when the client requests that
+ * something be placed into a database but the database is full (cannot take
+ * more data). <code>OBEX_DATABASE_LOCKED</code> will be returned when the
+ * client wishes to access a database, database table, or database record that
+ * has been locked.
+ * @hide
+ */
+public final class ResponseCodes {
+
+ /**
+ * Defines the OBEX CONTINUE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
+ */
+ public static final int OBEX_HTTP_CONTINUE = 0x90;
+
+ /**
+ * Defines the OBEX SUCCESS response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_OK</code> is 0xA0 (160).
+ */
+ public static final int OBEX_HTTP_OK = 0xA0;
+
+ /**
+ * Defines the OBEX CREATED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CREATED</code> is 0xA1 (161).
+ */
+ public static final int OBEX_HTTP_CREATED = 0xA1;
+
+ /**
+ * Defines the OBEX ACCEPTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_ACCEPTED</code> is 0xA2 (162).
+ */
+ public static final int OBEX_HTTP_ACCEPTED = 0xA2;
+
+ /**
+ * Defines the OBEX NON-AUTHORITATIVE INFORMATION response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_AUTHORITATIVE</code> is 0xA3 (163).
+ */
+ public static final int OBEX_HTTP_NOT_AUTHORITATIVE = 0xA3;
+
+ /**
+ * Defines the OBEX NO CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NO_CONTENT</code> is 0xA4 (164).
+ */
+ public static final int OBEX_HTTP_NO_CONTENT = 0xA4;
+
+ /**
+ * Defines the OBEX RESET CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_RESET</code> is 0xA5 (165).
+ */
+ public static final int OBEX_HTTP_RESET = 0xA5;
+
+ /**
+ * Defines the OBEX PARTIAL CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PARTIAL</code> is 0xA6 (166).
+ */
+ public static final int OBEX_HTTP_PARTIAL = 0xA6;
+
+ /**
+ * Defines the OBEX MULTIPLE_CHOICES response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MULT_CHOICE</code> is 0xB0 (176).
+ */
+ public static final int OBEX_HTTP_MULT_CHOICE = 0xB0;
+
+ /**
+ * Defines the OBEX MOVED PERMANENTLY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MOVED_PERM</code> is 0xB1 (177).
+ */
+ public static final int OBEX_HTTP_MOVED_PERM = 0xB1;
+
+ /**
+ * Defines the OBEX MOVED TEMPORARILY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MOVED_TEMP</code> is 0xB2 (178).
+ */
+ public static final int OBEX_HTTP_MOVED_TEMP = 0xB2;
+
+ /**
+ * Defines the OBEX SEE OTHER response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_SEE_OTHER</code> is 0xB3 (179).
+ */
+ public static final int OBEX_HTTP_SEE_OTHER = 0xB3;
+
+ /**
+ * Defines the OBEX NOT MODIFIED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_MODIFIED</code> is 0xB4 (180).
+ */
+ public static final int OBEX_HTTP_NOT_MODIFIED = 0xB4;
+
+ /**
+ * Defines the OBEX USE PROXY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_USE_PROXY</code> is 0xB5 (181).
+ */
+ public static final int OBEX_HTTP_USE_PROXY = 0xB5;
+
+ /**
+ * Defines the OBEX BAD REQUEST response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_REQUEST</code> is 0xC0 (192).
+ */
+ public static final int OBEX_HTTP_BAD_REQUEST = 0xC0;
+
+ /**
+ * Defines the OBEX UNAUTHORIZED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNAUTHORIZED</code> is 0xC1 (193).
+ */
+ public static final int OBEX_HTTP_UNAUTHORIZED = 0xC1;
+
+ /**
+ * Defines the OBEX PAYMENT REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PAYMENT_REQUIRED</code> is 0xC2 (194).
+ */
+ public static final int OBEX_HTTP_PAYMENT_REQUIRED = 0xC2;
+
+ /**
+ * Defines the OBEX FORBIDDEN response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_FORBIDDEN</code> is 0xC3 (195).
+ */
+ public static final int OBEX_HTTP_FORBIDDEN = 0xC3;
+
+ /**
+ * Defines the OBEX NOT FOUND response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_FOUND</code> is 0xC4 (196).
+ */
+ public static final int OBEX_HTTP_NOT_FOUND = 0xC4;
+
+ /**
+ * Defines the OBEX METHOD NOT ALLOWED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_METHOD</code> is 0xC5 (197).
+ */
+ public static final int OBEX_HTTP_BAD_METHOD = 0xC5;
+
+ /**
+ * Defines the OBEX NOT ACCEPTABLE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_ACCEPTABLE</code> is 0xC6 (198).
+ */
+ public static final int OBEX_HTTP_NOT_ACCEPTABLE = 0xC6;
+
+ /**
+ * Defines the OBEX PROXY AUTHENTICATION REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PROXY_AUTH</code> is 0xC7 (199).
+ */
+ public static final int OBEX_HTTP_PROXY_AUTH = 0xC7;
+
+ /**
+ * Defines the OBEX REQUEST TIME OUT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_TIMEOUT</code> is 0xC8 (200).
+ */
+ public static final int OBEX_HTTP_TIMEOUT = 0xC8;
+
+ /**
+ * Defines the OBEX METHOD CONFLICT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CONFLICT</code> is 0xC9 (201).
+ */
+ public static final int OBEX_HTTP_CONFLICT = 0xC9;
+
+ /**
+ * Defines the OBEX METHOD GONE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_GONE</code> is 0xCA (202).
+ */
+ public static final int OBEX_HTTP_GONE = 0xCA;
+
+ /**
+ * Defines the OBEX METHOD LENGTH REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_LENGTH_REQUIRED</code> is 0xCB (203).
+ */
+ public static final int OBEX_HTTP_LENGTH_REQUIRED = 0xCB;
+
+ /**
+ * Defines the OBEX PRECONDITION FAILED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PRECON_FAILED</code> is 0xCC (204).
+ */
+ public static final int OBEX_HTTP_PRECON_FAILED = 0xCC;
+
+ /**
+ * Defines the OBEX REQUESTED ENTITY TOO LARGE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_ENTITY_TOO_LARGE</code> is 0xCD (205).
+ */
+ public static final int OBEX_HTTP_ENTITY_TOO_LARGE = 0xCD;
+
+ /**
+ * Defines the OBEX REQUESTED URL TOO LARGE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_REQ_TOO_LARGE</code> is 0xCE (206).
+ */
+ public static final int OBEX_HTTP_REQ_TOO_LARGE = 0xCE;
+
+ /**
+ * Defines the OBEX UNSUPPORTED MEDIA TYPE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNSUPPORTED_TYPE</code> is 0xCF (207).
+ */
+ public static final int OBEX_HTTP_UNSUPPORTED_TYPE = 0xCF;
+
+ /**
+ * Defines the OBEX INTERNAL SERVER ERROR response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_INTERNAL_ERROR</code> is 0xD0 (208).
+ */
+ public static final int OBEX_HTTP_INTERNAL_ERROR = 0xD0;
+
+ /**
+ * Defines the OBEX NOT IMPLEMENTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_IMPLEMENTED</code> is 0xD1 (209).
+ */
+ public static final int OBEX_HTTP_NOT_IMPLEMENTED = 0xD1;
+
+ /**
+ * Defines the OBEX BAD GATEWAY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_GATEWAY</code> is 0xD2 (210).
+ */
+ public static final int OBEX_HTTP_BAD_GATEWAY = 0xD2;
+
+ /**
+ * Defines the OBEX SERVICE UNAVAILABLE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNAVAILABLE</code> is 0xD3 (211).
+ */
+ public static final int OBEX_HTTP_UNAVAILABLE = 0xD3;
+
+ /**
+ * Defines the OBEX GATEWAY TIMEOUT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_GATEWAY_TIMEOUT</code> is 0xD4 (212).
+ */
+ public static final int OBEX_HTTP_GATEWAY_TIMEOUT = 0xD4;
+
+ /**
+ * Defines the OBEX HTTP VERSION NOT SUPPORTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_VERSION</code> is 0xD5 (213).
+ */
+ public static final int OBEX_HTTP_VERSION = 0xD5;
+
+ /**
+ * Defines the OBEX DATABASE FULL response code.
+ * <P>
+ * The value of <code>OBEX_DATABASE_FULL</code> is 0xE0 (224).
+ */
+ public static final int OBEX_DATABASE_FULL = 0xE0;
+
+ /**
+ * Defines the OBEX DATABASE LOCKED response code.
+ * <P>
+ * The value of <code>OBEX_DATABASE_LOCKED</code> is 0xE1 (225).
+ */
+ public static final int OBEX_DATABASE_LOCKED = 0xE1;
+
+ /**
+ * Constructor does nothing.
+ */
+ private ResponseCodes() {
+ }
+}
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
new file mode 100644
index 0000000..8710c64
--- /dev/null
+++ b/obex/javax/obex/ServerOperation.java
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.OutputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class implements the Operation interface for server side connections.
+ * <P>
+ * <STRONG>Request Codes</STRONG> There are four different request codes that
+ * are in this class. 0x02 is a PUT request that signals that the request is not
+ * complete and requires an additional OBEX packet. 0x82 is a PUT request that
+ * says that request is complete. In this case, the server can begin sending the
+ * response. The 0x03 is a GET request that signals that the request is not
+ * finished. When the server receives a 0x83, the client is signaling the server
+ * that it is done with its request. TODO: Extend the ClientOperation and reuse
+ * the methods defined TODO: in that class.
+ * @hide
+ */
+public final class ServerOperation implements Operation, BaseStream {
+
+ public boolean isAborted;
+
+ public HeaderSet requestHeader;
+
+ public HeaderSet replyHeader;
+
+ public boolean finalBitSet;
+
+ private InputStream mInput;
+
+ private ServerSession mParent;
+
+ private int mMaxPacketLength;
+
+ private int mResponseSize;
+
+ private boolean mClosed;
+
+ private boolean mGetOperation;
+
+ private PrivateInputStream mPrivateInput;
+
+ private PrivateOutputStream mPrivateOutput;
+
+ private boolean mPrivateOutputOpen;
+
+ private String mExceptionString;
+
+ private ServerRequestHandler mListener;
+
+ private boolean mRequestFinished;
+
+ private boolean mHasBody;
+
+ /**
+ * Creates new ServerOperation
+ * @param p the parent that created this object
+ * @param in the input stream to read from
+ * @param out the output stream to write to
+ * @param request the initial request that was received from the client
+ * @param maxSize the max packet size that the client will accept
+ * @param listen the listener that is responding to the request
+ * @throws IOException if an IO error occurs
+ */
+ public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
+ ServerRequestHandler listen) throws IOException {
+
+ isAborted = false;
+ mParent = p;
+ mInput = in;
+ mMaxPacketLength = maxSize;
+ mClosed = false;
+ requestHeader = new HeaderSet();
+ replyHeader = new HeaderSet();
+ mPrivateInput = new PrivateInputStream(this);
+ mResponseSize = 3;
+ mListener = listen;
+ mRequestFinished = false;
+ mPrivateOutputOpen = false;
+ mHasBody = false;
+ int bytesReceived;
+
+ /*
+ * Determine if this is a PUT request
+ */
+ if ((request == 0x02) || (request == 0x82)) {
+ /*
+ * It is a PUT request.
+ */
+ mGetOperation = false;
+ } else {
+ /*
+ * It is a GET request.
+ */
+ mGetOperation = true;
+ }
+
+ /*
+ * Determine if the final bit is set
+ */
+ if ((request & 0x80) == 0) {
+ finalBitSet = false;
+ } else {
+ finalBitSet = true;
+ mRequestFinished = true;
+ }
+
+ int length = in.read();
+ length = (length << 8) + in.read();
+
+ /*
+ * Determine if the packet length is larger than this device can receive
+ */
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+ throw new IOException("Packet received was too large");
+ }
+
+ /*
+ * Determine if any headers were sent in the initial request
+ */
+ if (length > 3) {
+ byte[] data = new byte[length - 3];
+ bytesReceived = in.read(data);
+
+ while (bytesReceived != data.length) {
+ bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
+ }
+
+ byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
+
+ if (body != null) {
+ mHasBody = true;
+ }
+
+ if (requestHeader.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
+ } else {
+ mListener.setConnectionId(0);
+ }
+
+ if (requestHeader.mAuthResp != null) {
+ if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+ mExceptionString = "Authentication Failed";
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+ mClosed = true;
+ requestHeader.mAuthResp = null;
+ return;
+ }
+ }
+
+ if (requestHeader.mAuthChall != null) {
+ mParent.handleAuthChall(requestHeader);
+ // send the authResp to the client
+ replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+ System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+ replyHeader.mAuthResp.length);
+ requestHeader.mAuthResp = null;
+ requestHeader.mAuthChall = null;
+
+ }
+
+ if (body != null) {
+ mPrivateInput.writeBytes(body, 1);
+ } else {
+ while ((!mGetOperation) && (!finalBitSet)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (mPrivateInput.available() > 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (mPrivateInput.available() > 0) {
+ break;
+ }
+ }
+
+ // wait for get request finished !!!!
+ while (mGetOperation && !finalBitSet) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ }
+ if (finalBitSet && mGetOperation) {
+ mRequestFinished = true;
+ }
+ }
+
+ public boolean isValidBody() {
+ return mHasBody;
+ }
+
+ /**
+ * Determines if the operation should continue or should wait. If it should
+ * continue, this method will continue the operation.
+ * @param sendEmpty if <code>true</code> then this will continue the
+ * operation even if no headers will be sent; if <code>false</code>
+ * then this method will only continue the operation if there are
+ * headers to send
+ * @param inStream if<code>true</code> the stream is input stream, otherwise
+ * output stream
+ * @return <code>true</code> if the operation was completed;
+ * <code>false</code> if no operation took place
+ */
+ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+ throws IOException {
+ if (!mGetOperation) {
+ if (!finalBitSet) {
+ if (sendEmpty) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ } else {
+ if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ }
+ }
+
+ /**
+ * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
+ * will wait for a response from the client before ending.
+ * @param type the response code to send back to the client
+ * @return <code>true</code> if the final bit was not set on the reply;
+ * <code>false</code> if no reply was received because the operation
+ * ended, an abort was received, or the final bit was set in the
+ * reply
+ * @throws IOException if an IO error occurs
+ */
+ public synchronized boolean sendReply(int type) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int bytesReceived;
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ replyHeader.mConnectionID = null;
+ } else {
+ replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
+ int bodyLength = -1;
+ int orginalBodyLength = -1;
+
+ if (mPrivateOutput != null) {
+ bodyLength = mPrivateOutput.size();
+ orginalBodyLength = bodyLength;
+ }
+
+ if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
+
+ int end = 0;
+ int start = 0;
+
+ while (end != headerArray.length) {
+ end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
+ - ObexHelper.BASE_PACKET_LENGTH);
+ if (end == -1) {
+
+ mClosed = true;
+
+ if (mPrivateInput != null) {
+ mPrivateInput.close();
+ }
+
+ if (mPrivateOutput != null) {
+ mPrivateOutput.close();
+ }
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ throw new IOException("OBEX Packet exceeds max packet size");
+ }
+ byte[] sendHeader = new byte[end - start];
+ System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+
+ mParent.sendResponse(type, sendHeader);
+ start = end;
+ }
+
+ if (bodyLength > 0) {
+ return true;
+ } else {
+ return false;
+ }
+
+ } else {
+ out.write(headerArray);
+ }
+
+ if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
+ if (bodyLength > 0) {
+ /*
+ * Determine if I can send the whole body or just part of
+ * the body. Remember that there is the 3 bytes for the
+ * response message and 3 bytes for the header ID and length
+ */
+ if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
+ bodyLength = mMaxPacketLength - headerArray.length - 6;
+ }
+
+ byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+ /*
+ * Since this is a put request if the final bit is set or
+ * the output stream is closed we need to send the 0x49
+ * (End of Body) otherwise, we need to send 0x48 (Body)
+ */
+ if ((finalBitSet) || (mPrivateOutput.isClosed())) {
+ out.write(0x49);
+ } else {
+ out.write(0x48);
+ }
+
+ bodyLength += 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+ out.write(body);
+ }
+ }
+
+ if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
+ out.write(0x49);
+ orginalBodyLength = 3;
+ out.write((byte)(orginalBodyLength >> 8));
+ out.write((byte)orginalBodyLength);
+
+ }
+
+ mResponseSize = 3;
+ mParent.sendResponse(type, out.toByteArray());
+
+ if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ int headerID = mInput.read();
+ int length = mInput.read();
+ length = (length << 8) + mInput.read();
+ if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
+ && (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
+ && (headerID != ObexHelper.OBEX_OPCODE_GET)
+ && (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+
+ if (length > 3) {
+ byte[] temp = new byte[length];
+ bytesReceived = mInput.read(temp);
+
+ while (bytesReceived != length) {
+ bytesReceived += mInput.read(temp, bytesReceived, length - bytesReceived);
+ }
+ }
+
+ /*
+ * Determine if an ABORT was sent as the reply
+ */
+ if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
+ mClosed = true;
+ isAborted = true;
+ mExceptionString = "Abort Received";
+ throw new IOException("Abort Received");
+ } else {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
+ mClosed = true;
+ mExceptionString = "Bad Request Received";
+ throw new IOException("Bad Request Received");
+ }
+ } else {
+
+ if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)
+ || (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+ finalBitSet = true;
+ }
+
+ /*
+ * Determine if the packet length is larger then this device can receive
+ */
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+ throw new IOException("Packet received was too large");
+ }
+
+ /*
+ * Determine if any headers were sent in the initial request
+ */
+ if (length > 3) {
+ byte[] data = new byte[length - 3];
+ bytesReceived = mInput.read(data);
+
+ while (bytesReceived != data.length) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length
+ - bytesReceived);
+ }
+ byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
+ if (body != null) {
+ mHasBody = true;
+ }
+ if (requestHeader.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper
+ .convertToLong(requestHeader.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (requestHeader.mAuthResp != null) {
+ if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+ mExceptionString = "Authentication Failed";
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+ mClosed = true;
+ requestHeader.mAuthResp = null;
+ return false;
+ }
+ requestHeader.mAuthResp = null;
+ }
+
+ if (requestHeader.mAuthChall != null) {
+ mParent.handleAuthChall(requestHeader);
+ // send the auhtResp to the client
+ replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+ System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+ replyHeader.mAuthResp.length);
+ requestHeader.mAuthResp = null;
+ requestHeader.mAuthChall = null;
+ }
+
+ if (body != null) {
+ mPrivateInput.writeBytes(body, 1);
+ }
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server called this method
+ */
+ public void abort() throws IOException {
+ throw new IOException("Called from a server");
+ }
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ public HeaderSet getReceivedHeader() throws IOException {
+ ensureOpen();
+ return requestHeader;
+ }
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ */
+ public void sendHeaders(HeaderSet headers) throws IOException {
+ ensureOpen();
+
+ if (headers == null) {
+ throw new IOException("Headers may not be null");
+ }
+
+ int[] headerList = headers.getHeaderList();
+ if (headerList != null) {
+ for (int i = 0; i < headerList.length; i++) {
+ replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+ }
+
+ }
+ }
+
+ /**
+ * Retrieves the response code retrieved from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> interface.
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet</code> in a <code>ClientSession</code>
+ * object; if this is called from a server
+ */
+ public int getResponseCode() throws IOException {
+ throw new IOException("Called from a server");
+ }
+
+ /**
+ * Always returns <code>null</code>
+ * @return <code>null</code>
+ */
+ public String getEncoding() {
+ return null;
+ }
+
+ /**
+ * Returns the type of content that the resource connected to is providing.
+ * E.g. if the connection is via HTTP, then the value of the content-type
+ * header field is returned.
+ * @return the content type of the resource that the URL references, or
+ * <code>null</code> if not known
+ */
+ public String getType() {
+ try {
+ return (String)requestHeader.getHeader(HeaderSet.TYPE);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the length of the content which is being provided. E.g. if the
+ * connection is via HTTP, then the value of the content-length header field
+ * is returned.
+ * @return the content length of the resource that this connection's URL
+ * references, or -1 if the content length is not known
+ */
+ public long getLength() {
+ try {
+ Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
+
+ if (temp == null) {
+ return -1;
+ } else {
+ return temp.longValue();
+ }
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketLength - 6;
+ }
+
+ /**
+ * Open and return an input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public InputStream openInputStream() throws IOException {
+ ensureOpen();
+ return mPrivateInput;
+ }
+
+ /**
+ * Open and return a data input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ /**
+ * Open and return an output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public OutputStream openOutputStream() throws IOException {
+ ensureOpen();
+
+ if (mPrivateOutputOpen) {
+ throw new IOException("no more input streams available, stream already opened");
+ }
+
+ if (!mRequestFinished) {
+ throw new IOException("no output streams available ,request not finished");
+ }
+
+ if (mPrivateOutput == null) {
+ mPrivateOutput = new PrivateOutputStream(this, mMaxPacketLength - 6);
+ }
+ mPrivateOutputOpen = true;
+ return mPrivateOutput;
+ }
+
+ /**
+ * Open and return a data output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ /**
+ * Closes the connection and ends the transaction
+ * @throws IOException if the operation has already ended or is closed
+ */
+ public void close() throws IOException {
+ ensureOpen();
+ mClosed = true;
+ }
+
+ /**
+ * Verifies that the connection is open and no exceptions should be thrown.
+ * @throws IOException if an exception needs to be thrown
+ */
+ public void ensureOpen() throws IOException {
+ if (mExceptionString != null) {
+ throw new IOException(mExceptionString);
+ }
+ if (mClosed) {
+ throw new IOException("Operation has already ended");
+ }
+ }
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * <P>
+ * Included to implement the BaseStream interface only. It does not do
+ * anything on the server side since the operation of the Operation object
+ * is not done until after the handler returns from its method.
+ * @throws IOException if the operation is completed
+ */
+ public void ensureNotDone() throws IOException {
+ }
+
+ /**
+ * Called when the output or input stream is closed. It does not do anything
+ * on the server side since the operation of the Operation object is not
+ * done until after the handler returns from its method.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ public void streamClosed(boolean inStream) throws IOException {
+
+ }
+}
diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java
new file mode 100644
index 0000000..d93e5b6
--- /dev/null
+++ b/obex/javax/obex/ServerRequestHandler.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+/**
+ * The <code>ServerRequestHandler</code> class defines an event listener that
+ * will respond to OBEX requests made to the server.
+ * <P>
+ * The <code>onConnect()</code>, <code>onSetPath()</code>,
+ * <code>onDelete()</code>, <code>onGet()</code>, and <code>onPut()</code>
+ * methods may return any response code defined in the
+ * <code>ResponseCodes</code> class except for <code>OBEX_HTTP_CONTINUE</code>.
+ * If <code>OBEX_HTTP_CONTINUE</code> or a value not defined in the
+ * <code>ResponseCodes</code> class is returned, the server implementation will
+ * send an <code>OBEX_HTTP_INTERNAL_ERROR</code> response to the client.
+ * <P>
+ * <STRONG>Connection ID and Target Headers</STRONG>
+ * <P>
+ * According to the IrOBEX specification, a packet may not contain a Connection
+ * ID and Target header. Since the Connection ID header is managed by the
+ * implementation, it will not send a Connection ID header, if a Connection ID
+ * was specified, in a packet that has a Target header. In other words, if an
+ * application adds a Target header to a <code>HeaderSet</code> object used in
+ * an OBEX operation and a Connection ID was specified, no Connection ID will be
+ * sent in the packet containing the Target header.
+ * <P>
+ * <STRONG>CREATE-EMPTY Requests</STRONG>
+ * <P>
+ * A CREATE-EMPTY request allows clients to create empty objects on the server.
+ * When a CREATE-EMPTY request is received, the <code>onPut()</code> method will
+ * be called by the implementation. To differentiate between a normal PUT
+ * request and a CREATE-EMPTY request, an application must open the
+ * <code>InputStream</code> from the <code>Operation</code> object passed to the
+ * <code>onPut()</code> method. For a PUT request, the application will be able
+ * to read Body data from this <code>InputStream</code>. For a CREATE-EMPTY
+ * request, there will be no Body data to read. Therefore, a call to
+ * <code>InputStream.read()</code> will return -1.
+ * @hide
+ */
+public class ServerRequestHandler {
+
+ private long mConnectionId;
+
+ /**
+ * Creates a <code>ServerRequestHandler</code>.
+ */
+ protected ServerRequestHandler() {
+ /*
+ * A connection ID of -1 implies there is no conenction ID
+ */
+ mConnectionId = -1;
+ }
+
+ /**
+ * Sets the connection ID header to include in the reply packets.
+ * @param connectionId the connection ID to use; -1 if no connection ID
+ * should be sent
+ * @throws IllegalArgumentException if <code>id</code> is not in the range
+ * -1 to 2<sup>32</sup>-1
+ */
+ public void setConnectionId(final long connectionId) {
+ if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Illegal Connection ID");
+ }
+ mConnectionId = connectionId;
+ }
+
+ /**
+ * Retrieves the connection ID that is being used in the present connection.
+ * This method will return -1 if no connection ID is being used.
+ * @return the connection id being used or -1 if no connection ID is being
+ * used
+ */
+ public long getConnectionId() {
+ return mConnectionId;
+ }
+
+ /**
+ * Called when a CONNECT request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onConnect()</code> will always return an <code>OBEX_HTTP_OK</code>
+ * response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onConnect(HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ /**
+ * Called when a DISCONNECT request is received.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ */
+ public void onDisconnect(HeaderSet request, HeaderSet reply) {
+ }
+
+ /**
+ * Called when a SETPATH request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onSetPath()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @param backup <code>true</code> if the client requests that the server
+ * back up one directory before changing to the path described by
+ * <code>name</code>; <code>false</code> to apply the request to the
+ * present path
+ * @param create <code>true</code> if the path should be created if it does
+ * not already exist; <code>false</code> if the path should not be
+ * created if it does not exist and an error code should be returned
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
+
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a DELETE request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onDelete()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onDelete(HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a PUT request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onPut()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * If an ABORT request is received during the processing of a PUT request,
+ * <code>op</code> will be closed by the implementation.
+ * @param operation contains the headers sent by the client and allows new
+ * headers to be sent in the reply; <code>op</code> will never be
+ * <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onPut(Operation operation) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a GET request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onGet()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * If an ABORT request is received during the processing of a GET request,
+ * <code>op</code> will be closed by the implementation.
+ * @param operation contains the headers sent by the client and allows new
+ * headers to be sent in the reply; <code>op</code> will never be
+ * <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onGet(Operation operation) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when this object attempts to authenticate a client and the
+ * authentication request fails because the response digest in the
+ * authentication response header was wrong.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ * @param userName the user name returned in the authentication response;
+ * <code>null</code> if no user name was provided in the response
+ */
+ public void onAuthenticationFailure(byte[] userName) {
+ }
+
+ /**
+ * Called by ServerSession to update the status of current transaction
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ */
+ public void updateStatus(String message) {
+ }
+
+ /**
+ * Called when session is closed.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ */
+ public void onClose() {
+ }
+}
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
new file mode 100644
index 0000000..423d5a7
--- /dev/null
+++ b/obex/javax/obex/ServerSession.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class in an implementation of the OBEX ServerSession.
+ * @hide
+ */
+public final class ServerSession extends ObexSession implements Runnable {
+
+ private static final String TAG = "Obex ServerSession";
+
+ private ObexTransport mTransport;
+
+ private InputStream mInput;
+
+ private OutputStream mOutput;
+
+ private ServerRequestHandler mListener;
+
+ private Thread mProcessThread;
+
+ private int mMaxPacketLength;
+
+ private boolean mClosed;
+
+ /**
+ * Creates new ServerSession.
+ * @param trans the connection to the client
+ * @param handler the event listener that will process requests
+ * @param auth the authenticator to use with this connection
+ * @throws IOException if an error occurred while opening the input and
+ * output streams
+ */
+ public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
+ throws IOException {
+ mAuthenticator = auth;
+ mTransport = trans;
+ mInput = mTransport.openInputStream();
+ mOutput = mTransport.openOutputStream();
+ mListener = handler;
+ mMaxPacketLength = 256;
+
+ mClosed = false;
+ mProcessThread = new Thread(this);
+ mProcessThread.start();
+ }
+
+ /**
+ * Processes requests made to the server and forwards them to the
+ * appropriate event listener.
+ */
+ public void run() {
+ try {
+
+ boolean done = false;
+ while (!done && !mClosed) {
+ int requestType = mInput.read();
+ switch (requestType) {
+ case ObexHelper.OBEX_OPCODE_CONNECT:
+ handleConnectRequest();
+ break;
+
+ case ObexHelper.OBEX_OPCODE_DISCONNECT:
+ handleDisconnectRequest();
+ done = true;
+ break;
+
+ case ObexHelper.OBEX_OPCODE_GET:
+ case ObexHelper.OBEX_OPCODE_GET_FINAL:
+ handleGetRequest(requestType);
+ break;
+
+ case ObexHelper.OBEX_OPCODE_PUT:
+ case ObexHelper.OBEX_OPCODE_PUT_FINAL:
+ handlePutRequest(requestType);
+ break;
+
+ case ObexHelper.OBEX_OPCODE_SETPATH:
+ handleSetPathRequest();
+ break;
+
+ case -1:
+ done = true;
+ break;
+
+ default:
+
+ /*
+ * Received a request type that is not recognized so I am
+ * just going to read the packet and send a not implemented
+ * to the client
+ */
+ int length = mInput.read();
+ length = (length << 8) + mInput.read();
+ for (int i = 3; i < length; i++) {
+ mInput.read();
+ }
+ sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
+ }
+ }
+
+ } catch (NullPointerException e) {
+ Log.d(TAG, e.toString());
+ } catch (Exception e) {
+ Log.d(TAG, e.toString());
+ }
+ close();
+ }
+
+ /**
+ * Handles a PUT request from a client. This method will provide a
+ * <code>ServerOperation</code> object to the request handler. The
+ * <code>ServerOperation</code> object will handle the rest of the request.
+ * It will also send replies and receive requests until the final reply
+ * should be sent. When the final reply should be sent, this method will get
+ * the response code to use and send the reply. The
+ * <code>ServerOperation</code> object will always reply with a
+ * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+ * needed.
+ * @param type the type of request received; either 0x02 or 0x82
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handlePutRequest(int type) throws IOException {
+ ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+ try {
+ int response = -1;
+
+ if ((op.finalBitSet) && !op.isValidBody()) {
+ response = validateResponseCode(mListener
+ .onDelete(op.requestHeader, op.replyHeader));
+ } else {
+ response = validateResponseCode(mListener.onPut(op));
+ }
+ if (response != ResponseCodes.OBEX_HTTP_OK) {
+ op.sendReply(response);
+ } else if (!op.isAborted) {
+ // wait for the final bit
+ while (!op.finalBitSet) {
+ op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ }
+ op.sendReply(response);
+ }
+ } catch (Exception e) {
+ /*To fix bugs in aborted cases,
+ *(client abort file transfer prior to the last packet which has the end of body header,
+ *internal error should not be sent because server has already replied with
+ *OK response in "sendReply")
+ */
+ if (!op.isAborted) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ }
+ }
+ }
+
+ /**
+ * Handles a GET request from a client. This method will provide a
+ * <code>ServerOperation</code> object to the request handler. The
+ * <code>ServerOperation</code> object will handle the rest of the request.
+ * It will also send replies and receive requests until the final reply
+ * should be sent. When the final reply should be sent, this method will get
+ * the response code to use and send the reply. The
+ * <code>ServerOperation</code> object will always reply with a
+ * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+ * needed.
+ * @param type the type of request received; either 0x03 or 0x83
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleGetRequest(int type) throws IOException {
+ ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+ try {
+ int response = validateResponseCode(mListener.onGet(op));
+
+ if (!op.isAborted) {
+ op.sendReply(response);
+ }
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ }
+ }
+
+ /**
+ * Send standard response.
+ * @param code the response code to send
+ * @param header the headers to include in the response
+ * @throws IOException if an IO error occurs
+ */
+ public void sendResponse(int code, byte[] header) throws IOException {
+ int totalLength = 3;
+ byte[] data = null;
+
+ if (header != null) {
+ totalLength += header.length;
+ data = new byte[totalLength];
+ data[0] = (byte)code;
+ data[1] = (byte)(totalLength >> 8);
+ data[2] = (byte)totalLength;
+ System.arraycopy(header, 0, data, 3, header.length);
+ } else {
+ data = new byte[totalLength];
+ data[0] = (byte)code;
+ data[1] = (byte)0x00;
+ data[2] = (byte)totalLength;
+ }
+ mOutput.write(data);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a SETPATH request from a client. This method will read the rest
+ * of the request from the client. Assuming the request is valid, it will
+ * create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server
+ * with the response code provided.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleSetPathRequest() throws IOException {
+ int length;
+ int flags;
+ @SuppressWarnings("unused")
+ int constants;
+ int totalLength = 3;
+ byte[] head = null;
+ int code = -1;
+ int bytesReceived;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+
+ length = mInput.read();
+ length = (length << 8) + mInput.read();
+ flags = mInput.read();
+ constants = mInput.read();
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 3;
+ } else {
+ if (length > 5) {
+ byte[] headers = new byte[length - 5];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(-1);
+ }
+ // the Auth chan is initiated by the server, client sent back the authResp .
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+ // the Auth challenge is initiated by the client
+ // the server will send back the authResp to the client
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ reply.mAuthResp = new byte[request.mAuthResp.length];
+ System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+ reply.mAuthResp.length);
+ request.mAuthChall = null;
+ request.mAuthResp = null;
+ }
+ boolean backup = false;
+ boolean create = true;
+ if (!((flags & 1) == 0)) {
+ backup = true;
+ }
+ if ((flags & 2) == 0) {
+ create = false;
+ }
+
+ try {
+ code = mListener.onSetPath(request, reply, backup, create);
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ return;
+ }
+
+ code = validateResponseCode(code);
+
+ if (reply.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+ } else {
+ mChallengeDigest = null;
+ }
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 3;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ // Compute Length of OBEX SETPATH packet
+ byte[] replyData = new byte[totalLength];
+ replyData[0] = (byte)code;
+ replyData[1] = (byte)(totalLength >> 8);
+ replyData[2] = (byte)totalLength;
+ if (head != null) {
+ System.arraycopy(head, 0, replyData, 3, head.length);
+ }
+ /*
+ * Write the OBEX SETPATH packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+ */
+ mOutput.write(replyData);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a disconnect request from a client. This method will read the
+ * rest of the request from the client. Assuming the request is valid, it
+ * will create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleDisconnectRequest() throws IOException {
+ int length;
+ int code = ResponseCodes.OBEX_HTTP_OK;
+ int totalLength = 3;
+ byte[] head = null;
+ int bytesReceived;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+
+ length = mInput.read();
+ length = (length << 8) + mInput.read();
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 3;
+ } else {
+ if (length > 3) {
+ byte[] headers = new byte[length - 3];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+ }
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ request.mAuthChall = null;
+ }
+
+ try {
+ mListener.onDisconnect(request, reply);
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ return;
+ }
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 3;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ // Compute Length of OBEX CONNECT packet
+ byte[] replyData;
+ if (head != null) {
+ replyData = new byte[3 + head.length];
+ } else {
+ replyData = new byte[3];
+ }
+ replyData[0] = (byte)code;
+ replyData[1] = (byte)(totalLength >> 8);
+ replyData[2] = (byte)totalLength;
+ if (head != null) {
+ System.arraycopy(head, 0, replyData, 3, head.length);
+ }
+ /*
+ * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+ */
+ mOutput.write(replyData);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a connect request from a client. This method will read the rest
+ * of the request from the client. Assuming the request is valid, it will
+ * create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server
+ * with the response code provided.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleConnectRequest() throws IOException {
+ int packetLength;
+ @SuppressWarnings("unused")
+ int version;
+ @SuppressWarnings("unused")
+ int flags;
+ int totalLength = 7;
+ byte[] head = null;
+ int code = -1;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+ int bytesReceived;
+
+ /*
+ * Read in the length of the OBEX packet, OBEX version, flags, and max
+ * packet length
+ */
+ packetLength = mInput.read();
+ packetLength = (packetLength << 8) + mInput.read();
+ version = mInput.read();
+ flags = mInput.read();
+ mMaxPacketLength = mInput.read();
+ mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
+
+ // should we check it?
+ if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
+ }
+
+ if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 7;
+ } else {
+ if (packetLength > 7) {
+ byte[] headers = new byte[packetLength - 7];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+ }
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ reply.mAuthResp = new byte[request.mAuthResp.length];
+ System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+ reply.mAuthResp.length);
+ request.mAuthChall = null;
+ request.mAuthResp = null;
+ }
+
+ try {
+ code = mListener.onConnect(request, reply);
+ code = validateResponseCode(code);
+
+ if (reply.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+ } else {
+ mChallengeDigest = null;
+ }
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 7;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ totalLength = 7;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+ }
+ }
+
+ // Compute Length of OBEX CONNECT packet
+ byte[] length = ObexHelper.convertToByteArray(totalLength);
+
+ /*
+ * Write the OBEX CONNECT packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
+ * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
+ * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
+ */
+ byte[] sendData = new byte[totalLength];
+ sendData[0] = (byte)code;
+ sendData[1] = length[2];
+ sendData[2] = length[3];
+ sendData[3] = (byte)0x10;
+ sendData[4] = (byte)0x00;
+ sendData[5] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
+ sendData[6] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+
+ if (head != null) {
+ System.arraycopy(head, 0, sendData, 7, head.length);
+ }
+
+ mOutput.write(sendData);
+ mOutput.flush();
+ }
+
+ /**
+ * Closes the server session - in detail close I/O streams and the
+ * underlying transport layer. Internal flag is also set so that later
+ * attempt to read/write will throw an exception.
+ */
+ public synchronized void close() {
+ if (mListener != null) {
+ mListener.onClose();
+ }
+ try {
+ mInput.close();
+ mOutput.close();
+ mTransport.close();
+ mClosed = true;
+ } catch (Exception e) {
+ }
+ mTransport = null;
+ mInput = null;
+ mOutput = null;
+ mListener = null;
+ }
+
+ /**
+ * Verifies that the response code is valid. If it is not valid, it will
+ * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
+ * @param code the response code to check
+ * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
+ * if <code>code</code> is not valid
+ */
+ private int validateResponseCode(int code) {
+
+ if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
+ && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
+ && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
+ && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
+ && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
+ return code;
+ }
+ return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+}
diff --git a/obex/javax/obex/SessionNotifier.java b/obex/javax/obex/SessionNotifier.java
new file mode 100644
index 0000000..9836dd6
--- /dev/null
+++ b/obex/javax/obex/SessionNotifier.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * The <code>SessionNotifier</code> interface defines a connection notifier for
+ * server-side OBEX connections. When a <code>SessionNotifier</code> is created
+ * and calls <code>acceptAndOpen()</code>, it will begin listening for clients
+ * to create a connection at the transport layer. When the transport layer
+ * connection is received, the <code>acceptAndOpen()</code> method will return a
+ * <code>javax.microedition.io.Connection</code> that is the connection to the
+ * client. The <code>acceptAndOpen()</code> method also takes a
+ * <code>ServerRequestHandler</code> argument that will process the requests
+ * from the client that connects to the server.
+ * @hide
+ */
+public interface SessionNotifier {
+
+ /**
+ * Waits for a transport layer connection to be established and specifies
+ * the handler to handle the requests from the client. No authenticator is
+ * associated with this connection, therefore, it is implementation
+ * dependent as to how an authentication challenge and authentication
+ * response header will be received and processed.
+ * <P>
+ * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+ * on a <code>SessionNotifier</code> object that does not have a
+ * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+ * for this object will be added to the SDDB. This method requests the BCC
+ * to put the local device in connectable mode so that it will respond to
+ * connection attempts by clients.
+ * <P>
+ * The following checks are done to verify that the service record provided
+ * is valid. If any of these checks fail, then a
+ * <code>ServiceRegistrationException</code> is thrown.
+ * <UL>
+ * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+ * attributes for a <code>btgoep</code> service record, must be present in
+ * the <code>ServiceRecord</code> associated with this notifier.
+ * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+ * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+ * have changed the RFCOMM server channel number
+ * </UL>
+ * <P>
+ * This method will not ensure that <code>ServiceRecord</code> associated
+ * with this notifier is a completely valid service record. It is the
+ * responsibility of the application to ensure that the service record
+ * follows all of the applicable syntactic and semantic rules for service
+ * record correctness.
+ * @param handler the request handler that will respond to OBEX requests
+ * @return the connection to the client
+ * @throws IOException if an error occurs in the transport layer
+ * @throws NullPointerException if <code>handler</code> is <code>null</code>
+ */
+ ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
+
+ /**
+ * Waits for a transport layer connection to be established and specifies
+ * the handler to handle the requests from the client and the
+ * <code>Authenticator</code> to use to respond to authentication challenge
+ * and authentication response headers.
+ * <P>
+ * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+ * on a <code>SessionNotifier</code> object that does not have a
+ * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+ * for this object will be added to the SDDB. This method requests the BCC
+ * to put the local device in connectable mode so that it will respond to
+ * connection attempts by clients.
+ * <P>
+ * The following checks are done to verify that the service record provided
+ * is valid. If any of these checks fail, then a
+ * <code>ServiceRegistrationException</code> is thrown.
+ * <UL>
+ * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+ * attributes for a <code>btgoep</code> service record, must be present in
+ * the <code>ServiceRecord</code> associated with this notifier.
+ * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+ * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+ * have changed the RFCOMM server channel number
+ * </UL>
+ * <P>
+ * This method will not ensure that <code>ServiceRecord</code> associated
+ * with this notifier is a completely valid service record. It is the
+ * responsibility of the application to ensure that the service record
+ * follows all of the applicable syntactic and semantic rules for service
+ * record correctness.
+ * @param handler the request handler that will respond to OBEX requests
+ * @param auth the <code>Authenticator</code> to use with this connection;
+ * if <code>null</code> then no <code>Authenticator</code> will be
+ * used
+ * @return the connection to the client
+ * @throws IOException if an error occurs in the transport layer
+ * @throws NullPointerException if <code>handler</code> is <code>null</code>
+ */
+ ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
+}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 25cfcb8..545fd0e 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -131,6 +131,30 @@
/* Interfaces defined by EGL_KHR_image above */
#endif
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+struct android_native_buffer_t;
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_ANDROID_get_render_buffer
+#define EGL_ANDROID_get_render_buffer 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw);
+#endif
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw);
+#endif
+
+#ifndef EGL_ANDROID_swap_rectangle
+#define EGL_ANDROID_swap_rectangle 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif
+
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/include/EGL/eglnatives.h b/opengl/include/EGL/eglnatives.h
deleted file mode 100644
index 21622dc..0000000
--- a/opengl/include/EGL/eglnatives.h
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_EGLNATIVES_H
-#define ANDROID_EGLNATIVES_H
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-/* flags returned from swapBuffer */
-#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001
-
-/* surface flags */
-#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001
-
-enum native_pixel_format_t
-{
- NATIVE_PIXEL_FORMAT_RGBA_8888 = 1,
- NATIVE_PIXEL_FORMAT_RGB_565 = 4,
- NATIVE_PIXEL_FORMAT_BGRA_8888 = 5,
- NATIVE_PIXEL_FORMAT_RGBA_5551 = 6,
- NATIVE_PIXEL_FORMAT_RGBA_4444 = 7,
- NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
- NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
-};
-
-enum native_memory_type_t
-{
- NATIVE_MEMORY_TYPE_PMEM = 0,
- NATIVE_MEMORY_TYPE_GPU = 1,
- NATIVE_MEMORY_TYPE_FB = 2,
- NATIVE_MEMORY_TYPE_HEAP = 128
-};
-
-
-struct egl_native_window_t
-{
- /*
- * magic must be set to 0x600913
- */
- uint32_t magic;
-
- /*
- * must be sizeof(egl_native_window_t)
- */
- uint32_t version;
-
- /*
- * ident is reserved for the Android platform
- */
- uint32_t ident;
-
- /*
- * width, height and stride of the window in pixels
- * Any of these value can be nul in which case GL commands are
- * accepted and processed as usual, but not rendering occurs.
- */
- int width; // w=h=0 is legal
- int height;
- int stride;
-
- /*
- * format of the native window (see ui/PixelFormat.h)
- */
- int format;
-
- /*
- * Offset of the bits in the VRAM
- */
- intptr_t offset;
-
- /*
- * flags describing some attributes of this surface
- * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after
- * eglSwapBuffers
- */
- uint32_t flags;
-
- /*
- * horizontal and vertical resolution in DPI
- */
- float xdpi;
- float ydpi;
-
- /*
- * refresh rate in frames per second (Hz)
- */
- float fps;
-
-
- /*
- * Base memory virtual address of the surface in the CPU side
- */
- intptr_t base;
-
- /*
- * Heap the offset above is based from
- */
- int fd;
-
- /*
- * Memory type the surface resides into
- */
- uint8_t memory_type;
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- uint8_t reserved_pad[3];
- int reserved[8];
-
- /*
- * Vertical stride (only relevant with planar formats)
- */
-
- int vstride;
-
- /*
- * Hook called by EGL to hold a reference on this structure
- */
- void (*incRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to release a reference on this structure
- */
- void (*decRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to perform a page flip. This function
- * may update the size attributes above, in which case it returns
- * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
- */
- uint32_t (*swapBuffers)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_0)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_1)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_2)(void);
-
-
- /*
- * Hook called by EGL when the native surface is associated to EGL
- * (eglCreateWindowSurface). Can be NULL.
- */
- void (*connect)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL when eglDestroySurface is called. Can be NULL.
- */
- void (*disconnect)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc[11])(void);
-
- /*
- * Some storage reserved for the oem driver.
- */
- intptr_t oem[4];
-};
-
-
-struct egl_native_pixmap_t
-{
- int32_t version; /* must be 32 */
- int32_t width;
- int32_t height;
- int32_t stride;
- uint8_t* data;
- uint8_t format;
- uint8_t rfu[3];
- union {
- uint32_t compressedFormat;
- int32_t vstride;
- };
- int32_t reserved;
-};
-
-/*****************************************************************************/
-
-/*
- * This a convenience function to create a NativeWindowType surface
- * that maps to the whole screen
- * This function is actually implemented in libui.so
- */
-
-struct egl_native_window_t* android_createDisplaySurface();
-
-/*****************************************************************************/
-
-
-/*
- * OEM's egl's library (libhgl.so) must imlement these hooks to allocate
- * the GPU memory they need
- */
-
-
-typedef struct
-{
- // for internal use
- void* user;
- // virtual address of this area
- void* base;
- // size of this area in bytes
- size_t size;
- // physical address of this area
- void* phys;
- // offset in this area available to the GPU
- size_t offset;
- // fd of this area
- int fd;
-} gpu_area_t;
-
-typedef struct
-{
- // area where GPU registers are mapped
- gpu_area_t regs;
- // number of extra areas (currently limited to 2)
- int32_t count;
- // extra GPU areas (currently limited to 2)
- gpu_area_t gpu[2];
-} request_gpu_t;
-
-
-typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user);
-typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle);
-typedef void (*register_gpu_t)
- (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t);
-
-void oem_register_gpu(
- void* user,
- OEM_EGL_acquire_gpu_t acquire,
- OEM_EGL_release_gpu_t release);
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_EGLNATIVES_H */
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index ac00901..53e9e6116 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -89,9 +89,10 @@
#elif defined(ANDROID)
-#include <EGL/eglnatives.h>
+struct android_native_window_t;
+struct egl_native_pixmap_t;
-typedef struct egl_native_window_t* EGLNativeWindowType;
+typedef struct android_native_window_t* EGLNativeWindowType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
index 0924cae..198e679 100644
--- a/opengl/include/GLES/glplatform.h
+++ b/opengl/include/GLES/glplatform.h
@@ -28,12 +28,6 @@
#define GL_APIENTRY KHRONOS_APIENTRY
-// XXX: this should probably not be here
-#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
-
-// XXX: not sure how this is intended to be used
-#define GL_GLEXT_PROTOTYPES
-
#endif
#endif /* __glplatform_h_ */
diff --git a/opengl/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h
new file mode 100644
index 0000000..0182a67
--- /dev/null
+++ b/opengl/include/GLES2/gl2.h
@@ -0,0 +1,620 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
new file mode 100644
index 0000000..72f1ae7
--- /dev/null
+++ b/opengl/include/GLES2/gl2ext.h
@@ -0,0 +1,518 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 8271 $ on $Date:: 2009-05-21 09:33:40 -0700 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture3D */
+#ifndef GL_OES_texture3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA 0x80E1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint fence);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/opengl/include/GLES2/gl2platform.h b/opengl/include/GLES2/gl2platform.h
new file mode 100644
index 0000000..3e9036c
--- /dev/null
+++ b/opengl/include/GLES2/gl2platform.h
@@ -0,0 +1,29 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+#endif /* __gl2platform_h_ */
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index ccb27cc..132473a 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -204,7 +204,6 @@
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this);
- holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
}
/**
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 3ce0414..2522656 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -6,6 +6,9 @@
include $(CLEAR_VARS)
+# Set to 1 to use gralloc and copybits
+LIBAGL_USE_GRALLOC_COPYBITS := 1
+
LOCAL_SRC_FILES:= \
egl.cpp \
state.cpp \
@@ -29,13 +32,23 @@
ifneq ($(TARGET_SIMULATOR),true)
# we need to access the private Bionic header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
-LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
+ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
+ LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
+ LOCAL_SRC_FILES += copybit.cpp
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_LDLIBS := -lpthread -ldl
-LOCAL_MODULE:= libagl
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
+LOCAL_MODULE:= libGLES_android
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index ce31854..255ccac 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -1,16 +1,16 @@
/*
** Copyright 2006, The Android Open Source Project
**
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
+ ** 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
+ ** 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
+ ** 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.
*/
@@ -19,11 +19,13 @@
#include "context.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
namespace android {
// ----------------------------------------------------------------------------
EGLTextureObject::EGLTextureObject()
- : mCount(0), mSize(0)
+ : mSize(0)
{
init();
}
@@ -53,6 +55,10 @@
memset(crop_rect, 0, sizeof(crop_rect));
generate_mipmap = GL_FALSE;
direct = GL_FALSE;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ try_copybit = false;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ buffer = 0;
}
void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
@@ -123,6 +129,7 @@
}
surface = *s;
internalformat = 0;
+ buffer = 0;
// we should keep the crop_rect, but it's delicate because
// the new size of the surface could make it invalid.
@@ -141,12 +148,26 @@
return NO_ERROR;
}
+status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+{
+ GGLSurface sur;
+ sur.version = sizeof(GGLSurface);
+ sur.width = native_buffer->width;
+ sur.height= native_buffer->height;
+ sur.stride= native_buffer->stride;
+ sur.format= native_buffer->format;
+ sur.data = 0;
+ setSurface(&sur);
+ buffer = native_buffer;
+ return NO_ERROR;
+}
+
status_t EGLTextureObject::reallocate(
GLint level, int w, int h, int s,
int format, int compressedFormat, int bpr)
{
const size_t size = h * bpr;
- if (level == 0)
+ if (level == 0)
{
if (size!=mSize || !surface.data) {
if (mSize && surface.data) {
@@ -177,9 +198,9 @@
return NO_MEMORY;
}
- LOGW_IF(level-1 >= mNumExtraLod,
+ LOGW_IF(level-1 >= mNumExtraLod,
"specifying mipmap level %d, but # of level is %d",
- level, mNumExtraLod+1);
+ level, mNumExtraLod+1);
GGLSurface& mipmap = editMip(level);
if (mipmap.data)
@@ -224,7 +245,7 @@
// ----------------------------------------------------------------------------
EGLSurfaceManager::EGLSurfaceManager()
- : TokenManager(), mCount(0)
+ : TokenManager()
{
}
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 74ed1a4..279e040 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -1,16 +1,16 @@
/*
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -30,6 +30,8 @@
#include <private/pixelflinger/ggl_context.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include "Tokenizer.h"
#include "TokenManager.h"
@@ -39,22 +41,20 @@
// ----------------------------------------------------------------------------
-class EGLTextureObject
+class EGLTextureObject : public LightRefBase<EGLTextureObject>
{
public:
EGLTextureObject();
~EGLTextureObject();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- inline uint32_t getStrongCount() const;
+ status_t setSurface(GGLSurface const* s);
+ status_t setImage(android_native_buffer_t* buffer);
+ void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
- status_t setSurface(GGLSurface const* s);
status_t reallocate(GLint level,
int w, int h, int s,
int format, int compressedFormat, int bpr);
- inline size_t size() const;
+ inline size_t size() const { return mSize; }
const GGLSurface& mip(int lod) const;
GGLSurface& editMip(int lod);
bool hasMipmaps() const { return mMipmaps!=0; }
@@ -65,7 +65,6 @@
status_t allocateMipmaps();
void freeMipmaps();
void init();
- mutable int32_t mCount;
size_t mSize;
GGLSurface *mMipmaps;
int mNumExtraLod;
@@ -81,36 +80,22 @@
GLint crop_rect[4];
GLint generate_mipmap;
GLint direct;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ bool try_copybit;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ android_native_buffer_t* buffer;
};
-void EGLTextureObject::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLTextureObject::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-uint32_t EGLTextureObject::getStrongCount() const {
- return mCount;
-}
-size_t EGLTextureObject::size() const {
- return mSize;
-}
-
// ----------------------------------------------------------------------------
-class EGLSurfaceManager : public TokenManager
+class EGLSurfaceManager :
+ public LightRefBase<EGLSurfaceManager>,
+ public TokenManager
{
public:
EGLSurfaceManager();
~EGLSurfaceManager();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- typedef void weakref_type;
-
sp<EGLTextureObject> createTexture(GLuint name);
sp<EGLTextureObject> removeTexture(GLuint name);
sp<EGLTextureObject> replaceTexture(GLuint name);
@@ -118,21 +103,10 @@
sp<EGLTextureObject> texture(GLuint name);
private:
- mutable int32_t mCount;
mutable Mutex mLock;
KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
};
-void EGLSurfaceManager::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLSurfaceManager::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 3e9c6a5..f414ee5 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -1,16 +1,16 @@
-/*
+/*
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -26,6 +26,9 @@
#include "primitives.h"
#include "texture.h"
#include "BufferObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
// ----------------------------------------------------------------------------
@@ -250,7 +253,7 @@
v[2] = GGL_S_TO_X(p[2]);
}
-typedef array_t::fetcher_t fn_t;
+typedef array_t::fetcher_t fn_t;
static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
{ 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
@@ -334,7 +337,7 @@
this->bounds = count;
}
-inline void array_t::resolve()
+inline void array_t::resolve()
{
physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
}
@@ -465,7 +468,7 @@
// We compute directly the index of a "free" entry from the locked
// state of v[2] and v[3].
v = c->vc.vBuffer + 2;
- v += v[0].locked | (v[1].locked<<1);
+ v += v[0].locked | (v[1].locked<<1);
}
// note: compileElement clears v->flags
c->arrays.compileElement(c, v, index);
@@ -480,7 +483,7 @@
#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
- vertex_t* const v = c->vc.vCache +
+ vertex_t* const v = c->vc.vCache +
(index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
if (ggl_likely(v->index == index)) {
@@ -491,7 +494,7 @@
#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
- vertex_t* v = c->vc.vCache +
+ vertex_t* v = c->vc.vCache +
(index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
// always record LRU in v[0]
@@ -532,12 +535,12 @@
return;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE);
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -569,13 +572,13 @@
count -= 1;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 1);
do {
- v0 = c->vc.vBuffer + 0;
+ v0 = c->vc.vBuffer + 0;
v = c->vc.vBuffer + 1;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -602,7 +605,7 @@
return;
drawPrimitivesLineStrip(c, first, count);
if (ggl_likely(count >= 3)) {
- vertex_t* v0 = c->vc.vBuffer;
+ vertex_t* v0 = c->vc.vBuffer;
vertex_t* v1 = c->vc.vBuffer + 1;
c->arrays.compileElement(c, v1, first);
const uint32_t cc = v0->flags & v1->flags;
@@ -617,12 +620,12 @@
return;
// vertex cache size must be multiple of 2
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -662,14 +665,14 @@
// because it allows us to preserve the same winding when the whole
// batch is culled. We also need 2 extra vertices in the array, because
// we always keep the two first ones.
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
do {
- v0 = c->vc.vBuffer + 0;
- v1 = c->vc.vBuffer + 1;
+ v0 = c->vc.vBuffer + 0;
+ v1 = c->vc.vBuffer + 1;
v = c->vc.vBuffer + 2;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -697,13 +700,19 @@
} while (count > 0);
}
-void drawPrimitivesTriangleStrip(ogles_context_t* c,
+void drawPrimitivesTriangleStrip(ogles_context_t* c,
GLint first, GLsizei count) {
drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
}
void drawPrimitivesTriangleFan(ogles_context_t* c,
GLint first, GLsizei count) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTriangleFanWithCopybit(c, first, count)) {
+ return;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
}
@@ -713,12 +722,12 @@
return;
// vertex cache size must be multiple of 3
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -779,11 +788,11 @@
{
if (ggl_unlikely(count < 2))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -806,11 +815,11 @@
drawIndexedPrimitivesLines(c, count, indices);
return;
}
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -825,7 +834,7 @@
} while (count);
v1->locked = 0;
- v1 = c->vc.vBuffer;
+ v1 = c->vc.vBuffer;
const uint32_t cc = v0->flags & v1->flags;
if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
c->prims.renderLine(c, v0, v1);
@@ -861,7 +870,7 @@
if (ggl_unlikely(count < 3))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1 = v+1;
@@ -985,17 +994,17 @@
const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
const size_t stride = c->arrays.vertex.stride / 4;
// const GLfixed* const& m = c->transforms.mvp.matrix.m;
-
+
GLfixed m[16];
memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
-
+
do {
const GLfixed rx = vp[0];
const GLfixed ry = vp[1];
const GLfixed rz = vp[2];
vp += stride;
v->index = first++;
- v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
@@ -1023,7 +1032,7 @@
#pragma mark clippers
#endif
-static void clipVec4(vec4_t& nv,
+static void clipVec4(vec4_t& nv,
GLfixed t, const vec4_t& s, const vec4_t& p)
{
for (int i=0; i<4 ; i++)
@@ -1086,10 +1095,10 @@
// automatically turn it off (in fact we could when the 4th coordinate
// is not spcified in the vertex array).
// W interpolation is never needed for points.
- GLboolean perspective =
+ GLboolean perspective =
c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
-
+
// set anti-aliasing
GLboolean smooth = GL_FALSE;
switch (mode) {
@@ -1120,7 +1129,7 @@
if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
want |= transform_state_t::TEXTURE;
}
- if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
+ if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
want |= transform_state_t::MODELVIEW; // needs eye coords
}
ogles_validate_transform(c, want);
@@ -1139,18 +1148,18 @@
c->arrays.mv_transform =
c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
-
+
/*
* ***********************************************************************
* pick fetchers
* ***********************************************************************
*/
-
+
array_machine_t& am = c->arrays;
am.vertex.fetch = fetchNop;
am.normal.fetch = currentNormal;
am.color.fetch = currentColor;
-
+
if (am.vertex.enable) {
am.vertex.resolve();
if (am.vertex.bo || am.vertex.pointer) {
@@ -1366,9 +1375,18 @@
if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
return; // all triangles are culled
+
validate_arrays(c, mode);
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+
drawArraysPrims[mode](c, first, count);
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1413,15 +1431,23 @@
// clear the vertex-cache
c->vc.clear();
validate_arrays(c, mode);
-
+
// if indices are in a buffer object, the pointer is treated as an
// offset in that buffer.
if (c->arrays.element_array_buffer) {
indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
}
- drawElementsPrims[mode](c, count, indices);
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+ drawElementsPrims[mode](c, count, indices);
+
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1448,7 +1474,7 @@
return;
}
}
- ((target == GL_ARRAY_BUFFER) ?
+ ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
}
@@ -1467,7 +1493,7 @@
ogles_error(c, GL_INVALID_ENUM);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1497,7 +1523,7 @@
ogles_error(c, GL_INVALID_VALUE);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1545,7 +1571,7 @@
}
}
}
- }
+ }
c->bufferObjectManager->deleteBuffers(n, buffers);
c->bufferObjectManager->recycleTokens(n, buffers);
}
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
new file mode 100644
index 0000000..867459d
--- /dev/null
+++ b/opengl/libagl/copybit.cpp
@@ -0,0 +1,460 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "primitives.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+#include <hardware/gralloc.h>
+#include <hardware/copybit.h>
+#include <private/ui/android_natives_priv.h>
+
+
+#define DEBUG_COPYBIT true
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void textureToCopyBitImage(
+ const GGLSurface* surface, buffer_handle_t buffer, copybit_image_t* img)
+{
+ img->w = surface->stride;
+ img->h = surface->height;
+ img->format = surface->format;
+ img->base = surface->data;
+ img->handle = (native_handle_t *)buffer;
+}
+
+struct clipRectRegion : public copybit_region_t {
+ clipRectRegion(ogles_context_t* c)
+ {
+ scissor_t const* scissor = &c->rasterizer.state.scissor;
+ r.l = scissor->left;
+ r.t = scissor->top;
+ r.r = scissor->right;
+ r.b = scissor->bottom;
+ next = iterate;
+ }
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ *rect = static_cast<clipRectRegion const*>(self)->r;
+ const_cast<copybit_region_t *>(self)->next = iterate_done;
+ return 1;
+ }
+ static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
+ return 0;
+ }
+ copybit_rect_t r;
+};
+
+static bool supportedCopybitsFormat(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_RGBX_8888:
+ case COPYBIT_FORMAT_RGB_888:
+ case COPYBIT_FORMAT_RGB_565:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ case COPYBIT_FORMAT_YCbCr_422_SP:
+ case COPYBIT_FORMAT_YCbCr_420_SP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool hasAlpha(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int fixedToByte(GGLfixed val) {
+ return (val - (val >> 8)) >> 8;
+}
+
+/**
+ * Performs a quick check of the rendering state. If this function returns
+ * false we cannot use the copybit driver.
+ */
+
+static bool checkContext(ogles_context_t* c) {
+
+ // By convention copybitQuickCheckContext() has already returned true.
+ // avoid checking the same information again.
+
+ if (c->copybits.blitEngine == NULL) {
+ LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
+ return false;
+ }
+
+ if (c->rasterizer.state.enables
+ & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
+ return false;
+ }
+
+ // Note: The drawSurfaceBuffer is only set for destination
+ // surfaces types that are supported by the hardware and
+ // do not have an alpha channel. So we don't have to re-check that here.
+
+ static const int tmu = 0;
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ EGLTextureObject* textureObject = u.texture;
+
+ if (!supportedCopybitsFormat(textureObject->surface.format)) {
+ LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
+ return false;
+ }
+ return true;
+}
+
+
+static bool copybit(GLint x, GLint y,
+ GLint w, GLint h,
+ EGLTextureObject* textureObject,
+ const GLint* crop_rect,
+ int transform,
+ ogles_context_t* c)
+{
+ // We assume checkContext has already been called and has already
+ // returned true.
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+
+ y = cbSurface.height - (y + h);
+
+ const GLint Ucr = crop_rect[0];
+ const GLint Vcr = crop_rect[1];
+ const GLint Wcr = crop_rect[2];
+ const GLint Hcr = crop_rect[3];
+
+ GLint screen_w = w;
+ GLint screen_h = h;
+ int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt
+ int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht
+ if (transform & COPYBIT_TRANSFORM_ROT_90) {
+ swap(screen_w, screen_h);
+ }
+ if (dsdx!=screen_w || dtdy!=screen_h) {
+ // in most cases the divide is not needed
+ dsdx /= screen_w;
+ dtdy /= screen_h;
+ }
+ dtdy = -dtdy; // see equation of dtdy above
+ if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
+ || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
+ // The requested scale is out of the range the hardware
+ // can support.
+ LOGD_IF(DEBUG_COPYBIT,
+ "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+ "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+ dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+ return false;
+ }
+
+ // copybit doesn't say anything about filtering, so we can't
+ // discriminate. On msm7k, copybit will always filter.
+ // the code below handles min/mag filters, we keep it as a reference.
+
+#ifdef MIN_MAG_FILTER
+ int32_t texelArea = gglMulx(dtdy, dsdx);
+ if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
+ // Non-linear filtering on a texture enlargement.
+ LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
+ return false;
+ }
+ if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
+ // Non-linear filtering on an texture shrink.
+ LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
+ return false;
+ }
+#endif
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ int planeAlpha = 255;
+ static const int tmu = 0;
+ texture_t& tev(c->rasterizer.state.texture[tmu]);
+ bool srcTextureHasAlpha = hasAlpha(textureObject->surface.format);
+ if (!srcTextureHasAlpha) {
+ planeAlpha = fixedToByte(c->currentColorClamped.a);
+ }
+
+ switch (tev.env) {
+ case GGL_REPLACE:
+ break;
+ case GGL_MODULATE:
+ if (! (c->currentColorClamped.r == FIXED_ONE &&
+ c->currentColorClamped.g == FIXED_ONE &&
+ c->currentColorClamped.b == FIXED_ONE)) {
+ LOGD_IF(DEBUG_COPYBIT,
+ "MODULATE and non white color (%08x, %08x, %08x)",
+ c->currentColorClamped.r,
+ c->currentColorClamped.g,
+ c->currentColorClamped.b);
+ return false;
+ }
+ if (srcTextureHasAlpha && c->currentColorClamped.a < FIXED_ONE) {
+ LOGD_IF(DEBUG_COPYBIT,
+ "MODULATE and texture w/alpha and alpha=%08x)",
+ c->currentColorClamped.a);
+ return false;
+ }
+ break;
+
+ default:
+ // Incompatible texture environment.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
+ return false;
+ }
+
+ bool blending = false;
+ if ((enables & GGL_ENABLE_BLENDING)
+ && !(c->rasterizer.state.blend.src == GL_ONE
+ && c->rasterizer.state.blend.dst == GL_ZERO)) {
+ // Blending is OK if it is
+ // the exact kind of blending that the copybits hardware supports.
+ // Note: The hardware only supports
+ // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
+ // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
+ // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
+ // because the performance is worth it, even if the results are
+ // not correct.
+ if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
+ || c->rasterizer.state.blend.src == GL_ONE)
+ && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
+ && c->rasterizer.state.blend.alpha_separate == 0)) {
+ // Incompatible blend mode.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
+ return false;
+ }
+ blending = true;
+ } else {
+ // No blending is OK if we are not using alpha.
+ if (srcTextureHasAlpha || planeAlpha != 255) {
+ // Incompatible alpha
+ LOGD_IF(DEBUG_COPYBIT, "incompatible alpha");
+ return false;
+ }
+ }
+
+ if (srcTextureHasAlpha && planeAlpha != 255) {
+ // Can't do two types of alpha at once.
+ LOGD_IF(DEBUG_COPYBIT, "src alpha and plane alpha");
+ return false;
+ }
+
+ // LOGW("calling copybits");
+
+ copybit_device_t* copybit = c->copybits.blitEngine;
+
+ copybit_image_t dst;
+ buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
+ textureToCopyBitImage(&cbSurface, target_hnd, &dst);
+ copybit_rect_t drect = {x, y, x+w, y+h};
+
+ copybit_image_t src;
+ buffer_handle_t source_hnd = textureObject->buffer->handle;
+ textureToCopyBitImage(&textureObject->surface, source_hnd, &src);
+ copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+ clipRectRegion it(c);
+ status_t err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ if (err != NO_ERROR) {
+ c->textures.tmu[0].texture->try_copybit = false;
+ }
+ return err == NO_ERROR ? true : false;
+}
+
+/*
+ * Try to draw a triangle fan with copybit, return false if we fail.
+ */
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (!checkContext(c)) {
+ return false;
+ }
+
+ // FIXME: we should handle culling here
+ c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
+
+ // we detect if we're dealing with a rectangle, by comparing the
+ // rectangles {v0,v2} and {v1,v3} which should be identical.
+
+ // NOTE: we should check that the rectangle is window aligned, however
+ // if we do that, the optimization won't be taken in a lot of cases.
+ // Since this code is intended to be used with SurfaceFlinger only,
+ // so it's okay...
+
+ const vec4_t& v0 = c->vc.vBuffer[0].window;
+ const vec4_t& v1 = c->vc.vBuffer[1].window;
+ const vec4_t& v2 = c->vc.vBuffer[2].window;
+ const vec4_t& v3 = c->vc.vBuffer[3].window;
+ int l = min(v0.x, v2.x);
+ int b = min(v0.y, v2.y);
+ int r = max(v0.x, v2.x);
+ int t = max(v0.y, v2.y);
+ if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
+ (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
+ return false;
+ }
+
+ // fetch and transform texture coordinates
+ // NOTE: maybe it would be better to have a "compileElementsAll" method
+ // that would ensure all vertex data are fetched and transformed
+ const transform_t& tr = c->transforms.texture[0].transform;
+ for (size_t i=0 ; i<4 ; i++) {
+ const GLubyte* tp = c->arrays.texture[0].element(i);
+ vertex_t* const v = &c->vc.vBuffer[i];
+ c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
+ // FIXME: we should bail if q!=1
+ c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
+ }
+
+ const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
+ const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
+ const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
+ const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
+ int txl = min(t0.x, t2.x);
+ int txb = min(t0.y, t2.y);
+ int txr = max(t0.x, t2.x);
+ int txt = max(t0.y, t2.y);
+ if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
+ (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
+ return false;
+ }
+ if ((txl != 0) || (txb != 0) ||
+ (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
+ // we could probably handle this case, if we wanted to
+ LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
+ txl, txb, txr, txt);
+ return false;
+ }
+
+ // at this point, we know we are dealing with a rectangle, so we
+ // only need to consider 3 vertices for computing the jacobians
+
+ const int dx01 = v1.x - v0.x;
+ const int dx02 = v2.x - v0.x;
+ const int dy01 = v1.y - v0.y;
+ const int dy02 = v2.y - v0.y;
+ const int ds01 = t1.S - t0.S;
+ const int ds02 = t2.S - t0.S;
+ const int dt01 = t1.T - t0.T;
+ const int dt02 = t2.T - t0.T;
+ const int area = dx01*dy02 - dy01*dx02;
+ int dsdx, dsdy, dtdx, dtdy;
+ if (area >= 0) {
+ dsdx = ds01*dy02 - ds02*dy01;
+ dtdx = dt01*dy02 - dt02*dy01;
+ dsdy = ds02*dx01 - ds01*dx02;
+ dtdy = dt02*dx01 - dt01*dx02;
+ } else {
+ dsdx = ds02*dy01 - ds01*dy02;
+ dtdx = dt02*dy01 - dt01*dy02;
+ dsdy = ds01*dx02 - ds02*dx01;
+ dtdy = dt01*dx02 - dt02*dx01;
+ }
+
+ // here we rely on the fact that we know the transform is
+ // a rigid-body transform AND that it can only rotate in 90 degrees
+ // increments
+
+ int transform = 0;
+ if (dsdx == 0) {
+ // 90 deg rotation case
+ // [ 0 dtdx ]
+ // [ dsdx 0 ]
+ transform |= COPYBIT_TRANSFORM_ROT_90;
+ // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
+ if (dtdx > 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dsdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ } else {
+ // [ dsdx 0 ]
+ // [ 0 dtdy ]
+ if (dsdx < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dtdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ }
+
+ //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
+ //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
+ // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
+
+ int x = l >> 4;
+ int y = b >> 4;
+ int w = (r-l) >> 4;
+ int h = (t-b) >> 4;
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ GLint tWidth = textureObject->surface.width;
+ GLint tHeight = textureObject->surface.height;
+ GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + h);
+ return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
+}
+
+/*
+ * Try to drawTexiOESWithCopybit, return false if we fail.
+ */
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c)
+{
+ // quickly process empty rects
+ if ((w|h) <= 0) {
+ return true;
+ }
+ if (!checkContext(c)) {
+ return false;
+ }
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
+}
+
+} // namespace android
+
diff --git a/opengl/libagl/copybit.h b/opengl/libagl/copybit.h
new file mode 100644
index 0000000..b8b5afd
--- /dev/null
+++ b/opengl/libagl/copybit.h
@@ -0,0 +1,75 @@
+/*
+**
+** Copyright 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 ANDROID_OPENGLES_COPYBIT_H
+#define ANDROID_OPENGLES_COPYBIT_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+#include "TextureObjectManager.h"
+namespace android {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c);
+
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first,
+ GLsizei count);
+
+inline bool copybitQuickCheckContext(ogles_context_t* c) {
+ return c->copybits.drawSurfaceBuffer != 0
+ && c->rasterizer.state.enabled_tmu == 1
+ && c->textures.tmu[0].texture->try_copybit;
+}
+
+/*
+ * Tries to draw a drawTexiOES using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c) {
+ if (!copybitQuickCheckContext(c)) {
+ return false;
+ }
+
+ return drawTexiOESWithCopybit_impl(x, y, z, w, h, c);
+}
+
+/*
+ * Tries to draw a triangle fan using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first,
+ GLsizei count) {
+ /*
+ * We are looking for the glDrawArrays call made by SurfaceFlinger.
+ */
+
+ if ((count!=4) || first || !copybitQuickCheckContext(c))
+ return false;
+
+ return drawTriangleFanWithCopybit_impl(c, first, count);
+}
+
+
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_COPYBIT_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 4461567..0762ebf 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -15,8 +15,6 @@
** limitations under the License.
*/
-#define LOG_TAG "EGL"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
@@ -41,6 +39,10 @@
#include <pixelflinger/format.h>
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/android_natives_priv.h>
+
+#include <hardware/copybit.h>
+
#include "context.h"
#include "state.h"
#include "texture.h"
@@ -89,9 +91,9 @@
struct egl_display_t
{
egl_display_t() : type(0), initialized(0) { }
-
+
static egl_display_t& get_display(EGLDisplay dpy);
-
+
static EGLBoolean is_valid(EGLDisplay dpy) {
return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
}
@@ -140,18 +142,21 @@
egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
virtual ~egl_surface_t();
virtual bool isValid() const = 0;
-
+
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
+ virtual EGLBoolean connect() { return EGL_TRUE; }
+ virtual void disconnect() {}
virtual EGLint getWidth() const = 0;
virtual EGLint getHeight() const = 0;
- virtual void* getBits() const = 0;
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
protected:
GGLSurface depth;
};
@@ -185,119 +190,507 @@
EGLint egl_surface_t::getSwapBehavior() const {
return EGL_BUFFER_PRESERVED;
}
+EGLBoolean egl_surface_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ return EGL_FALSE;
+}
+EGLClientBuffer egl_surface_t::getRenderBuffer() const {
+ return 0;
+}
// ----------------------------------------------------------------------------
-struct egl_window_surface_t : public egl_surface_t
+struct egl_window_surface_v2_t : public egl_surface_t
{
- egl_window_surface_t(
+ egl_window_surface_v2_t(
EGLDisplay dpy, EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window);
+ android_native_window_t* window);
- ~egl_window_surface_t();
+ ~egl_window_surface_v2_t();
- virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
+ virtual bool isValid() const { return nativeWindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC; }
virtual EGLBoolean swapBuffers();
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLint getWidth() const { return nativeWindow->width; }
- virtual EGLint getHeight() const { return nativeWindow->height; }
- virtual void* getBits() const;
+ virtual EGLBoolean connect();
+ virtual void disconnect();
+ virtual EGLint getWidth() const { return width; }
+ virtual EGLint getHeight() const { return height; }
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
+
private:
- egl_native_window_t* nativeWindow;
+ status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
+ status_t unlock(android_native_buffer_t* buf);
+ android_native_window_t* nativeWindow;
+ android_native_buffer_t* buffer;
+ android_native_buffer_t* previousBuffer;
+ gralloc_module_t const* module;
+ copybit_device_t* blitengine;
+ int width;
+ int height;
+ void* bits;
+ GGLFormat const* pixelFormatTable;
+
+ struct Rect {
+ inline Rect() { };
+ inline Rect(int32_t w, int32_t h)
+ : left(0), top(0), right(w), bottom(h) { }
+ inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
+ : left(l), top(t), right(r), bottom(b) { }
+ Rect& andSelf(const Rect& r) {
+ left = max(left, r.left);
+ top = max(top, r.top);
+ right = min(right, r.right);
+ bottom = min(bottom, r.bottom);
+ return *this;
+ }
+ bool isEmpty() const {
+ return (left>=right || top>=bottom);
+ }
+ void dump(char const* what) {
+ LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
+ what, left, top, right-left, bottom-top);
+ }
+
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
+
+ struct Region {
+ inline Region() : count(0) { }
+ typedef Rect const* const_iterator;
+ const_iterator begin() const { return storage; }
+ const_iterator end() const { return storage+count; }
+ static Region subtract(const Rect& lhs, const Rect& rhs) {
+ Region reg;
+ Rect* storage = reg.storage;
+ if (!lhs.isEmpty()) {
+ if (lhs.top < rhs.top) { // top rect
+ storage->left = lhs.left;
+ storage->top = lhs.top;
+ storage->right = lhs.right;
+ storage->bottom = rhs.top;
+ storage++;
+ }
+ const int32_t top = max(lhs.top, rhs.top);
+ const int32_t bot = min(lhs.bottom, rhs.bottom);
+ if (top < bot) {
+ if (lhs.left < rhs.left) { // left-side rect
+ storage->left = lhs.left;
+ storage->top = top;
+ storage->right = rhs.left;
+ storage->bottom = bot;
+ storage++;
+ }
+ if (lhs.right > rhs.right) { // right-side rect
+ storage->left = rhs.right;
+ storage->top = top;
+ storage->right = lhs.right;
+ storage->bottom = bot;
+ storage++;
+ }
+ }
+ if (lhs.bottom > rhs.bottom) { // bottom rect
+ storage->left = lhs.left;
+ storage->top = rhs.bottom;
+ storage->right = lhs.right;
+ storage->bottom = lhs.bottom;
+ storage++;
+ }
+ reg.count = storage - reg.storage;
+ }
+ return reg;
+ }
+ bool isEmpty() const {
+ return count<=0;
+ }
+ private:
+ Rect storage[4];
+ ssize_t count;
+ };
+
+ struct region_iterator : public copybit_region_t {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
+ this->next = iterate;
+ }
+ private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
+ }
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
+ };
+
+ void copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip);
+
+ Rect dirtyRegion;
+ Rect oldDirtyRegion;
};
-egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window)
- : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+ android_native_window_t* window)
+ : egl_surface_t(dpy, config, depthFormat),
+ nativeWindow(window), buffer(0), previousBuffer(0), module(0),
+ blitengine(0), bits(NULL)
{
- if (depthFormat) {
- depth.width = window->width;
- depth.height = window->height;
+ hw_module_t const* pModule;
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
+ module = reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
+ copybit_open(pModule, &blitengine);
+ }
+
+ pixelFormatTable = gglGetPixelFormatTable();
+
+ // keep a reference on the window
+ nativeWindow->common.incRef(&nativeWindow->common);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
+}
+
+egl_window_surface_v2_t::~egl_window_surface_v2_t() {
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ }
+ nativeWindow->common.decRef(&nativeWindow->common);
+ if (blitengine) {
+ copybit_close(blitengine);
+ }
+}
+
+EGLBoolean egl_window_surface_v2_t::connect()
+{
+ // we're intending to do software rendering
+ native_window_set_usage(nativeWindow,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ // dequeue a buffer
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ // allocate a corresponding depth-buffer
+ width = buffer->width;
+ height = buffer->height;
+ if (depth.format) {
+ depth.width = width;
+ depth.height = height;
depth.stride = depth.width; // use the width here
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
}
}
- nativeWindow->incRef(nativeWindow);
-}
-egl_window_surface_t::~egl_window_surface_t() {
- nativeWindow->decRef(nativeWindow);
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // Lock the buffer
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+ // pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("connect() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+ return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::swapBuffers()
+void egl_window_surface_v2_t::disconnect()
{
- uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
- if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+ if (buffer && bits) {
+ bits = NULL;
+ unlock(buffer);
+ }
+ // enqueue the last frame
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ buffer = 0;
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+}
+
+status_t egl_window_surface_v2_t::lock(
+ android_native_buffer_t* buf, int usage, void** vaddr)
+{
+ int err = module->lock(module, buf->handle,
+ usage, 0, 0, buf->width, buf->height, vaddr);
+ return err;
+}
+
+status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+{
+ if (!buf) return BAD_VALUE;
+ int err = module->unlock(module, buf->handle);
+ return err;
+}
+
+void egl_window_surface_v2_t::copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip)
+{
+ // FIXME: use copybit if possible
+ // NOTE: dst and src must be the same format
+
+ status_t err = NO_ERROR;
+ copybit_device_t* const copybit = blitengine;
+ if (copybit) {
+ copybit_image_t simg;
+ simg.w = src->width;
+ simg.h = src->height;
+ simg.format = src->format;
+ simg.handle = const_cast<native_handle_t*>(src->handle);
+
+ copybit_image_t dimg;
+ dimg.w = dst->width;
+ dimg.h = dst->height;
+ dimg.format = dst->format;
+ dimg.handle = const_cast<native_handle_t*>(dst->handle);
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ region_iterator it(clip);
+ err = copybit->blit(copybit, &dimg, &simg, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
+ }
+
+ if (!copybit || err) {
+ Region::const_iterator cur = clip.begin();
+ Region::const_iterator end = clip.end();
+
+ const size_t bpp = pixelFormatTable[src->format].size;
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+ uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
+
+ while (cur != end) {
+ const Rect& r(*cur++);
+ ssize_t w = r.right - r.left;
+ ssize_t h = r.bottom - r.top;
+ if (w <= 0 || h<=0) continue;
+ size_t size = w * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+}
+
+EGLBoolean egl_window_surface_v2_t::swapBuffers()
+{
+ if (!buffer) {
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+
+ /*
+ * Handle eglSetSwapRectangleANDROID()
+ * We copyback from the front buffer
+ */
+ if (!dirtyRegion.isEmpty()) {
+ dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
+ if (previousBuffer) {
+ const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ if (!copyBack.isEmpty()) {
+ void* prevBits;
+ if (lock(previousBuffer,
+ GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
+ // copy from previousBuffer to buffer
+ copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
+ unlock(previousBuffer);
+ }
+ }
+ }
+ oldDirtyRegion = dirtyRegion;
+ }
+
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+
+ unlock(buffer);
+ previousBuffer = buffer;
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ buffer = 0;
+
+ // dequeue a new buffer
+ nativeWindow->dequeueBuffer(nativeWindow, &buffer);
+
+ // TODO: lockBuffer should rather be executed when the very first
+ // direct rendering occurs.
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+
+ // reallocate the depth-buffer if needed
+ if ((width != buffer->width) || (height != buffer->height)) {
// TODO: we probably should reset the swap rect here
// if the window size has changed
+ width = buffer->width;
+ height = buffer->height;
if (depth.data) {
free(depth.data);
- depth.width = nativeWindow->width;
- depth.height = nativeWindow->height;
- depth.stride = nativeWindow->stride;
+ depth.width = width;
+ depth.height = height;
+ depth.stride = buffer->stride;
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ setError(EGL_BAD_ALLOC, EGL_FALSE);
return EGL_FALSE;
}
}
}
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // finally pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ dirtyRegion = Rect(l, t, l+w, t+h);
+ return EGL_TRUE;
+}
+
+EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
+{
+ return buffer;
+}
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+static bool supportedCopybitsDestinationFormat(int format) {
+ // Hardware supported
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+ }
+ return false;
+}
+#endif
+
+EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits;
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ gl->copybits.drawSurfaceBuffer = 0;
+ if (gl->copybits.blitEngine != NULL) {
+ if (supportedCopybitsDestinationFormat(buffer.format)) {
+ buffer_handle_t handle = this->buffer->handle;
+ if (handle != NULL) {
+ gl->copybits.drawSurfaceBuffer = handle;
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.readBuffer(gl, &buffer);
return EGL_TRUE;
}
-void* egl_window_surface_t::getBits() const {
- return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
-}
-EGLint egl_window_surface_t::getHorizontalResolution() const {
+EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getVerticalResolution() const {
+EGLint egl_window_surface_v2_t::getVerticalResolution() const {
return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getRefreshRate() const {
- return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+EGLint egl_window_surface_v2_t::getRefreshRate() const {
+ return (60 * EGL_DISPLAY_SCALING); // FIXME
}
-EGLint egl_window_surface_t::getSwapBehavior() const {
- uint32_t flags = nativeWindow->flags;
- if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
- return EGL_BUFFER_DESTROYED;
- return EGL_BUFFER_PRESERVED;
+EGLint egl_window_surface_v2_t::getSwapBehavior() const
+{
+ /*
+ * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
+ * the content of the swapped buffer.
+ *
+ * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
+ *
+ * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
+ * only applies to the area specified by eglSetSwapRectangleANDROID(), that
+ * is, everything outside of this area is preserved.
+ *
+ * This implementation of EGL assumes the later case.
+ *
+ */
+
+ return EGL_BUFFER_DESTROYED;
}
// ----------------------------------------------------------------------------
@@ -311,12 +704,11 @@
virtual ~egl_pixmap_surface_t() { }
- virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return nativePixmap.width; }
virtual EGLint getHeight() const { return nativePixmap.height; }
- virtual void* getBits() const { return nativePixmap.data; }
private:
egl_native_pixmap_t nativePixmap;
};
@@ -347,7 +739,7 @@
buffer.stride = nativePixmap.stride;
buffer.data = nativePixmap.data;
buffer.format = nativePixmap.format;
-
+
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
@@ -376,12 +768,11 @@
virtual ~egl_pbuffer_surface_t();
- virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual bool isValid() 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; }
virtual EGLint getHeight() const { return pbuffer.height; }
- virtual void* getBits() const { return pbuffer.data; }
private:
GGLSurface pbuffer;
};
@@ -407,7 +798,7 @@
pbuffer.stride = w;
pbuffer.data = (GGLubyte*)malloc(size);
pbuffer.format = f;
-
+
if (depthFormat) {
depth.width = pbuffer.width;
depth.height = pbuffer.height;
@@ -468,7 +859,13 @@
static char const * const gVendorString = "Google Inc.";
static char const * const gVersionString = "1.2 Android Driver";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionsString = "";
+static char const * const gExtensionsString =
+ "EGL_KHR_image_base "
+ // "KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
// ----------------------------------------------------------------------------
@@ -496,6 +893,10 @@
(__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
{ "glQueryMatrixxOES",
(__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+ { "glEGLImageTargetTexture2DOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
+ { "glEGLImageTargetRenderbufferStorageOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
{ "glClipPlanef",
(__eglMustCastToProperFunctionPointerType)&glClipPlanef },
{ "glClipPlanex",
@@ -510,9 +911,17 @@
(__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
{ "glGenBuffers",
(__eglMustCastToProperFunctionPointerType)&glGenBuffers },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
-/*
+/*
* In the lists below, attributes names MUST be sorted.
* Additionally, all configs must be sorted according to
* the EGL specification.
@@ -523,7 +932,7 @@
{ EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
{ EGL_LEVEL, 0 },
{ EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_PIXELS,
+ { EGL_MAX_PBUFFER_PIXELS,
GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
{ EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
{ EGL_NATIVE_RENDERABLE, EGL_TRUE },
@@ -660,9 +1069,9 @@
{
while (first <= last) {
int mid = (first + last) / 2;
- if (key > sortedArray[mid].key) {
+ if (key > sortedArray[mid].key) {
first = mid + 1;
- } else if (key < sortedArray[mid].key) {
+ } else if (key < sortedArray[mid].key) {
last = mid - 1;
} else {
return mid;
@@ -674,13 +1083,13 @@
static int isAttributeMatching(int i, EGLint attr, EGLint val)
{
// look for the attribute in all of our configs
- config_pair_t const* configFound = gConfigs[i].array;
+ config_pair_t const* configFound = gConfigs[i].array;
int index = binarySearch<config_pair_t>(
gConfigs[i].array,
0, gConfigs[i].size-1,
attr);
if (index < 0) {
- configFound = config_base_attribute_list;
+ configFound = config_base_attribute_list;
index = binarySearch<config_pair_t>(
config_base_attribute_list,
0, NELEM(config_base_attribute_list)-1,
@@ -794,28 +1203,28 @@
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -828,9 +1237,9 @@
//if (EGLint(info.format) != pixelFormat)
// return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- egl_surface_t* surface =
- new egl_window_surface_t(dpy, config, depthFormat,
- static_cast<egl_native_window_t*>(window));
+ egl_surface_t* surface;
+ surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
+ static_cast<android_native_window_t*>(window));
if (!surface->isValid()) {
// there was a problem in the ctor, the error
@@ -863,28 +1272,28 @@
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -916,10 +1325,10 @@
EGLint surfaceType;
if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
return EGL_FALSE;
-
+
if (!(surfaceType & EGL_PBUFFER_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -927,28 +1336,28 @@
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -1001,7 +1410,7 @@
egl_display_t& d = egl_display_t::get_display(dpy);
d.type = display;
return dpy;
- }
+ }
return EGL_NO_DISPLAY;
}
@@ -1009,10 +1418,10 @@
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
EGLBoolean res = EGL_TRUE;
egl_display_t& d = egl_display_t::get_display(dpy);
-
+
if (android_atomic_inc(&d.initialized) == 0) {
// initialize stuff here if needed
//pthread_mutex_lock(&gInitMutex);
@@ -1080,7 +1489,7 @@
*num_config = 0;
return EGL_TRUE;
}
-
+
int numAttributes = 0;
int numConfigs = NELEM(gConfigs);
uint32_t possibleMatch = (1<<numConfigs)-1;
@@ -1161,7 +1570,7 @@
{
return createWindowSurface(dpy, config, window, attrib_list);
}
-
+
EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
NativePixmapType pixmap,
const EGLint *attrib_list)
@@ -1174,7 +1583,7 @@
{
return createPbufferSurface(dpy, config, attrib_list);
}
-
+
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
@@ -1185,6 +1594,11 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (surface->ctx) {
+ // FIXME: this surface is current check what the spec says
+ surface->disconnect();
+ surface->ctx = 0;
+ }
delete surface;
}
return EGL_TRUE;
@@ -1244,7 +1658,7 @@
*value = (wr * EGL_DISPLAY_SCALING) / hr;
} break;
case EGL_SWAP_BEHAVIOR:
- *value = surface->getSwapBehavior();
+ *value = surface->getSwapBehavior();
break;
default:
ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
@@ -1294,7 +1708,7 @@
}
EGLContext current_ctx = EGL_NO_CONTEXT;
-
+
if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
return setError(EGL_BAD_MATCH, EGL_FALSE);
@@ -1310,21 +1724,28 @@
egl_surface_t* r = (egl_surface_t*)read;
if ((d && d->ctx && d->ctx != ctx) ||
(r && r->ctx && r->ctx != ctx)) {
- // once of the surface is bound to a context in another thread
+ // one of the surface is bound to a context in another thread
return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
}
- // TODO: call connect / disconnect on the surface
-
ogles_context_t* gl = (ogles_context_t*)ctx;
if (makeCurrent(gl) == 0) {
if (ctx) {
egl_context_t* c = egl_context_t::context(ctx);
egl_surface_t* d = (egl_surface_t*)draw;
egl_surface_t* r = (egl_surface_t*)read;
- c->read = read;
+
+ if (c->draw) {
+ reinterpret_cast<egl_surface_t*>(c->draw)->disconnect();
+ }
+ if (c->read) {
+ // FIXME: unlock/disconnect the read surface too
+ }
+
c->draw = draw;
+ c->read = read;
+
if (c->flags & egl_context_t::NEVER_CURRENT) {
c->flags &= ~egl_context_t::NEVER_CURRENT;
GLint w = 0;
@@ -1338,10 +1759,14 @@
ogles_scissor(gl, 0, 0, w, h);
}
if (d) {
+ if (d->connect() == EGL_FALSE) {
+ return EGL_FALSE;
+ }
d->ctx = ctx;
d->bindDrawSurface(gl);
}
if (r) {
+ // FIXME: lock/connect the read surface too
r->ctx = ctx;
r->bindReadSurface(gl);
}
@@ -1352,8 +1777,16 @@
egl_context_t* c = egl_context_t::context(current_ctx);
egl_surface_t* d = (egl_surface_t*)c->draw;
egl_surface_t* r = (egl_surface_t*)c->read;
- if (d) d->ctx = EGL_NO_CONTEXT;
- if (r) r->ctx = EGL_NO_CONTEXT;
+ if (d) {
+ c->draw = 0;
+ d->ctx = EGL_NO_CONTEXT;
+ d->disconnect();
+ }
+ if (r) {
+ c->read = 0;
+ r->ctx = EGL_NO_CONTEXT;
+ // FIXME: unlock/disconnect the read surface too
+ }
}
}
return EGL_TRUE;
@@ -1425,7 +1858,7 @@
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1558,7 +1991,7 @@
}
// ----------------------------------------------------------------------------
-// Android extensions
+// EGL_EGLEXT_VERSION 3
// ----------------------------------------------------------------------------
void (*eglGetProcAddress (const char *procname))()
@@ -1571,3 +2004,93 @@
}
return NULL;
}
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ if (ctx != EGL_NO_CONTEXT) {
+ return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ }
+ if (target != EGL_NATIVE_BUFFER_ANDROID) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ native_buffer->common.incRef(&native_buffer->common);
+ return (EGLImageKHR)native_buffer;
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ native_buffer->common.decRef(&native_buffer->common);
+
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // post the surface
+ d->setSwapRectangle(left, top, width, height);
+
+ return EGL_TRUE;
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ // post the surface
+ return d->getRenderBuffer();
+}
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index f164c02..769ec40 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -369,7 +369,7 @@
int32_t c0, int32_t c1, int32_t c2) const
{
int64_t it64[3];
- iterators0032(it, c0, c1, c2);
+ iterators0032(it64, c0, c1, c2);
it[0] = it64[0];
it[1] = it64[1];
it[2] = it64[2];
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 5cbabea..a59b3b0 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -28,12 +28,16 @@
#include "BufferObjectManager.h"
#include "TextureObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include <hardware/copybit.h>
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
static char const * const gVendorString = "Android";
-static char const * const gRendererString = "Android PixelFlinger 1.0";
+static char const * const gRendererString = "Android PixelFlinger 1.1";
static char const * const gVersionString = "OpenGL ES-CM 1.0";
static char const * const gExtensionsString =
"GL_OES_byte_coordinates " // OK
@@ -46,9 +50,9 @@
"GL_OES_query_matrix " // OK
// "GL_OES_point_size_array " // TODO
// "GL_OES_point_sprite " // TODO
+ "GL_OES_EGL_image " // OK
"GL_ARB_texture_compression " // OK
"GL_ARB_texture_non_power_of_two " // OK
- "GL_ANDROID_direct_texture " // OK
"GL_ANDROID_user_clip_plane " // OK
"GL_ANDROID_vertex_buffer_object " // OK
"GL_ANDROID_generate_mipmap " // OK
@@ -62,13 +66,13 @@
ogles_context_t *ogles_init(size_t extra)
{
void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
- if (!base) return 0;
+ if (!base) return 0;
ogles_context_t *c =
(ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
memset(c, 0, sizeof(ogles_context_t));
ggl_init_context(&(c->rasterizer));
-
+
// XXX: this should be passed as an argument
sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
c->surfaceManager = smgr.get();
@@ -87,13 +91,42 @@
c->rasterizer.base = base;
c->point.size = TRI_ONE;
c->line.width = TRI_ONE;
-
+
// in OpenGL, writing to the depth buffer is enabled by default.
c->rasterizer.procs.depthMask(c, 1);
-
+
// OpenGL enables dithering by default
c->rasterizer.procs.enable(c, GL_DITHER);
+ c->copybits.blitEngine = NULL;
+ c->copybits.minScale = 0;
+ c->copybits.maxScale = 0;
+ c->copybits.drawSurfaceBuffer = 0;
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ hw_module_t const* module;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ struct copybit_device_t* copyBits;
+ if (copybit_open(module, ©Bits) == 0) {
+ c->copybits.blitEngine = copyBits;
+ {
+ int minLim = copyBits->get(copyBits,
+ COPYBIT_MINIFICATION_LIMIT);
+ if (minLim != -EINVAL && minLim > 0) {
+ c->copybits.minScale = (1 << 16) / minLim;
+ }
+ }
+ {
+ int magLim = copyBits->get(copyBits,
+ COPYBIT_MAGNIFICATION_LIMIT);
+ if (magLim != -EINVAL && magLim > 0) {
+ c->copybits.maxScale = min(32*1024-1, magLim) << 16;
+ }
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return c;
}
@@ -107,7 +140,12 @@
c->surfaceManager->decStrong(c);
c->bufferObjectManager->decStrong(c);
ggl_uninit_context(&(c->rasterizer));
- free(c->rasterizer.base);
+ free(c->rasterizer.base);
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (c->copybits.blitEngine != NULL) {
+ copybit_close((struct copybit_device_t*) c->copybits.blitEngine);
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
}
void _ogles_error(ogles_context_t* c, GLenum error)
@@ -188,7 +226,7 @@
// these need to fall through into the rasterizer
c->rasterizer.procs.enableDisable(c, cap, enabled);
break;
-
+
case GL_MULTISAMPLE:
case GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL_SAMPLE_ALPHA_TO_ONE:
@@ -281,7 +319,7 @@
case GL_LINE_SMOOTH_HINT:
break;
case GL_POINT_SMOOTH_HINT:
- c->rasterizer.procs.enableDisable(c,
+ c->rasterizer.procs.enableDisable(c,
GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
break;
case GL_PERSPECTIVE_CORRECTION_HINT:
@@ -323,7 +361,7 @@
c->error = 0;
return ret;
}
-
+
if (c->rasterizer.error) {
const GLenum ret(c->rasterizer.error);
c->rasterizer.error = 0;
@@ -362,25 +400,25 @@
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].ah - formats[index].al;
- break;
+ break;
}
case GL_RED_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].rh - formats[index].rl;
- break;
+ break;
}
case GL_GREEN_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].gh - formats[index].gl;
- break;
+ break;
}
case GL_BLUE_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].bh - formats[index].bl;
- break;
+ break;
}
case GL_COMPRESSED_TEXTURE_FORMATS:
params[ 0] = GL_PALETTE4_RGB8_OES;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 14a910c..4d3c2f4 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -23,6 +23,12 @@
#include "texture.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
@@ -48,7 +54,7 @@
// each context has a default named (0) texture (not shared)
c->textures.defaultTexture = new EGLTextureObject();
c->textures.defaultTexture->incStrong(c);
-
+
// bind the default texture to each texture unit
for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
bindTextureTmu(c, i, 0, c->textures.defaultTexture);
@@ -96,7 +102,7 @@
}
}
-void ogles_validate_texture_impl(ogles_context_t* c)
+void ogles_validate_texture(ogles_context_t* c)
{
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable)
@@ -110,6 +116,66 @@
c->textures.tmu[tmu].dirty = flags;
}
+/*
+ * If the active textures are EGLImage, they need to be locked before
+ * they can be used.
+ *
+ * FIXME: code below is far from being optimal
+ *
+ */
+
+void ogles_lock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ void* vaddr;
+ int err = module->lock(module, native_buffer->handle,
+ GRALLOC_USAGE_SW_READ_OFTEN,
+ 0, 0, native_buffer->width, native_buffer->height,
+ &vaddr);
+
+ u.texture->setImageBits(vaddr);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+}
+
+void ogles_unlock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ module->unlock(module, native_buffer->handle);
+ u.texture->setImageBits(NULL);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
@@ -255,7 +321,7 @@
u.texture->decStrong(c);
if (name == 0) {
- // 0 is our local texture object, not shared with anyone.
+ // 0 is our local texture object, not shared with anyone.
// But it affects all bound TMUs immediately.
// (we need to invalidate all units bound to this texture object)
tex = c->textures.defaultTexture;
@@ -273,7 +339,7 @@
u.texture = tex.get();
u.texture->incStrong(c);
u.name = name;
- invalidate_texture(c, active);
+ invalidate_texture(c, active);
return tex;
}
@@ -282,7 +348,7 @@
{
if (tex.get() == c->textures.tmu[tmu].texture)
return;
-
+
// free the reference to the previously bound object
texture_unit_t& u(c->textures.tmu[tmu]);
if (u.texture)
@@ -310,7 +376,7 @@
if (formatIdx == 0) { // we don't know what to do with this
return GL_INVALID_OPERATION;
}
-
+
// figure out the size we need as well as the stride
const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
const int32_t align = c->textures.unpackAlignment-1;
@@ -530,8 +596,8 @@
ogles_error(c, GL_INVALID_ENUM);
return;
}
-
- EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
switch (pname) {
case GL_TEXTURE_WRAP_S:
if ((param == GL_REPEAT) ||
@@ -581,13 +647,12 @@
}
-static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+
+static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
ogles_context_t* c)
{
- // quickly reject empty rects
- if ((w|h) <= 0)
- return;
-
+ ogles_lock_textures(c);
+
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = gglIntToFixed(cbSurface.height) - (y + h);
w >>= FIXED_BITS;
@@ -610,7 +675,7 @@
GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
u.dirty = 0xFF; // XXX: should be more subtle
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Ucr = textureObject->crop_rect[0] << 16;
const GLint Vcr = textureObject->crop_rect[1] << 16;
const GLint Wcr = textureObject->crop_rect[2] << 16;
@@ -641,11 +706,30 @@
c->rasterizer.procs.disable(c, GGL_W_LERP);
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
- c->rasterizer.procs.recti(c,
+ c->rasterizer.procs.recti(c,
gglFixedToIntRound(x),
gglFixedToIntRound(y),
gglFixedToIntRound(x)+w,
gglFixedToIntRound(y)+h);
+
+ ogles_unlock_textures(c);
+}
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+ ogles_context_t* c)
+{
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
+ gglFixedToIntRound(y), gglFixedToIntRound(z),
+ gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
+ return;
+ }
+#else
+ // quickly reject empty rects
+ if ((w|h) <= 0)
+ return;
+#endif
+ drawTexxOESImp(x, y, z, w, h, c);
}
static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
@@ -656,14 +740,21 @@
// which is a lot faster.
if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
+ return;
+ }
+#endif
const int tmu = 0;
texture_unit_t& u(c->textures.tmu[tmu]);
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Wcr = textureObject->crop_rect[2];
const GLint Hcr = textureObject->crop_rect[3];
if ((w == Wcr) && (h == -Hcr)) {
+#ifndef LIBAGL_USE_GRALLOC_COPYBITS
if ((w|h) <= 0) return; // quickly reject empty rects
+#endif
if (u.dirty) {
c->rasterizer.procs.activeTexture(c, tmu);
@@ -679,14 +770,14 @@
GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
u.dirty = 0xFF; // XXX: should be more subtle
c->rasterizer.procs.activeTexture(c, c->textures.active);
-
+
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = cbSurface.height - (y + h);
const GLint Ucr = textureObject->crop_rect[0];
const GLint Vcr = textureObject->crop_rect[1];
const GLint s0 = Ucr - x;
const GLint t0 = (Vcr + Hcr) - y;
-
+
const GLuint tw = textureObject->surface.width;
const GLuint th = textureObject->surface.height;
if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
@@ -694,7 +785,9 @@
// in this case, so we just use the slow case, which
// at least won't crash
goto slow_case;
- }
+ }
+
+ ogles_lock_textures(c);
c->rasterizer.procs.texCoord2i(c, s0, t0);
const uint32_t enables = c->rasterizer.state.enables;
@@ -706,12 +799,15 @@
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+
+ ogles_unlock_textures(c);
+
return;
}
}
slow_case:
- drawTexxOES(
+ drawTexxOESImp(
gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
gglIntToFixed(w), gglIntToFixed(h),
c);
@@ -749,7 +845,7 @@
}
// Bind or create a texture
- sp<EGLTextureObject> tex;
+ sp<EGLTextureObject> tex;
if (texture == 0) {
// 0 is our local texture object
tex = c->textures.defaultTexture;
@@ -837,7 +933,7 @@
if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
ogles_error(c, GL_INVALID_ENUM);
return;
- }
+ }
if ((param<=0 || param>8) || (param & (param-1))) {
ogles_error(c, GL_INVALID_VALUE);
return;
@@ -952,7 +1048,7 @@
}
// "uncompress" the texture since pixelflinger doesn't support
- // any compressed texture format natively.
+ // any compressed texture format natively.
GLenum format;
GLenum type;
switch (internalformat) {
@@ -1016,7 +1112,7 @@
GLenum format, GLenum type, const GLvoid *pixels)
{
ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ if (target != GL_TEXTURE_2D) {
ogles_error(c, GL_INVALID_ENUM);
return;
}
@@ -1024,7 +1120,7 @@
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (format != internalformat) {
+ if (format != (GLenum)internalformat) {
ogles_error(c, GL_INVALID_OPERATION);
return;
}
@@ -1034,16 +1130,10 @@
int32_t size = 0;
GGLSurface* surface = 0;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
- } else if (pixels == 0 || level != 0) {
- // pixel can't be null for direct texture
- ogles_error(c, GL_INVALID_OPERATION);
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
return;
}
@@ -1064,18 +1154,12 @@
userSurface.compressedFormat = 0;
userSurface.data = (GLubyte*)pixels;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
- generateMipmap(c, level);
- } else {
- // bind it to the texture unit
- sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
- tex->setSurface(&userSurface);
+ int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
}
+ generateMipmap(c, level);
}
}
@@ -1150,7 +1234,7 @@
int err = copyPixels(c,
surface, xoffset, yoffset,
- userSurface, 0, 0, width, height);
+ userSurface, 0, 0, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1203,7 +1287,7 @@
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE:
type = GL_UNSIGNED_BYTE;
- break;
+ break;
}
// figure out the format to use for the new texture
@@ -1213,7 +1297,7 @@
case GGL_PIXEL_FORMAT_RGBA_5551:
case GGL_PIXEL_FORMAT_RGBA_4444:
format = internalformat;
- break;
+ break;
case GGL_PIXEL_FORMAT_RGBX_8888:
case GGL_PIXEL_FORMAT_RGB_888:
case GGL_PIXEL_FORMAT_RGB_565:
@@ -1222,7 +1306,7 @@
case GL_LUMINANCE:
case GL_RGB:
format = internalformat;
- break;
+ break;
}
break;
}
@@ -1242,7 +1326,7 @@
ogles_error(c, error);
return;
}
-
+
// The bottom row is stored first in textures
GGLSurface txSurface(*surface);
txSurface.stride = -txSurface.stride;
@@ -1252,7 +1336,7 @@
int err = copyPixels(c,
txSurface, 0, 0,
- cbSurface, x, y, cbSurface.width, cbSurface.height);
+ cbSurface, x, y, cbSurface.width, cbSurface.height);
if (err) {
ogles_error(c, err);
}
@@ -1302,7 +1386,7 @@
int err = copyPixels(c,
surface, xoffset, yoffset,
- cbSurface, x, y, width, height);
+ cbSurface, x, y, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1372,7 +1456,7 @@
return;
}
- ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
+ ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
ggl->bindTexture(ggl, &readSurface); // source is read-buffer
ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
ggl->recti(ggl, 0, 0, width, height);
@@ -1426,3 +1510,43 @@
ogles_context_t* c = ogles_context_t::get();
drawTexxOES(x, y, z, w, h, c);
}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark EGL Image Extension
+#endif
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // bind it to the texture unit
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ tex->setImage(native_buffer);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ tex->try_copybit = false;
+ if (c->copybits.blitEngine != NULL) {
+ tex->try_copybit = true;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
index 5c57948..98f7550 100644
--- a/opengl/libagl/texture.h
+++ b/opengl/libagl/texture.h
@@ -32,13 +32,9 @@
void ogles_init_texture(ogles_context_t* c);
void ogles_uninit_texture(ogles_context_t* c);
-void ogles_validate_texture_impl(ogles_context_t* c);
-
-inline void ogles_validate_texture(ogles_context_t* c) {
- if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
- ogles_validate_texture_impl(c);
-}
-
+void ogles_validate_texture(ogles_context_t* c);
+void ogles_lock_textures(ogles_context_t* c);
+void ogles_unlock_textures(ogles_context_t* c);
}; // namespace android
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 23304d5..e1fd48b 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -1,17 +1,18 @@
LOCAL_PATH:= $(call my-dir)
-#
+###############################################################################
# Build META EGL library
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- EGL/egl.cpp \
- EGL/gpu.cpp \
+ EGL/egl.cpp \
+ EGL/hooks.cpp \
+ EGL/Loader.cpp \
#
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_SHARED_LIBRARIES += libcutils libutils
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
@@ -19,24 +20,42 @@
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
+installed_libEGL := $(LOCAL_INSTALLED_MODULE)
+# OpenGL drivers config file
+ifneq ($(BOARD_EGL_CFG),)
-#
-# Build the wrapper OpenGL ES library
+include $(CLEAR_VARS)
+LOCAL_MODULE := egl.cfg
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
+LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
+include $(BUILD_PREBUILT)
+
+# make sure we depend on egl.cfg, so it gets installed
+$(installed_libEGL): | egl.cfg
+
+endif
+
+###############################################################################
+# Build the wrapper OpenGL ES 1.x library
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- GLES_CM/gl.cpp.arm \
+LOCAL_SRC_FILES:= \
+ GLES_CM/gl.cpp.arm \
#
LOCAL_SHARED_LIBRARIES += libcutils libEGL
@@ -47,10 +66,41 @@
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+###############################################################################
+# Build the wrapper OpenGL ES 2.x library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ GLES2/gl2.cpp.arm \
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libEGL
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLESv2
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
new file mode 100644
index 0000000..445e681
--- /dev/null
+++ b/opengl/libs/EGL/Loader.cpp
@@ -0,0 +1,276 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+#include "Loader.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * EGL drivers are called
+ *
+ * /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so
+ *
+ */
+
+ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+
+// ----------------------------------------------------------------------------
+
+Loader::driver_t::driver_t(void* gles)
+{
+ dso[0] = gles;
+ for (size_t i=1 ; i<NELEM(dso) ; i++)
+ dso[i] = 0;
+}
+
+Loader::driver_t::~driver_t()
+{
+ for (size_t i=0 ; i<NELEM(dso) ; i++) {
+ if (dso[i]) {
+ dlclose(dso[i]);
+ dso[i] = 0;
+ }
+ }
+}
+
+status_t Loader::driver_t::set(void* hnd, int32_t api)
+{
+ switch (api) {
+ case EGL:
+ dso[0] = hnd;
+ break;
+ case GLESv1_CM:
+ dso[1] = hnd;
+ break;
+ case GLESv2:
+ dso[2] = hnd;
+ break;
+ default:
+ return BAD_INDEX;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
+ : dpy(dpy), impl(impl), tag(tag) {
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::Loader()
+{
+ char line[256];
+ char tag[256];
+ FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
+ if (cfg == NULL) {
+ // default config
+ LOGD("egl.cfg not found, using default config");
+ gConfig.add( entry_t(0, 0, "android") );
+ } else {
+ while (fgets(line, 256, cfg)) {
+ int dpy;
+ int impl;
+ if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
+ //LOGD(">>> %u %u %s", dpy, impl, tag);
+ gConfig.add( entry_t(dpy, impl, tag) );
+ }
+ }
+ fclose(cfg);
+ }
+}
+
+Loader::~Loader()
+{
+}
+
+const char* Loader::getTag(int dpy, int impl)
+{
+ const Vector<entry_t>& cfgs(gConfig);
+ const size_t c = cfgs.size();
+ for (size_t i=0 ; i<c ; i++) {
+ if (dpy == cfgs[i].dpy)
+ if (impl == cfgs[i].impl)
+ return cfgs[i].tag.string();
+ }
+ return 0;
+}
+
+void* Loader::open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks)
+{
+ /*
+ * TODO: if we don't find display/0, then use 0/0
+ * (0/0 should always work)
+ */
+
+ void* dso;
+ char path[PATH_MAX];
+ int index = int(display);
+ driver_t* hnd = 0;
+ const char* const format = "/system/lib/egl/lib%s_%s.so";
+
+ char const* tag = getTag(index, impl);
+ if (tag) {
+ snprintf(path, PATH_MAX, format, "GLES", tag);
+ dso = load_driver(path, hooks, EGL | GLESv1_CM | GLESv2);
+ if (dso) {
+ hnd = new driver_t(dso);
+ } else {
+ // Always load EGL first
+ snprintf(path, PATH_MAX, format, "EGL", tag);
+ dso = load_driver(path, hooks, EGL);
+ if (dso) {
+ hnd = new driver_t(dso);
+
+ // TODO: make this more automated
+ snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
+ hnd->set( load_driver(path, hooks, GLESv1_CM), GLESv1_CM );
+
+ snprintf(path, PATH_MAX, format, "GLESv2", tag);
+ hnd->set( load_driver(path, hooks, GLESv2), GLESv2 );
+ }
+ }
+ }
+
+ LOG_FATAL_IF(!index && !impl && !hnd,
+ "couldn't find the default OpenGL ES implementation "
+ "for default display");
+
+ return (void*)hnd;
+}
+
+status_t Loader::close(void* driver)
+{
+ driver_t* hnd = (driver_t*)driver;
+ delete hnd;
+ return NO_ERROR;
+}
+
+void Loader::init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress)
+{
+ char scrap[256];
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ }
+ if (f == NULL) {
+ // Try without the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ // Try with the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ strcat(scrap, "OES");
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ //LOGD("%s", name);
+ f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+ }
+ *curr++ = f;
+ api++;
+ }
+}
+
+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;
+
+ if (mask & EGL) {
+ getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+
+ LOGE_IF(!getProcAddress,
+ "can't find eglGetProcAddress() in %s", driver);
+
+ gl_hooks_t::egl_t* egl = &hooks->egl;
+ __eglMustCastToProperFunctionPointerType* curr =
+ (__eglMustCastToProperFunctionPointerType*)egl;
+ char const * const * api = egl_names;
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ if (f == NULL) {
+ f = (__eglMustCastToProperFunctionPointerType)0;
+ }
+ }
+ *curr++ = f;
+ api++;
+ }
+ }
+
+ if (mask & GLESv1_CM) {
+ init_api(dso, gl_names,
+ (__eglMustCastToProperFunctionPointerType*)&hooks->gl,
+ getProcAddress);
+ }
+
+ if (mask & GLESv2) {
+ init_api(dso, gl2_names,
+ (__eglMustCastToProperFunctionPointerType*)&hooks->gl2,
+ getProcAddress);
+ }
+
+ return dso;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
new file mode 100644
index 0000000..69f6dd5
--- /dev/null
+++ b/opengl/libs/EGL/Loader.h
@@ -0,0 +1,90 @@
+/*
+ ** Copyright 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 ANDROID_EGL_LOADER_H
+#define ANDROID_EGL_LOADER_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+class Loader : public Singleton<Loader>
+{
+ friend class Singleton<Loader>;
+
+ typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
+ const char*);
+
+ enum {
+ EGL = 0x01,
+ GLESv1_CM = 0x02,
+ GLESv2 = 0x04
+ };
+ struct driver_t {
+ driver_t(void* gles);
+ ~driver_t();
+ status_t set(void* hnd, int32_t api);
+ void* dso[3];
+ };
+
+ struct entry_t {
+ entry_t() { }
+ entry_t(int dpy, int impl, const char* tag);
+ int dpy;
+ int impl;
+ String8 tag;
+ };
+
+ Vector<entry_t> gConfig;
+ getProcAddressType getProcAddress;
+
+ const char* getTag(int dpy, int impl);
+
+public:
+ ~Loader();
+
+ void* open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks);
+ status_t close(void* driver);
+
+private:
+ Loader();
+ void *load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask);
+
+ static __attribute__((noinline))
+ void init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_LOADER_H */
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index c6e0f50..03e764c 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -14,9 +14,8 @@
** limitations under the License.
*/
-#define LOG_TAG "libEGL"
-
#include <ctype.h>
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
@@ -37,11 +36,9 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
-#include <utils/RefBase.h>
-
#include "hooks.h"
#include "egl_impl.h"
-
+#include "Loader.h"
#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -53,9 +50,18 @@
#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 = "";
+static char const * const gExtensionString =
+ "EGL_KHR_image "
+ "EGL_KHR_image_base "
+ "EGL_KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
+
+// ----------------------------------------------------------------------------
template <int MAGIC>
struct egl_object_t
@@ -87,21 +93,15 @@
struct egl_surface_t : public egl_object_t<'_srf'>
{
egl_surface_t(EGLDisplay dpy, EGLSurface surface,
- NativeWindowType window, int impl, egl_connection_t const* cnx)
- : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
+ int impl, egl_connection_t const* cnx)
+ : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
{
// NOTE: window must be incRef'ed and connected already
}
~egl_surface_t() {
- if (window) {
- if (window->disconnect)
- window->disconnect(window);
- window->decRef(window);
- }
}
EGLDisplay dpy;
EGLSurface surface;
- NativeWindowType window;
int impl;
egl_connection_t const* cnx;
};
@@ -121,39 +121,26 @@
egl_connection_t const* cnx;
};
+struct egl_image_t : public egl_object_t<'_img'>
+{
+ egl_image_t(EGLDisplay dpy, EGLContext context)
+ : dpy(dpy), context(context)
+ {
+ memset(images, 0, sizeof(images));
+ }
+ EGLDisplay dpy;
+ EGLConfig context;
+ EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+};
+
struct tls_t
{
- tls_t() : error(EGL_SUCCESS), ctx(0) { }
+ tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
EGLint error;
EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
};
-static void gl_unimplemented() {
- LOGE("called unimplemented OpenGL ES API");
-}
-
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-static char const * const gl_names[] = {
- #include "gl_entries.in"
- #include "glext_entries.in"
- NULL
-};
-
-static char const * const egl_names[] = {
- #include "egl_entries.in"
- NULL
-};
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
// ----------------------------------------------------------------------------
@@ -262,110 +249,8 @@
return tls->ctx;
}
-
/*****************************************************************************/
-class ISurfaceComposer;
-const sp<ISurfaceComposer>& getSurfaceFlinger();
-request_gpu_t* gpu_acquire(void* user);
-int gpu_release(void*, request_gpu_t* gpu);
-
-static __attribute__((noinline))
-void *load_driver(const char* driver, gl_hooks_t* hooks)
-{
- //LOGD("%s", driver);
- char scrap[256];
- void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
- LOGE_IF(!dso,
- "couldn't load <%s> library (%s)",
- driver, dlerror());
-
- if (dso) {
- // first find the symbol for eglGetProcAddress
-
- typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
- const char*);
-
- getProcAddressType getProcAddress =
- (getProcAddressType)dlsym(dso, "eglGetProcAddress");
-
- LOGE_IF(!getProcAddress,
- "can't find eglGetProcAddress() in %s", driver);
-
- __eglMustCastToProperFunctionPointerType* curr;
- char const * const * api;
-
- gl_hooks_t::egl_t* egl = &hooks->egl;
- curr = (__eglMustCastToProperFunctionPointerType*)egl;
- api = egl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- if (f == NULL) {
- f = (__eglMustCastToProperFunctionPointerType)0;
- }
- }
- *curr++ = f;
- api++;
- }
-
- gl_hooks_t::gl_t* gl = &hooks->gl;
- curr = (__eglMustCastToProperFunctionPointerType*)gl;
- api = gl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- }
- if (f == NULL) {
- // Try without the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- // Try with the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- strcat(scrap, "OES");
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- //LOGD("%s", name);
- f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
- }
- *curr++ = f;
- api++;
- }
-
- // hook this driver up with surfaceflinger if needed
- register_gpu_t register_gpu =
- (register_gpu_t)dlsym(dso, "oem_register_gpu");
-
- if (register_gpu != NULL) {
- if (getSurfaceFlinger() != 0) {
- register_gpu(dso, gpu_acquire, gpu_release);
- }
- }
- }
- return dso;
-}
-
template<typename T>
static __attribute__((noinline))
int binarySearch(
@@ -412,6 +297,18 @@
};
static const extention_map_t gExtentionMap[] = {
+ { "eglLockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
+ { "eglUnlockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -429,29 +326,15 @@
// ----------------------------------------------------------------------------
-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) {
+ tls->logCallWithNoContext = EGL_FALSE;
+ LOGE("call to OpenGL ES API with no current context "
+ "(logged once per thread)");
+ }
}
-static void gl_no_context() {
- LOGE("call to OpenGL ES API with no current context");
-}
static void early_egl_init(void)
{
#if !USE_FAST_TLS_KEY
@@ -491,6 +374,11 @@
return egl_to_native_cast<egl_context_t>(context);
}
+static inline
+egl_image_t* get_image(EGLImageKHR image) {
+ return egl_to_native_cast<egl_image_t>(image);
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp, int& impl, int& index)
@@ -540,82 +428,99 @@
}
-EGLDisplay egl_init_displays(NativeDisplayType display)
+EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
+{
+ 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())
+ 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];
+}
+
+// ----------------------------------------------------------------------------
+
+// this mutex protects:
+// d->dpys[]
+// 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;
- }
+ // get our driver loader
+ Loader& loader(Loader::getInstance());
- EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
- egl_display_t* d = &gDisplay[index];
+ // 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];
- // dynamically load all our EGL implementations for that display
- // and call into the real eglGetGisplay()
- egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+ cnx = &gEGLImpl[IMPL_SOFTWARE];
if (cnx->dso == 0) {
cnx->hooks = &gHooks[IMPL_SOFTWARE];
- cnx->dso = load_driver("libagl.so", 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->dpys[IMPL_SOFTWARE] = 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 = load_driver("libhgl.so", 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->dpys[IMPL_HARDWARE] = 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()));
- dlclose((void*)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
@@ -625,7 +530,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;
}
// ----------------------------------------------------------------------------
@@ -712,28 +627,25 @@
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;
-
+
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). */
-
+ // REVISIT: it's unclear what to do if eglTerminate() fails
free(dp->configs[i]);
free((void*)dp->queryString[i].extensions);
dp->numConfigs[i] = 0;
dp->dpys[i] = EGL_NO_DISPLAY;
- dlclose((void*)cnx->dso);
- cnx->dso = 0;
res = EGL_TRUE;
}
}
@@ -909,26 +821,12 @@
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- // window must be connected upon calling underlying
- // eglCreateWindowSurface
- if (window) {
- window->incRef(window);
- if (window->connect)
- window->connect(window);
- }
-
EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
dp->dpys[i], dp->configs[i][index], window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
-
- // something went wrong, disconnect and free window
- // (will disconnect() automatically)
- if (window) {
- window->decRef(window);
- }
}
return EGL_NO_SURFACE;
}
@@ -944,7 +842,7 @@
EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -961,7 +859,7 @@
EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
dp->dpys[i], dp->configs[i][index], attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -1097,12 +995,18 @@
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);
@@ -1118,6 +1022,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);
@@ -1129,6 +1036,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) {
@@ -1146,6 +1056,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) {
@@ -1182,9 +1095,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));
@@ -1350,6 +1265,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) {
@@ -1371,6 +1288,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++) {
@@ -1388,6 +1309,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) {
@@ -1430,3 +1355,154 @@
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ 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.eglLockSurfaceKHR) {
+ return s->cnx->hooks->egl.eglLockSurfaceKHR(
+ dp->dpys[s->impl], s->surface, attrib_list);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ 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.eglUnlockSurfaceKHR) {
+ return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
+ dp->dpys[s->impl], s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (ctx != EGL_NO_CONTEXT) {
+ 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);
+ if (image == EGL_NO_IMAGE_KHR)
+ return image;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ result->images[c->impl] = image;
+ return (EGLImageKHR)result;
+ } else {
+ // EGL_NO_CONTEXT is a valid parameter
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ // since we don't have a way to know which implementation to call,
+ // we're calling all of them
+
+ EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ implImages[i] = EGL_NO_IMAGE_KHR;
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglCreateImageKHR) {
+ implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
+ dp->dpys[i], ctx, target, buffer, attrib_list);
+ if (implImages[i] != EGL_NO_IMAGE_KHR) {
+ success = true;
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_NO_IMAGE_KHR;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ memcpy(result->images, implImages, sizeof(implImages));
+ return (EGLImageKHR)result;
+ }
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ 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);
+ }
+
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (image->images[i] != EGL_NO_IMAGE_KHR) {
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglCreateImageKHR) {
+ if (cnx->hooks->egl.eglDestroyImageKHR(
+ dp->dpys[i], image->images[i])) {
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_FALSE;
+
+ delete image;
+
+ return EGL_TRUE;
+}
+
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ 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 setError(EGL_BAD_DISPLAY, NULL);
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ 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 setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
+}
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
new file mode 100644
index 0000000..5d89287
--- /dev/null
+++ b/opengl/libs/EGL/egl_entries.in
@@ -0,0 +1,57 @@
+EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
+EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
+EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
+EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
+EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
+
+EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
+EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *)
+EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
+EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
+EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
+EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
+EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
+EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *)
+EGL_ENTRY(EGLBoolean, eglWaitGL, void)
+EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
+EGL_ENTRY(EGLint, eglGetError, void)
+EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
+EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
+
+/* EGL 1.1 */
+
+EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
+EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
+
+/* EGL 1.2 */
+
+EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
+EGL_ENTRY(EGLenum, eglQueryAPI, void)
+EGL_ENTRY(EGLBoolean, eglWaitClient, void)
+EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
+EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
+
+/* EGL 1.3 */
+
+/* EGL 1.4 */
+
+/* EGL_EGLEXT_VERSION 3 */
+
+EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+
+/* ANDROID extensions */
+
+EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
+EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
deleted file mode 100644
index 4c902c8..0000000
--- a/opengl/libs/EGL/gpu.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- ** 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.
- */
-
-#define LOG_TAG "EGL"
-
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
-
-#include <ui/EGLDisplaySurface.h>
-#include <ui/ISurfaceComposer.h>
-
-#include "hooks.h"
-#include "egl_impl.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-/*
- * we provide our own allocators for the GPU regions, these
- * allocators go through surfaceflinger
- */
-
-static Mutex gRegionsLock;
-static request_gpu_t gRegions;
-static sp<ISurfaceComposer> gSurfaceManager;
-GL_API ISurfaceComposer* GLES_localSurfaceManager = 0;
-
-extern egl_connection_t gEGLImpl[2];
-
-const sp<ISurfaceComposer>& getSurfaceFlinger()
-{
- Mutex::Autolock _l(gRegionsLock);
-
- /*
- * There is a little bit of voodoo magic here. We want to access
- * surfaceflinger for allocating GPU regions, however, when we are
- * running as part of surfaceflinger, we want to bypass the
- * service manager because surfaceflinger might not be registered yet.
- * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
- * own address, so we can just use that.
- */
- if (gSurfaceManager == 0) {
- if (GLES_localSurfaceManager) {
- // we're running in SurfaceFlinger's context
- gSurfaceManager = GLES_localSurfaceManager;
- } else {
- // we're a remote process or not part of surfaceflinger,
- // go through the service manager
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
- gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
- }
- }
- }
- return gSurfaceManager;
-}
-
-class GPURevokeRequester : public BnGPUCallback
-{
-public:
- virtual void gpuLost() {
- LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
- gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
- }
-};
-
-static sp<GPURevokeRequester> gRevokerCallback;
-
-
-request_gpu_t* gpu_acquire(void* user)
-{
- sp<ISurfaceComposer> server( getSurfaceFlinger() );
-
- Mutex::Autolock _l(gRegionsLock);
- if (server == NULL) {
- return 0;
- }
-
- ISurfaceComposer::gpu_info_t info;
-
- if (gRevokerCallback == 0)
- gRevokerCallback = new GPURevokeRequester();
-
- status_t err = server->requestGPU(gRevokerCallback, &info);
- if (err != NO_ERROR) {
- LOGD("requestGPU returned %d", err);
- return 0;
- }
-
- if (info.regs == 0) {
- LOGD("requestGPU() failed");
- return 0;
- }
-
- bool failed = false;
- request_gpu_t* gpu = &gRegions;
- memset(gpu, 0, sizeof(*gpu));
-
- if (info.regs != 0) {
- sp<IMemoryHeap> heap(info.regs->getMemory());
- if (heap != 0) {
- int fd = heap->heapID();
- gpu->regs.fd = fd;
- gpu->regs.base = info.regs->pointer();
- gpu->regs.size = info.regs->size();
- gpu->regs.user = info.regs.get();
-#if HAVE_ANDROID_OS
- struct pmem_region region;
- if (ioctl(fd, PMEM_GET_PHYS, ®ion) >= 0)
- gpu->regs.phys = (void*)region.offset;
-#endif
- info.regs->incStrong(gpu);
- } else {
- LOGE("GPU register handle %p is invalid!", info.regs.get());
- failed = true;
- }
- }
-
- for (size_t i=0 ; i<info.count && !failed ; i++) {
- sp<IMemory>& region(info.regions[i].region);
- if (region != 0) {
- sp<IMemoryHeap> heap(region->getMemory());
- if (heap != 0) {
- const int fd = heap->heapID();
- gpu->gpu[i].fd = fd;
- gpu->gpu[i].base = region->pointer();
- gpu->gpu[i].size = region->size();
- gpu->gpu[i].user = region.get();
- gpu->gpu[i].offset = info.regions[i].reserved;
-#if HAVE_ANDROID_OS
- struct pmem_region reg;
- if (ioctl(fd, PMEM_GET_PHYS, ®) >= 0)
- gpu->gpu[i].phys = (void*)reg.offset;
-#endif
- region->incStrong(gpu);
- } else {
- LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
- failed = true;
- }
- }
- }
-
- if (failed) {
- // something went wrong, clean up everything!
- if (gpu->regs.user) {
- static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
- for (size_t i=0 ; i<info.count ; i++) {
- if (gpu->gpu[i].user) {
- static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
- }
- }
- }
- }
-
- gpu->count = info.count;
- return gpu;
-}
-
-int gpu_release(void*, request_gpu_t* gpu)
-{
- sp<IMemory> regs;
-
- { // scope for lock
- Mutex::Autolock _l(gRegionsLock);
- regs = static_cast<IMemory*>(gpu->regs.user);
- gpu->regs.user = 0;
- if (regs != 0) regs->decStrong(gpu);
-
- for (int i=0 ; i<gpu->count ; i++) {
- sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
- gpu->gpu[i].user = 0;
- if (r != 0) r->decStrong(gpu);
- }
- }
-
- // there is a special transaction to relinquish the GPU
- // (it will happen automatically anyway if we don't do this)
- Parcel data, reply;
- // NOTE: this transaction does not require an interface token
- regs->asBinder()->transact(1000, data, &reply);
- return 1;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
new file mode 100644
index 0000000..2246366
--- /dev/null
+++ b/opengl/libs/EGL/hooks.cpp
@@ -0,0 +1,67 @@
+/*
+ ** Copyright 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+ #include "GLES_CM/gl_entries.in"
+ #include "GLES_CM/glext_entries.in"
+ NULL
+};
+
+char const * const gl2_names[] = {
+ #include "GLES2/gl2_entries.in"
+ #include "GLES2/gl2ext_entries.in"
+ NULL
+};
+
+char const * const egl_names[] = {
+ #include "egl_entries.in"
+ NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
new file mode 100644
index 0000000..e5358c3
--- /dev/null
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -0,0 +1,111 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Actual GL entry-points
+// ----------------------------------------------------------------------------
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+#if USE_FAST_TLS_KEY
+
+ #define API_ENTRY(_api) __attribute__((naked)) _api
+
+ #define CALL_GL_API(_api, ...) \
+ asm volatile( \
+ "mov r12, #0xFFFF0FFF \n" \
+ "ldr r12, [r12, #-15] \n" \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ "bx lr \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl2._api)) \
+ : \
+ );
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API(_api, __VA_ARGS__) \
+ return 0; // placate gcc's warnings. never reached.
+
+#else
+
+ #define API_ENTRY(_api) _api
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl2_t const * const _c = &getGlThreadSpecific()->gl2; \
+ _c->_api(__VA_ARGS__)
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl2_t const * const _c = &getGlThreadSpecific()->gl2; \
+ return _c->_api(__VA_ARGS__)
+
+#endif
+
+
+extern "C" {
+#include "gl2_api.in"
+#include "gl2ext_api.in"
+}
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+
+/*
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
+ */
+
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
+}
+
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
new file mode 100644
index 0000000..9c2e69a
--- /dev/null
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -0,0 +1,426 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+ CALL_GL_API(glActiveTexture, texture);
+}
+void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glAttachShader, program, shader);
+}
+void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const char* name) {
+ CALL_GL_API(glBindAttribLocation, program, index, name);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+ CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
+ CALL_GL_API(glBindFramebuffer, target, framebuffer);
+}
+void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
+ CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
+}
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+ CALL_GL_API(glBindTexture, target, texture);
+}
+void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glBlendColor, red, green, blue, alpha);
+}
+void API_ENTRY(glBlendEquation)( GLenum mode ) {
+ CALL_GL_API(glBlendEquation, mode);
+}
+void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
+ CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
+}
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+ CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
+ CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
+}
+void API_ENTRY(glClear)(GLbitfield mask) {
+ CALL_GL_API(glClear, mask);
+}
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+ CALL_GL_API(glClearDepthf, depth);
+}
+void API_ENTRY(glClearStencil)(GLint s) {
+ CALL_GL_API(glClearStencil, s);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glCompileShader)(GLuint shader) {
+ CALL_GL_API(glCompileShader, shader);
+}
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+ CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
+}
+void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
+}
+GLuint API_ENTRY(glCreateProgram)(void) {
+ CALL_GL_API_RETURN(glCreateProgram);
+}
+GLuint API_ENTRY(glCreateShader)(GLenum type) {
+ CALL_GL_API_RETURN(glCreateShader, type);
+}
+void API_ENTRY(glCullFace)(GLenum mode) {
+ CALL_GL_API(glCullFace, mode);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+ CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers) {
+ CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glDeleteProgram)(GLuint program) {
+ CALL_GL_API(glDeleteProgram, program);
+}
+void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers) {
+ CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glDeleteShader)(GLuint shader) {
+ CALL_GL_API(glDeleteShader, shader);
+}
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint* textures) {
+ CALL_GL_API(glDeleteTextures, n, textures);
+}
+void API_ENTRY(glDepthFunc)(GLenum func) {
+ CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+ CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+ CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glDetachShader, program, shader);
+}
+void API_ENTRY(glDisable)(GLenum cap) {
+ CALL_GL_API(glDisable, cap);
+}
+void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glDisableVertexAttribArray, index);
+}
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+ CALL_GL_API(glDrawArrays, mode, first, count);
+}
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+void API_ENTRY(glEnable)(GLenum cap) {
+ CALL_GL_API(glEnable, cap);
+}
+void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glEnableVertexAttribArray, index);
+}
+void API_ENTRY(glFinish)(void) {
+ CALL_GL_API(glFinish);
+}
+void API_ENTRY(glFlush)(void) {
+ CALL_GL_API(glFlush);
+}
+void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
+ CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
+ CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
+}
+void API_ENTRY(glFrontFace)(GLenum mode) {
+ CALL_GL_API(glFrontFace, mode);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+ CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGenerateMipmap)(GLenum target) {
+ CALL_GL_API(glGenerateMipmap, target);
+}
+void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers) {
+ CALL_GL_API(glGenFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) {
+ CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint* textures) {
+ CALL_GL_API(glGenTextures, n, textures);
+}
+void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
+}
+int API_ENTRY(glGetAttribLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetAttribLocation, program, name);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
+ CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+GLenum API_ENTRY(glGetError)(void) {
+ CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
+ CALL_GL_API(glGetIntegerv, pname, params);
+}
+void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetProgramiv, program, pname, params);
+}
+void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
+}
+void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetShaderiv, shader, pname, params);
+}
+void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
+}
+void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
+}
+void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
+}
+const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+ CALL_GL_API_RETURN(glGetString, name);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
+ CALL_GL_API(glGetUniformfv, program, location, params);
+}
+void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
+ CALL_GL_API(glGetUniformiv, program, location, params);
+}
+int API_ENTRY(glGetUniformLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetUniformLocation, program, name);
+}
+void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetVertexAttribfv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetVertexAttribiv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer) {
+ CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
+}
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+ CALL_GL_API(glHint, target, mode);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+ CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+ CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
+ CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
+}
+GLboolean API_ENTRY(glIsProgram)(GLuint program) {
+ CALL_GL_API_RETURN(glIsProgram, program);
+}
+GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
+ CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
+}
+GLboolean API_ENTRY(glIsShader)(GLuint shader) {
+ CALL_GL_API_RETURN(glIsShader, shader);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+ CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glLineWidth)(GLfloat width) {
+ CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glLinkProgram)(GLuint program) {
+ CALL_GL_API(glLinkProgram, program);
+}
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+ CALL_GL_API(glPixelStorei, pname, param);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+ CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
+ CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glReleaseShaderCompiler)(void) {
+ CALL_GL_API(glReleaseShaderCompiler);
+}
+void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+ CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glScissor, x, y, width, height);
+}
+void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) {
+ CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
+}
+void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length) {
+ CALL_GL_API(glShaderSource, shader, count, string, length);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask) {
+ CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
+ CALL_GL_API(glStencilMaskSeparate, face, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
+}
+void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
+ CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
+}
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexParameterf, target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
+ CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
+ CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
+ CALL_GL_API(glUniform1f, location, x);
+}
+void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform1fv, location, count, v);
+}
+void API_ENTRY(glUniform1i)(GLint location, GLint x) {
+ CALL_GL_API(glUniform1i, location, x);
+}
+void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform1iv, location, count, v);
+}
+void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
+ CALL_GL_API(glUniform2f, location, x, y);
+}
+void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform2fv, location, count, v);
+}
+void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
+ CALL_GL_API(glUniform2i, location, x, y);
+}
+void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform2iv, location, count, v);
+}
+void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glUniform3f, location, x, y, z);
+}
+void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform3fv, location, count, v);
+}
+void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
+ CALL_GL_API(glUniform3i, location, x, y, z);
+}
+void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform3iv, location, count, v);
+}
+void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glUniform4f, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform4fv, location, count, v);
+}
+void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
+ CALL_GL_API(glUniform4i, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform4iv, location, count, v);
+}
+void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
+}
+void API_ENTRY(glUseProgram)(GLuint program) {
+ CALL_GL_API(glUseProgram, program);
+}
+void API_ENTRY(glValidateProgram)(GLuint program) {
+ CALL_GL_API(glValidateProgram, program);
+}
+void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
+ CALL_GL_API(glVertexAttrib1f, indx, x);
+}
+void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib1fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
+ CALL_GL_API(glVertexAttrib2f, indx, x, y);
+}
+void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib2fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
+}
+void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib3fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
+}
+void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib4fv, indx, values);
+}
+void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) {
+ CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
+}
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glViewport, x, y, width, height);
+}
diff --git a/opengl/libs/GLES2/gl2_entries.in b/opengl/libs/GLES2/gl2_entries.in
new file mode 100644
index 0000000..6a41b94
--- /dev/null
+++ b/opengl/libs/GLES2/gl2_entries.in
@@ -0,0 +1,142 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const char* name)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glBlendEquation, GLenum mode )
+GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glCompileShader, GLuint shader)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(GLuint, glCreateProgram, void)
+GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint* buffers)
+GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteShader, GLuint shader)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint* textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint* buffers)
+GL_ENTRY(void, glGenerateMipmap, GLenum target)
+GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint* textures)
+GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+GL_ENTRY(int, glGetAttribLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean* params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+GL_ENTRY(const GLubyte*, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)
+GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params)
+GL_ENTRY(int, glGetUniformLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsShader, GLuint shader)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLinkProgram, GLuint program)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+GL_ENTRY(void, glReleaseShaderCompiler, void)
+GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const char** string, const GLint* length)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat* params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint* params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glUniform1f, GLint location, GLfloat x)
+GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform1i, GLint location, GLint x)
+GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
+GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
+GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
new file mode 100644
index 0000000..6eeecb3
--- /dev/null
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -0,0 +1,105 @@
+void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
+}
+void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
+}
+void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) {
+ CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary);
+}
+void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) {
+ CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length);
+}
+void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {
+ CALL_GL_API_RETURN(glMapBufferOES, target, access);
+}
+GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {
+ CALL_GL_API_RETURN(glUnmapBufferOES, target);
+}
+void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) {
+ CALL_GL_API(glGetBufferPointervOES, target, pname, params);
+}
+void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels);
+}
+void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+}
+void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height);
+}
+void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+}
+void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {
+ CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset);
+}
+void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) {
+ CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups);
+}
+void API_ENTRY(glGetPerfMonitorCountersAMD)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) {
+ CALL_GL_API(glGetPerfMonitorCountersAMD, group, numCounters, maxActiveCounters, counterSize, counters);
+}
+void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, char *groupString) {
+ CALL_GL_API(glGetPerfMonitorGroupStringAMD, group, bufSize, length, groupString);
+}
+void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString) {
+ CALL_GL_API(glGetPerfMonitorCounterStringAMD, group, counter, bufSize, length, counterString);
+}
+void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, void *data) {
+ CALL_GL_API(glGetPerfMonitorCounterInfoAMD, group, counter, pname, data);
+}
+void API_ENTRY(glGenPerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glGenPerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glDeletePerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glDeletePerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glSelectPerfMonitorCountersAMD)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList) {
+ CALL_GL_API(glSelectPerfMonitorCountersAMD, monitor, enable, group, numCounters, countersList);
+}
+void API_ENTRY(glBeginPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glBeginPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glEndPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glEndPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {
+ CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);
+}
+void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
+ CALL_GL_API(glDeleteFencesNV, n, fences);
+}
+void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) {
+ CALL_GL_API(glGenFencesNV, n, fences);
+}
+GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glIsFenceNV, fence);
+}
+GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glTestFenceNV, fence);
+}
+void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetFenceivNV, fence, pname, params);
+}
+void API_ENTRY(glFinishFenceNV)(GLuint fence) {
+ CALL_GL_API(glFinishFenceNV, fence);
+}
+void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {
+ CALL_GL_API(glSetFenceNV, fence, condition);
+}
+void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {
+ CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);
+}
+void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString) {
+ CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString);
+}
+void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glEnableDriverControlQCOM, driverControl);
+}
+void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glDisableDriverControlQCOM, driverControl);
+}
diff --git a/opengl/libs/GLES2/gl2ext_entries.in b/opengl/libs/GLES2/gl2ext_entries.in
new file mode 100644
index 0000000..e608f5d
--- /dev/null
+++ b/opengl/libs/GLES2/gl2ext_entries.in
@@ -0,0 +1,35 @@
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
+GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params)
+GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
+GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
+GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, char *groupString)
+GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString)
+GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, void *data)
+GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)
+GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 384b59a..3204d9a 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -14,8 +14,6 @@
** limitations under the License.
*/
-#define LOG_TAG "GLES_CM"
-
#include <ctype.h>
#include <string.h>
#include <errno.h>
@@ -121,16 +119,25 @@
/*
- * These GL calls are special because they need to call into EGL to retrieve
- * some informations before they can execute.
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
*/
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
}
void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
}
diff --git a/opengl/libs/gl_entries.in b/opengl/libs/GLES_CM/gl_entries.in
similarity index 100%
rename from opengl/libs/gl_entries.in
rename to opengl/libs/GLES_CM/gl_entries.in
diff --git a/opengl/libs/glext_entries.in b/opengl/libs/GLES_CM/glext_entries.in
similarity index 100%
rename from opengl/libs/glext_entries.in
rename to opengl/libs/GLES_CM/glext_entries.in
diff --git a/opengl/libs/egl_entries.in b/opengl/libs/egl_entries.in
deleted file mode 100644
index 3b4551b..0000000
--- a/opengl/libs/egl_entries.in
+++ /dev/null
@@ -1,52 +0,0 @@
-EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
-EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
-EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
-EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
-EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
-
-EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
-EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
-EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
-EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *)
-EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
-EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
-EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
-EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
-EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
-EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *)
-EGL_ENTRY(EGLBoolean, eglWaitGL, void)
-EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
-EGL_ENTRY(EGLint, eglGetError, void)
-EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
-EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
-
-/* EGL 1.1 */
-
-EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
-EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
-
-/* EGL 1.2 */
-
-EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
-EGL_ENTRY(EGLenum, eglQueryAPI, void)
-EGL_ENTRY(EGLBoolean, eglWaitClient, void)
-EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
-EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
-
-/* EGL 1.3 */
-
-/* EGL 1.4 */
-
-/* EGL_EGLEXT_VERSION 3 */
-
-EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 312b176..ac286cb 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -31,13 +31,14 @@
struct egl_connection_t
{
- void volatile * dso;
+ void * dso;
gl_hooks_t * hooks;
EGLint major;
EGLint minor;
- int unavailable;
};
+EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/gl_enums.in b/opengl/libs/gl_enums.in
deleted file mode 100644
index ffc2fad..0000000
--- a/opengl/libs/gl_enums.in
+++ /dev/null
@@ -1,261 +0,0 @@
-GLENUM(GL_POINTS, 0x0000)
-GLENUM(GL_LINES, 0x0001)
-GLENUM(GL_LINE_LOOP, 0x0002)
-GLENUM(GL_LINE_STRIP, 0x0003)
-GLENUM(GL_TRIANGLES, 0x0004)
-GLENUM(GL_TRIANGLE_STRIP, 0x0005)
-GLENUM(GL_TRIANGLE_FAN, 0x0006)
-GLENUM(GL_ADD, 0x0104)
-GLENUM(GL_NEVER, 0x0200)
-GLENUM(GL_LESS, 0x0201)
-GLENUM(GL_EQUAL, 0x0202)
-GLENUM(GL_LEQUAL, 0x0203)
-GLENUM(GL_GREATER, 0x0204)
-GLENUM(GL_NOTEQUAL, 0x0205)
-GLENUM(GL_GEQUAL, 0x0206)
-GLENUM(GL_ALWAYS, 0x0207)
-GLENUM(GL_SRC_COLOR, 0x0300)
-GLENUM(GL_ONE_MINUS_SRC_COLOR, 0x0301)
-GLENUM(GL_SRC_ALPHA, 0x0302)
-GLENUM(GL_ONE_MINUS_SRC_ALPHA, 0x0303)
-GLENUM(GL_DST_ALPHA, 0x0304)
-GLENUM(GL_ONE_MINUS_DST_ALPHA, 0x0305)
-GLENUM(GL_DST_COLOR, 0x0306)
-GLENUM(GL_ONE_MINUS_DST_COLOR, 0x0307)
-GLENUM(GL_SRC_ALPHA_SATURATE, 0x0308)
-GLENUM(GL_FRONT, 0x0404)
-GLENUM(GL_BACK, 0x0405)
-GLENUM(GL_FRONT_AND_BACK, 0x0408)
-GLENUM(GL_INVALID_ENUM, 0x0500)
-GLENUM(GL_INVALID_VALUE, 0x0501)
-GLENUM(GL_INVALID_OPERATION, 0x0502)
-GLENUM(GL_STACK_OVERFLOW, 0x0503)
-GLENUM(GL_STACK_UNDERFLOW, 0x0504)
-GLENUM(GL_OUT_OF_MEMORY, 0x0505)
-GLENUM(GL_EXP, 0x0800)
-GLENUM(GL_EXP2, 0x0801)
-GLENUM(GL_CW, 0x0900)
-GLENUM(GL_CCW, 0x0901)
-GLENUM(GL_POINT_SMOOTH, 0x0B10)
-GLENUM(GL_SMOOTH_POINT_SIZE_RANGE, 0x0B12)
-GLENUM(GL_LINE_SMOOTH, 0x0B20)
-GLENUM(GL_SMOOTH_LINE_WIDTH_RANGE, 0x0B22)
-GLENUM(GL_CULL_FACE, 0x0B44)
-GLENUM(GL_LIGHTING, 0x0B50)
-GLENUM(GL_LIGHT_MODEL_TWO_SIDE, 0x0B52)
-GLENUM(GL_LIGHT_MODEL_AMBIENT, 0x0B53)
-GLENUM(GL_COLOR_MATERIAL, 0x0B57)
-GLENUM(GL_FOG, 0x0B60)
-GLENUM(GL_FOG_DENSITY, 0x0B62)
-GLENUM(GL_FOG_START, 0x0B63)
-GLENUM(GL_FOG_END, 0x0B64)
-GLENUM(GL_FOG_MODE, 0x0B65)
-GLENUM(GL_FOG_COLOR, 0x0B66)
-GLENUM(GL_DEPTH_TEST, 0x0B71)
-GLENUM(GL_STENCIL_TEST, 0x0B90)
-GLENUM(GL_NORMALIZE, 0x0BA1)
-GLENUM(GL_ALPHA_TEST, 0x0BC0)
-GLENUM(GL_DITHER, 0x0BD0)
-GLENUM(GL_BLEND, 0x0BE2)
-GLENUM(GL_COLOR_LOGIC_OP, 0x0BF2)
-GLENUM(GL_SCISSOR_TEST, 0x0C11)
-GLENUM(GL_PERSPECTIVE_CORRECTION_HINT, 0x0C50)
-GLENUM(GL_POINT_SMOOTH_HINT, 0x0C51)
-GLENUM(GL_LINE_SMOOTH_HINT, 0x0C52)
-GLENUM(GL_POLYGON_SMOOTH_HINT, 0x0C53)
-GLENUM(GL_FOG_HINT, 0x0C54)
-GLENUM(GL_UNPACK_ALIGNMENT, 0x0CF5)
-GLENUM(GL_PACK_ALIGNMENT, 0x0D05)
-GLENUM(GL_MAX_LIGHTS, 0x0D31)
-GLENUM(GL_MAX_CLIP_PLANES, 0x0D32)
-GLENUM(GL_MAX_TEXTURE_SIZE, 0x0D33)
-GLENUM(GL_MAX_MODELVIEW_STACK_DEPTH, 0x0D36)
-GLENUM(GL_MAX_PROJECTION_STACK_DEPTH, 0x0D38)
-GLENUM(GL_MAX_TEXTURE_STACK_DEPTH, 0x0D39)
-GLENUM(GL_MAX_VIEWPORT_DIMS, 0x0D3A)
-GLENUM(GL_RED_BITS, 0x0D52)
-GLENUM(GL_GREEN_BITS, 0x0D53)
-GLENUM(GL_BLUE_BITS, 0x0D54)
-GLENUM(GL_ALPHA_BITS, 0x0D55)
-GLENUM(GL_DEPTH_BITS, 0x0D56)
-GLENUM(GL_STENCIL_BITS, 0x0D57)
-GLENUM(GL_TEXTURE_2D, 0x0DE1)
-GLENUM(GL_DONT_CARE, 0x1100)
-GLENUM(GL_FASTEST, 0x1101)
-GLENUM(GL_NICEST, 0x1102)
-GLENUM(GL_AMBIENT, 0x1200)
-GLENUM(GL_DIFFUSE, 0x1201)
-GLENUM(GL_SPECULAR, 0x1202)
-GLENUM(GL_POSITION, 0x1203)
-GLENUM(GL_SPOT_DIRECTION, 0x1204)
-GLENUM(GL_SPOT_EXPONENT, 0x1205)
-GLENUM(GL_SPOT_CUTOFF, 0x1206)
-GLENUM(GL_CONSTANT_ATTENUATION, 0x1207)
-GLENUM(GL_LINEAR_ATTENUATION, 0x1208)
-GLENUM(GL_QUADRATIC_ATTENUATION, 0x1209)
-GLENUM(GL_BYTE, 0x1400)
-GLENUM(GL_UNSIGNED_BYTE, 0x1401)
-GLENUM(GL_SHORT, 0x1402)
-GLENUM(GL_UNSIGNED_SHORT, 0x1403)
-GLENUM(GL_FLOAT, 0x1406)
-GLENUM(GL_FIXED, 0x140C)
-GLENUM(GL_CLEAR, 0x1500)
-GLENUM(GL_AND, 0x1501)
-GLENUM(GL_AND_REVERSE, 0x1502)
-GLENUM(GL_COPY, 0x1503)
-GLENUM(GL_AND_INVERTED, 0x1504)
-GLENUM(GL_NOOP, 0x1505)
-GLENUM(GL_XOR, 0x1506)
-GLENUM(GL_OR, 0x1507)
-GLENUM(GL_NOR, 0x1508)
-GLENUM(GL_EQUIV, 0x1509)
-GLENUM(GL_INVERT, 0x150A)
-GLENUM(GL_OR_REVERSE, 0x150B)
-GLENUM(GL_COPY_INVERTED, 0x150C)
-GLENUM(GL_OR_INVERTED, 0x150D)
-GLENUM(GL_NAND, 0x150E)
-GLENUM(GL_SET, 0x150F)
-GLENUM(GL_EMISSION, 0x1600)
-GLENUM(GL_SHININESS, 0x1601)
-GLENUM(GL_AMBIENT_AND_DIFFUSE, 0x1602)
-GLENUM(GL_MODELVIEW, 0x1700)
-GLENUM(GL_PROJECTION, 0x1701)
-GLENUM(GL_TEXTURE, 0x1702)
-GLENUM(GL_ALPHA, 0x1906)
-GLENUM(GL_RGB, 0x1907)
-GLENUM(GL_RGBA, 0x1908)
-GLENUM(GL_LUMINANCE, 0x1909)
-GLENUM(GL_LUMINANCE_ALPHA, 0x190A)
-GLENUM(GL_FLAT, 0x1D00)
-GLENUM(GL_SMOOTH, 0x1D01)
-GLENUM(GL_KEEP, 0x1E00)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_INCR, 0x1E02)
-GLENUM(GL_DECR, 0x1E03)
-GLENUM(GL_VENDOR, 0x1F00)
-GLENUM(GL_RENDERER, 0x1F01)
-GLENUM(GL_VERSION, 0x1F02)
-GLENUM(GL_EXTENSIONS, 0x1F03)
-GLENUM(GL_MODULATE, 0x2100)
-GLENUM(GL_DECAL, 0x2101)
-GLENUM(GL_TEXTURE_ENV_MODE, 0x2200)
-GLENUM(GL_TEXTURE_ENV_COLOR, 0x2201)
-GLENUM(GL_TEXTURE_ENV, 0x2300)
-GLENUM(GL_NEAREST, 0x2600)
-GLENUM(GL_LINEAR, 0x2601)
-GLENUM(GL_NEAREST_MIPMAP_NEAREST, 0x2700)
-GLENUM(GL_LINEAR_MIPMAP_NEAREST, 0x2701)
-GLENUM(GL_NEAREST_MIPMAP_LINEAR, 0x2702)
-GLENUM(GL_LINEAR_MIPMAP_LINEAR, 0x2703)
-GLENUM(GL_TEXTURE_MAG_FILTER, 0x2800)
-GLENUM(GL_TEXTURE_MIN_FILTER, 0x2801)
-GLENUM(GL_TEXTURE_WRAP_S, 0x2802)
-GLENUM(GL_TEXTURE_WRAP_T, 0x2803)
-GLENUM(GL_CLAMP, 0x2900)
-GLENUM(GL_REPEAT, 0x2901)
-GLENUM(GL_CLIP_PLANE0, 0x3000)
-GLENUM(GL_CLIP_PLANE1, 0x3001)
-GLENUM(GL_CLIP_PLANE2, 0x3002)
-GLENUM(GL_CLIP_PLANE3, 0x3003)
-GLENUM(GL_CLIP_PLANE4, 0x3004)
-GLENUM(GL_CLIP_PLANE5, 0x3005)
-GLENUM(GL_LIGHT0, 0x4000)
-GLENUM(GL_LIGHT1, 0x4001)
-GLENUM(GL_LIGHT2, 0x4002)
-GLENUM(GL_LIGHT3, 0x4003)
-GLENUM(GL_LIGHT4, 0x4004)
-GLENUM(GL_LIGHT5, 0x4005)
-GLENUM(GL_LIGHT6, 0x4006)
-GLENUM(GL_LIGHT7, 0x4007)
-GLENUM(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0x7E80)
-GLENUM(GL_UNSIGNED_SHORT_4_4_4_4, 0x8033)
-GLENUM(GL_UNSIGNED_SHORT_5_5_5_1, 0x8034)
-GLENUM(GL_POLYGON_OFFSET_FILL, 0x8037)
-GLENUM(GL_RESCALE_NORMAL, 0x803A)
-GLENUM(GL_VERTEX_ARRAY, 0x8074)
-GLENUM(GL_NORMAL_ARRAY, 0x8075)
-GLENUM(GL_COLOR_ARRAY, 0x8076)
-GLENUM(GL_TEXTURE_COORD_ARRAY, 0x8078)
-GLENUM(GL_MULTISAMPLE, 0x809D)
-GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE, 0x809E)
-GLENUM(GL_SAMPLE_ALPHA_TO_ONE, 0x809F)
-GLENUM(GL_SAMPLE_COVERAGE, 0x80A0)
-GLENUM(GL_MAX_ELEMENTS_VERTICES, 0x80E8)
-GLENUM(GL_MAX_ELEMENTS_INDICES, 0x80E9)
-GLENUM(GL_CLAMP_TO_EDGE, 0x812F)
-GLENUM(GL_GENERATE_MIPMAP, 0x8191)
-GLENUM(GL_GENERATE_MIPMAP_HINT, 0x8192)
-GLENUM(GL_UNSIGNED_SHORT_5_6_5, 0x8363)
-GLENUM(GL_ALIASED_POINT_SIZE_RANGE, 0x846D)
-GLENUM(GL_ALIASED_LINE_WIDTH_RANGE, 0x846E)
-GLENUM(GL_TEXTURE0, 0x84C0)
-GLENUM(GL_TEXTURE1, 0x84C1)
-GLENUM(GL_TEXTURE2, 0x84C2)
-GLENUM(GL_TEXTURE3, 0x84C3)
-GLENUM(GL_TEXTURE4, 0x84C4)
-GLENUM(GL_TEXTURE5, 0x84C5)
-GLENUM(GL_TEXTURE6, 0x84C6)
-GLENUM(GL_TEXTURE7, 0x84C7)
-GLENUM(GL_TEXTURE8, 0x84C8)
-GLENUM(GL_TEXTURE9, 0x84C9)
-GLENUM(GL_TEXTURE10, 0x84CA)
-GLENUM(GL_TEXTURE11, 0x84CB)
-GLENUM(GL_TEXTURE12, 0x84CC)
-GLENUM(GL_TEXTURE13, 0x84CD)
-GLENUM(GL_TEXTURE14, 0x84CE)
-GLENUM(GL_TEXTURE15, 0x84CF)
-GLENUM(GL_TEXTURE16, 0x84D0)
-GLENUM(GL_TEXTURE17, 0x84D1)
-GLENUM(GL_TEXTURE18, 0x84D2)
-GLENUM(GL_TEXTURE19, 0x84D3)
-GLENUM(GL_TEXTURE20, 0x84D4)
-GLENUM(GL_TEXTURE21, 0x84D5)
-GLENUM(GL_TEXTURE22, 0x84D6)
-GLENUM(GL_TEXTURE23, 0x84D7)
-GLENUM(GL_TEXTURE24, 0x84D8)
-GLENUM(GL_TEXTURE25, 0x84D9)
-GLENUM(GL_TEXTURE26, 0x84DA)
-GLENUM(GL_TEXTURE27, 0x84DB)
-GLENUM(GL_TEXTURE28, 0x84DC)
-GLENUM(GL_TEXTURE29, 0x84DD)
-GLENUM(GL_TEXTURE30, 0x84DE)
-GLENUM(GL_TEXTURE31, 0x84DF)
-GLENUM(GL_MAX_TEXTURE_UNITS, 0x84E2)
-GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 0x86A2)
-GLENUM(GL_COMPRESSED_TEXTURE_FORMATS, 0x86A3)
-GLENUM(GL_BUFFER_SIZE, 0x8764)
-GLENUM(GL_BUFFER_USAGE, 0x8765)
-GLENUM(GL_POINT_SPRITE_OES, 0x8861)
-GLENUM(GL_COORD_REPLACE_OES, 0x8862)
-GLENUM(GL_ARRAY_BUFFER, 0x8892)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER, 0x8893)
-GLENUM(GL_ARRAY_BUFFER_BINDING, 0x8894)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0x8895)
-GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING, 0x8896)
-GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING, 0x8897)
-GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING, 0x8898)
-GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, 0x889A)
-GLENUM(GL_STATIC_DRAW, 0x88E4)
-GLENUM(GL_DYNAMIC_DRAW, 0x88E8)
-GLENUM(GL_POINT_SIZE_ARRAY_TYPE_OES, 0x898A)
-GLENUM(GL_POINT_SIZE_ARRAY_STRIDE_OES, 0x898B)
-GLENUM(GL_POINT_SIZE_ARRAY_POINTER_OES, 0x898C)
-GLENUM(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898D)
-GLENUM(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898E)
-GLENUM(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898F)
-GLENUM(GL_PALETTE4_RGB8_OES, 0x8B90)
-GLENUM(GL_PALETTE4_RGBA8_OES, 0x8B91)
-GLENUM(GL_PALETTE4_R5_G6_B5_OES, 0x8B92)
-GLENUM(GL_PALETTE4_RGBA4_OES, 0x8B93)
-GLENUM(GL_PALETTE4_RGB5_A1_OES, 0x8B94)
-GLENUM(GL_PALETTE8_RGB8_OES, 0x8B95)
-GLENUM(GL_PALETTE8_RGBA8_OES, 0x8B96)
-GLENUM(GL_PALETTE8_R5_G6_B5_OES, 0x8B97)
-GLENUM(GL_PALETTE8_RGBA4_OES, 0x8B98)
-GLENUM(GL_PALETTE8_RGB5_A1_OES, 0x8B99)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, 0x8B9A)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, 0x8B9B)
-GLENUM(GL_POINT_SIZE_ARRAY_OES, 0x8B9C)
-GLENUM(GL_TEXTURE_CROP_RECT_OES, 0x8B9D)
-GLENUM(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, 0x8B9F)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index fd97254..8c0357e 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -21,10 +21,14 @@
#include <string.h>
#include <errno.h>
+#include <pthread.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#if !defined(__arm__)
#define USE_SLOW_BINDING 1
@@ -56,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
};
@@ -76,11 +76,15 @@
struct gl_hooks_t {
struct gl_t {
- #include "gl_entries.in"
- #include "glext_entries.in"
+ #include "GLES_CM/gl_entries.in"
+ #include "GLES_CM/glext_entries.in"
} gl;
+ struct gl2_t {
+ #include "GLES2/gl2_entries.in"
+ #include "GLES2/gl2ext_entries.in"
+ } gl2;
struct egl_t {
- #include "egl_entries.in"
+ #include "EGL/egl_entries.in"
} egl;
struct gl_ext_t {
void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
@@ -94,6 +98,13 @@
extern gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
extern pthread_key_t gGLWrapperKey;
+extern "C" void gl_unimplemented();
+
+extern char const * const gl_names[];
+extern char const * const gl2_names[];
+extern char const * const egl_names[];
+
+// ----------------------------------------------------------------------------
#if USE_FAST_TLS_KEY
diff --git a/opengl/libs/tools/enumextract.sh b/opengl/libs/tools/enumextract.sh
deleted file mode 100644
index 5707302..0000000
--- a/opengl/libs/tools/enumextract.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-awk '
-/^#define GL_/ {
- names[count] = $2;
- values[count] = $3;
- sort[count] = $3 + 0;
- count++;
-}
-END {
- for (i = 1; i < count; i++) {
- for (j = 0; j < i; j++) {
- if (sort[i] < sort[j]) {
- tn = names[i];
- tv = values[i];
- ts = sort[i];
- names[i] = names[j];
- values[i] = values[j];
- sort[i] = sort[j];
- names[j] = tn;
- values[j] = tv;
- sort[j] = ts;
- }
- }
- }
-
- for (i = 0; i < count; i++) {
- printf("GLENUM(%s, %s)\n", names[i], values[i]);
- }
-}
-' < $1
-
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
index 107768b..4f8eda4 100755
--- a/opengl/libs/tools/genfiles
+++ b/opengl/libs/tools/genfiles
@@ -15,6 +15,13 @@
# limitations under the License.
./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in
-./glentrygen ../../include/GLES/gl.h > ../gl_entries.in
+./glentrygen ../../include/GLES/gl.h > ../GLES_CM/gl_entries.in
+
./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in
-./glentrygen ../../include/GLES/glext.h > ../glext_entries.in
+./glentrygen ../../include/GLES/glext.h > ../GLES_CM/glext_entries.in
+
+./glapigen ../../include/GLES2/gl2.h > ../GLES2/gl2_api.in
+./glentrygen ../../include/GLES2/gl2.h > ../GLES2/gl2_entries.in
+
+./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in
+./glentrygen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_entries.in
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index a2c3a7b..bd8dda3 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
#printf("%s", $line);
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
index 5e0f7b6..170f041 100755
--- a/opengl/libs/tools/glentrygen
+++ b/opengl/libs/tools/glentrygen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
}
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index e193483..d0c3221 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -2,7 +2,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.c demo.c.arm
+LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
LOCAL_MODULE:= angeles
LOCAL_MODULE_TAGS := optional
diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c
deleted file mode 100644
index 7d0d320..0000000
--- a/opengl/tests/angeles/app-linux.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* San Angeles Observation OpenGL ES version example
- * Copyright 2004-2005 Jetro Lauha
- * All rights reserved.
- * Web: http://iki.fi/jetro/
- *
- * This source is free software; you can redistribute it and/or
- * modify it under the terms of EITHER:
- * (1) The GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at
- * your option) any later version. The text of the GNU Lesser
- * General Public License is included with this source in the
- * file LICENSE-LGPL.txt.
- * (2) The BSD-style license that is included with this source in
- * the file LICENSE-BSD.txt.
- *
- * This source is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
- * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
- *
- * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $
- * $Revision: 1.4 $
- *
- * Parts of this source file is based on test/example code from
- * GLESonGL implementation by David Blythe. Here is copy of the
- * license notice from that source:
- *
- * Copyright (C) 2003 David Blythe All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-
-#include "app.h"
-
-
-int gAppAlive = 1;
-
-static const char sAppName[] =
- "San Angeles Observation OpenGL ES version example (Linux)";
-
-static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
-static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
-static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
-static EGLContext sEglContext = EGL_NO_CONTEXT;
-static EGLSurface sEglSurface = EGL_NO_SURFACE;
-
-const char *egl_strerror(unsigned err)
-{
- switch(err){
- case EGL_SUCCESS: return "SUCCESS";
- case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
- case EGL_BAD_ACCESS: return "BAD ACCESS";
- case EGL_BAD_ALLOC: return "BAD ALLOC";
- case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "BAD CONFIG";
- case EGL_BAD_CONTEXT: return "BAD CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
- case EGL_BAD_DISPLAY: return "BAD DISPLAY";
- case EGL_BAD_MATCH: return "BAD MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
- case EGL_BAD_PARAMETER: return "BAD PARAMETER";
- case EGL_BAD_SURFACE: return "BAD_SURFACE";
-// case EGL_CONTEXT_LOST: return "CONTEXT LOST";
- default: return "UNKNOWN";
- }
-}
-
-void egl_error(const char *name)
-{
- unsigned err = eglGetError();
- if(err != EGL_SUCCESS) {
- fprintf(stderr,"%s(): egl error 0x%x (%s)\n",
- name, err, egl_strerror(err));
- }
-}
-
-static void checkGLErrors()
-{
- GLenum error = glGetError();
- if (error != GL_NO_ERROR)
- fprintf(stderr, "GL Error: 0x%04x\n", (int)error);
-}
-
-
-static void checkEGLErrors()
-{
- EGLint error = eglGetError();
- // GLESonGL seems to be returning 0 when there is no errors?
- if (error && error != EGL_SUCCESS)
- fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
-}
-
-static int initGraphics()
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- #if 1
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, 0,
- #else
- EGL_ALPHA_SIZE, EGL_DONT_CARE,
- EGL_DEPTH_SIZE, EGL_DONT_CARE,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_SURFACE_TYPE, EGL_DONT_CARE,
- #endif
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- egl_error("eglGetDisplay");
- fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy);
-
- eglInitialize(dpy, &majorVersion, &minorVersion);
- egl_error("eglInitialize");
-
- eglGetConfigs(dpy, NULL, 0, &numConfigs);
- egl_error("eglGetConfigs");
- fprintf(stderr,"num configs %d\n", numConfigs);
-
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- egl_error("eglChooseConfig");
-
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- egl_error("eglMapWindowSurface");
-
- fprintf(stderr,"surface = %p\n", surface);
-
- context = eglCreateContext(dpy, config, NULL, NULL);
- egl_error("eglCreateContext");
- fprintf(stderr,"context = %p\n", context);
-
- eglMakeCurrent(dpy, surface, surface, context);
- egl_error("eglMakeCurrent");
-
- eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
-
- sEglDisplay = dpy;
- sEglSurface = surface;
- sEglContext = context;
-
- return EGL_TRUE;
-}
-
-
-static void deinitGraphics()
-{
- eglMakeCurrent(sEglDisplay, NULL, NULL, NULL);
- eglDestroyContext(sEglDisplay, sEglContext);
- eglDestroySurface(sEglDisplay, sEglSurface);
- eglTerminate(sEglDisplay);
-}
-
-
-int main(int argc, char *argv[])
-{
- // not referenced:
- argc = argc;
- argv = argv;
-
- if (!initGraphics())
- {
- fprintf(stderr, "Graphics initialization failed.\n");
- return EXIT_FAILURE;
- }
-
- appInit();
-
- while (gAppAlive)
- {
- struct timeval timeNow;
-
- if (gAppAlive)
- {
- gettimeofday(&timeNow, NULL);
- appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000,
- sWindowWidth, sWindowHeight);
- checkGLErrors();
- eglSwapBuffers(sEglDisplay, sEglSurface);
- checkEGLErrors();
- }
- }
-
- appDeinit();
- deinitGraphics();
-
- return EXIT_SUCCESS;
-}
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
new file mode 100644
index 0000000..06fa0c2
--- /dev/null
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -0,0 +1,213 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ * (1) The GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version. The text of the GNU Lesser
+ * General Public License is included with this source in the
+ * file LICENSE-LGPL.txt.
+ * (2) The BSD-style license that is included with this source in
+ * the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $
+ * $Revision: 1.4 $
+ *
+ * Parts of this source file is based on test/example code from
+ * GLESonGL implementation by David Blythe. Here is copy of the
+ * license notice from that source:
+ *
+ * Copyright (C) 2003 David Blythe All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+#include "app.h"
+
+
+int gAppAlive = 1;
+
+static const char sAppName[] =
+ "San Angeles Observation OpenGL ES version example (Linux)";
+
+static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
+static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
+static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
+static EGLContext sEglContext = EGL_NO_CONTEXT;
+static EGLSurface sEglSurface = EGL_NO_SURFACE;
+
+const char *egl_strerror(unsigned err)
+{
+ switch(err){
+ case EGL_SUCCESS: return "SUCCESS";
+ case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
+ case EGL_BAD_ACCESS: return "BAD ACCESS";
+ case EGL_BAD_ALLOC: return "BAD ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "BAD CONFIG";
+ case EGL_BAD_CONTEXT: return "BAD CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
+ case EGL_BAD_DISPLAY: return "BAD DISPLAY";
+ case EGL_BAD_MATCH: return "BAD MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
+ case EGL_BAD_PARAMETER: return "BAD PARAMETER";
+ case EGL_BAD_SURFACE: return "BAD_SURFACE";
+// case EGL_CONTEXT_LOST: return "CONTEXT LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+void egl_error(const char *name)
+{
+ unsigned err = eglGetError();
+ if(err != EGL_SUCCESS) {
+ fprintf(stderr,"%s(): egl error 0x%x (%s)\n",
+ name, err, egl_strerror(err));
+ }
+}
+
+static void checkGLErrors()
+{
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ fprintf(stderr, "GL Error: 0x%04x\n", (int)error);
+}
+
+
+static void checkEGLErrors()
+{
+ EGLint error = eglGetError();
+ // GLESonGL seems to be returning 0 when there is no errors?
+ if (error && error != EGL_SUCCESS)
+ fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
+}
+
+static int initGraphics()
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ egl_error("eglCreateWindowSurface");
+
+ fprintf(stderr,"surface = %p\n", surface);
+
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ egl_error("eglCreateContext");
+ fprintf(stderr,"context = %p\n", context);
+
+ eglMakeCurrent(dpy, surface, surface, context);
+ egl_error("eglMakeCurrent");
+
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
+
+ sEglDisplay = dpy;
+ sEglSurface = surface;
+ sEglContext = context;
+
+ return EGL_TRUE;
+}
+
+
+static void deinitGraphics()
+{
+ eglMakeCurrent(sEglDisplay, NULL, NULL, NULL);
+ eglDestroyContext(sEglDisplay, sEglContext);
+ eglDestroySurface(sEglDisplay, sEglSurface);
+ eglTerminate(sEglDisplay);
+}
+
+
+int main(int argc, char *argv[])
+{
+ // not referenced:
+ argc = argc;
+ argv = argv;
+
+ if (!initGraphics())
+ {
+ fprintf(stderr, "Graphics initialization failed.\n");
+ return EXIT_FAILURE;
+ }
+
+ appInit();
+
+ while (gAppAlive)
+ {
+ struct timeval timeNow;
+
+ if (gAppAlive)
+ {
+ gettimeofday(&timeNow, NULL);
+ appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000,
+ sWindowWidth, sWindowHeight);
+ checkGLErrors();
+ eglSwapBuffers(sEglDisplay, sEglSurface);
+ checkEGLErrors();
+ }
+ }
+
+ appDeinit();
+ deinitGraphics();
+
+ return EXIT_SUCCESS;
+}
diff --git a/opengl/tests/copybits/Android.mk b/opengl/tests/copybits/Android.mk
new file mode 100644
index 0000000..d5ded42
--- /dev/null
+++ b/opengl/tests/copybits/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ copybits.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-copybits
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/opengl/tests/copybits/copybits.cpp b/opengl/tests/copybits/copybits.cpp
new file mode 100644
index 0000000..11dfb6e
--- /dev/null
+++ b/opengl/tests/copybits/copybits.cpp
@@ -0,0 +1,726 @@
+// Test software OpenGL hardware accelleration using copybits.
+
+#define LOG_TAG "copybits_test"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <ui/PixelFormat.h>
+
+#include <cutils/log.h>
+#include <cutils/native_handle.h>
+
+#include <utils/Atomic.h>
+
+#include <private/ui/SurfaceBuffer.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+#define EGL_EGLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+
+EGLDisplay eglDisplay;
+EGLSurface eglSurface;
+EGLContext eglContext;
+GLuint texture;
+
+hw_module_t const* gralloc_module;
+alloc_device_t *sAllocDev;
+
+#define FIXED_ONE 0x10000 /* 1.0 in 16.16 fixed point. */
+
+int init_gl_surface();
+void free_gl_surface();
+void init_scene();
+
+int create_physical_texture();
+int readTimer();
+
+// ===========================================================================
+// Buffer an implementation of android_native_buffer_t
+// ===========================================================================
+
+class NativeBuffer;
+
+class Buffer : public android::SurfaceBuffer
+{
+public:
+ // creates w * h buffer
+ Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+ // return status
+ status_t initCheck() const;
+
+ uint32_t getWidth() const { return width; }
+ uint32_t getHeight() const { return height; }
+ uint32_t getStride() const { return stride; }
+ uint32_t getUsage() const { return usage; }
+ PixelFormat getPixelFormat() const { return format; }
+
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+ void setPixel(int x, int y, int r, int g, int b, int a);
+
+ status_t lock(GGLSurface* surface, uint32_t usage);
+ void lock() {
+ GGLSurface s;
+ lock(&s, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ mData = (void*)s.data;
+ }
+
+private:
+ friend class LightRefBase<Buffer>;
+ Buffer(const Buffer& rhs);
+ virtual ~Buffer();
+ Buffer& operator = (const Buffer& rhs);
+ const Buffer& operator = (const Buffer& rhs) const;
+
+ status_t initSize(uint32_t w, uint32_t h);
+
+ ssize_t mInitCheck;
+ void* mData;
+};
+
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage)
+ : SurfaceBuffer(), mInitCheck(NO_INIT)
+{
+ this->usage = usage;
+ this->format = format;
+ if (w>0 && h>0) {
+ mInitCheck = initSize(w, h);
+ }
+}
+
+Buffer::~Buffer()
+{
+ if (handle) {
+ sAllocDev->free(sAllocDev, handle);
+ }
+}
+
+status_t Buffer::initCheck() const {
+ return mInitCheck;
+}
+
+android_native_buffer_t* Buffer::getNativeBuffer() const
+{
+ return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
+}
+
+status_t Buffer::initSize(uint32_t w, uint32_t h)
+{
+ status_t err = NO_ERROR;
+
+ err = sAllocDev->alloc(sAllocDev, w, h, format, usage, &handle, &stride);
+
+ if (err == NO_ERROR) {
+ if (err == NO_ERROR) {
+ width = w;
+ height = h;
+ }
+ }
+
+ return err;
+}
+
+status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
+{
+ void* vaddr;
+ status_t res = SurfaceBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->data = static_cast<GGLubyte*>(vaddr);
+ }
+ return res;
+}
+
+
+void Buffer::setPixel(int x, int y, int r, int g, int b, int a) {
+ if (x < 0 || (unsigned int) x >= width
+ || y < 0 || (unsigned int) y >= height) {
+ // clipped
+ return;
+ }
+ int index = stride * y + x;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565: {
+ unsigned short val = (unsigned short) (
+ ((0x1f & (r >> 3)) << 11)
+ | ((0x3f & (g >> 2)) << 5)
+ | (0x1f & (b >> 3)));
+ ((unsigned short*) mData)[index]= val;
+ }
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888: { // ABGR
+ unsigned int val = (unsigned int)
+ (((a & 0xff) << 24)
+ | ((b & 0xff) << 16)
+ | ((g & 0xff) << 8)
+ | (r & 0xff));
+ ((unsigned int*) mData)[index] = val;
+ }
+ break;
+ default:
+ // Unsupported pixel format
+ break;
+ }
+}
+
+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ, float upX, float upY,
+ float upZ)
+{
+ // See the OpenGL GLUT documentation for gluLookAt for a description
+ // of the algorithm. We implement it in a straightforward way:
+
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // Normalize up
+ float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+ upX *= rlup;
+ upY *= rlup;
+ upZ *= rlup;
+
+ // compute s = f x up (x means "cross product")
+
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ float m[16] ;
+ m[0] = sx;
+ m[1] = ux;
+ m[2] = -fx;
+ m[3] = 0.0f;
+
+ m[4] = sy;
+ m[5] = uy;
+ m[6] = -fy;
+ m[7] = 0.0f;
+
+ m[8] = sz;
+ m[9] = uz;
+ m[10] = -fz;
+ m[11] = 0.0f;
+
+ m[12] = 0.0f;
+ m[13] = 0.0f;
+ m[14] = 0.0f;
+ m[15] = 1.0f;
+
+ glMultMatrixf(m);
+ glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+
+int init_gralloc() {
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &gralloc_module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+
+ if (err == 0) {
+ gralloc_open(gralloc_module, &sAllocDev);
+ }
+ return err;
+}
+
+int init_gl_surface(void)
+{
+ EGLint numConfigs = 1;
+ EGLConfig myConfig = {0};
+ EGLint attrib[] =
+ {
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ printf("init_gl_surface\n");
+ if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
+ {
+ printf("eglGetDisplay failed\n");
+ return 0;
+ }
+
+ if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )
+ {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ if ( EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig) != 0)
+ {
+ printf("EGLUtils::selectConfigForNativeWindow failed\n");
+ return 0;
+ }
+
+
+ if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
+ window, 0)) == EGL_NO_SURFACE )
+ {
+ printf("eglCreateWindowSurface failed\n");
+ return 0;
+ }
+
+ if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
+ {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+
+ if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )
+ {
+ printf("eglMakeCurrent failed\n");
+ return 0;
+ }
+
+#if EGL_ANDROID_swap_rectangle
+ eglSetSwapRectangleANDROID(eglDisplay, eglSurface, 0, 0, 320, 480);
+#endif
+
+ return 1;
+}
+
+void free_gl_surface(void)
+{
+ if (eglDisplay != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent( eglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT );
+ eglDestroyContext( eglDisplay, eglContext );
+ eglDestroySurface( eglDisplay, eglSurface );
+ eglTerminate( eglDisplay );
+ eglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void init_scene(void)
+{
+ glDisable(GL_DITHER);
+ glEnable(GL_CULL_FACE);
+ float ratio = 320.0f / 480.0f;
+ glViewport(0, 0, 320, 480);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+ gluLookAt(
+ 0, 0, 3, // eye
+ 0, 0, 0, // center
+ 0, 1, 0); // up
+
+ glEnable(GL_TEXTURE_2D);
+}
+
+// #define USE_ALPHA_COLOR
+
+#define USE_GL_REPLACE
+//#define USE_GL_MODULATE
+
+// #define USE_BLEND
+
+#define USE_565
+// #define USE_8888
+
+// #define USE_NEAREST
+#define USE_LINEAR
+
+#define USE_SCALE
+
+void setSmoothGradient(Buffer* bufferObject) {
+ int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+ int step = 0;
+ for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ int grey = step * 255 / pixels;
+ bufferObject->setPixel(x, y, grey, grey, grey, 255);
+ ++step;
+ }
+ }
+}
+
+void setSmoothAlphaGradient(Buffer* bufferObject) {
+ int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+ int step = 0;
+ for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ int grey = step * 255 / pixels;
+ bufferObject->setPixel(x, y, 255, 255, 255, grey);
+ ++step;
+ }
+ }
+}
+
+void setOrientedCheckerboard(Buffer* bufferObject) {
+ bufferObject->setPixel(0, 0, 0, 0, 0, 255);
+ for(unsigned int x = 1; x < bufferObject->getWidth() ; x++) {
+ bufferObject->setPixel(x, 0, 0, 255, 0, 255);
+ }
+ for (unsigned int y = 1; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ if ((x ^ y ) & 1) {
+ bufferObject->setPixel(x, y, 255, 255, 255, 255);
+ } else {
+ bufferObject->setPixel(x, y, 255, 0, 0, 255);
+ }
+ }
+ }
+}
+
+int create_physical_texture(unsigned int w, unsigned int h)
+{
+
+#ifdef USE_565
+ PixelFormat format = HAL_PIXEL_FORMAT_RGB_565;
+#else
+ PixelFormat format = HAL_PIXEL_FORMAT_RGBA_8888;
+#endif
+ int usage = GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_HW_2D; /* This is the key to allocating the texture in pmem. */
+ int32_t stride;
+ buffer_handle_t handle;
+
+ // Allocate the hardware buffer
+ Buffer* bufferObject = new Buffer(w, h, format, usage);
+
+ android_native_buffer_t* buffer = bufferObject->getNativeBuffer();
+
+ buffer->common.incRef(&buffer->common);
+
+ // create the new EGLImageKHR
+ EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_NONE };
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)buffer, attrs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ printf("Could not create an image %d\n", eglGetError());
+ return -1;
+ }
+
+ bufferObject->lock();
+ setOrientedCheckerboard(bufferObject);
+ // setSmoothGradient(bufferObject);
+ // setSmoothAlphaGradient(bufferObject);
+ bufferObject->unlock();
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+#ifdef USE_LINEAR
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#elif defined(USE_NEAREST)
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+#ifdef USE_GL_REPLACE
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+#elif defined(USE_GL_MODULATE)
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+#endif
+
+#ifdef USE_ALPHA_COLOR
+ glColor4f(1.0f, 1.0f, 1.0f, 0.4f);
+#else
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+#endif
+
+#ifdef USE_BLEND
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+ return 0;
+}
+
+static const int SCALE_COUNT = 12;
+
+int scale(int base, int factor) {
+ static const float kTable[SCALE_COUNT] = {
+ 0.24f, 0.25f, 0.5f, 0.75f, 1.0f,
+ 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 5.0f
+ };
+ return base * kTable[factor];
+}
+
+class Timer {
+ struct timeval first;
+ double elapsedSeconds;
+
+public:
+ Timer() {}
+ void start() {
+ gettimeofday(&first, NULL);
+ }
+
+ void stop() {
+ struct timeval second,
+ elapsed;
+ gettimeofday(&second, NULL);
+
+ if (first.tv_usec > second.tv_usec) {
+ second.tv_usec += 1000000;
+ second.tv_sec--;
+ }
+
+ elapsedSeconds = (second.tv_sec - first.tv_sec) +
+ (second.tv_usec - first.tv_usec) / 1000000.0;
+ }
+
+ double getElapsedSeconds() {
+ return elapsedSeconds;
+ }
+
+ double getElapsedMs() {
+ return elapsedSeconds* 1000.0f;
+ }
+};
+
+int testTime()
+{
+ static const int WIDTH = 320;
+ static const int HEIGHT = 480;
+ static const int SCALE = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 1.0, 0.4, 0.4);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+#if defined(USE_SCALE)
+ static const int scaleOffset = 0;
+#else
+ static const int scaleOffset = 1;
+#endif
+ printf("ms\n");
+ for(int j = 0; j < SCALE; j++) {
+ int w = WIDTH >> (j + scaleOffset);
+ int h = HEIGHT >> j;
+ int cropRect[4] = {0,h,w,-h}; // Left bottom width height. Width and Height can be neg to flip.
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+ Timer timer;
+ timer.start();
+
+ int copyCount = 1000;
+ for (int i = 0; i < copyCount; i++) {
+ glDrawTexiOES(0, 0, 0, w, h);
+ }
+
+ timer.stop();
+ printf("%g\n", timer.getElapsedMs() / copyCount);
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ return 0;
+}
+
+int testStretch()
+{
+ static const int WIDTH = 8;
+ static const int HEIGHT = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 1.0, 0.4, 1.0);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ int cropRect[4] = {0,HEIGHT,WIDTH,-HEIGHT}; // Left bottom width height. Width and Height can be neg to flip.
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+ for(int frame = 0; frame < 2; frame++) {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ int baseX = 10;
+ for (int x = 0; x < SCALE_COUNT; x++) {
+ int baseY = 10;
+ int width = scale(WIDTH, x);
+ for (int y = 0; y < SCALE_COUNT; y++) {
+ int height = scale(HEIGHT, y);
+ glDrawTexxOES(baseX << 16, baseY << 16, 0, width << 16, height << 16);
+ baseY += height + 10;
+ }
+ baseX += width + 10;
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ LOGD("wait 1s");
+ usleep(1000000);
+ }
+ return 0;
+}
+
+int testRot90()
+{
+ static const int WIDTH = 8;
+ static const int HEIGHT = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, 320, 480, 0, 0, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 0.4, 0.4, 0.4);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+ glDisable(GL_BLEND);
+ glShadeModel(GL_FLAT);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+
+ for(int frame = 0; frame < 2; frame++) {
+ LOGD("frame = %d", frame);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ int baseX = 10;
+ for (int x = 0; x < SCALE_COUNT; x++) {
+ int baseY = 10;
+ int width = scale(WIDTH, x);
+ for (int y = 0; y < SCALE_COUNT; y++) {
+ int height = scale(HEIGHT, y);
+
+ // Code copied from SurfaceFlinger LayerBase.cpp
+
+ const GLfixed texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 0x10000 },
+ { 0x10000, 0x10000 },
+ { 0x10000, 0 }
+ };
+
+ GLfixed fx = baseX << 16;
+ GLfixed fy = baseY << 16;
+ GLfixed fw = width << 16;
+ GLfixed fh = height << 16;
+
+ /*
+ * Vertex pattern:
+ * (2)--(3)
+ * |\ |
+ * | \ |
+ * | \ |
+ * | \|
+ * (1)--(0)
+ *
+ */
+
+ const GLfixed vertices[4][2] = {
+ {fx + fw, fy},
+ {fx, fy},
+ {fx, fy + fh},
+ {fx + fw, fy + fh}
+ };
+
+ static const bool rotate90 = true;
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, vertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ LOGD("testRot90 %d, %d %d, %d", baseX, baseY, width, height);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ baseY += height + 10;
+ }
+ baseX += width + 10;
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+
+ int q;
+ int start, end;
+
+ if (init_gralloc()) {
+ printf("gralloc initialization failed - exiting\n");
+ return 0;
+ }
+
+ printf("Initializing EGL...\n");
+
+ if(!init_gl_surface())
+ {
+ printf("GL initialisation failed - exiting\n");
+ return 0;
+ }
+
+ init_scene();
+
+ printf("Start test...\n");
+ // testTime();
+ testStretch();
+ //testRot90();
+ free_gl_surface();
+
+ return 0;
+}
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
new file mode 100644
index 0000000..a7d30c2
--- /dev/null
+++ b/opengl/tests/fillrate/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ fillrate.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-fillrate
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
new file mode 100644
index 0000000..911d354
--- /dev/null
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -0,0 +1,161 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ uint32_t* t32 = (uint32_t*)malloc(512*512*4);
+ for (int y=0 ; y<512 ; y++) {
+ for (int x=0 ; x<512 ; x++) {
+ int u = x-256;
+ int v = y-256;
+ if (u*u+v*v < 256*256) {
+ t32[x+y*512] = 0x10FFFFFF;
+ } else {
+ t32[x+y*512] = 0x20FF0000;
+ }
+ }
+ }
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ eglSwapBuffers(dpy, surface);
+
+
+ nsecs_t times[32];
+
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ // for (int c=31 ; c>=1 ; c--) {
+ int j=0;
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ nsecs_t now = systemTime();
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ nsecs_t t = systemTime() - now;
+ times[j++] = t;
+ }
+
+ for (int c=1, j=0 ; c<32 ; c++, j++) {
+ nsecs_t t = times[j];
+ printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+ }
+
+
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index 31b7d9a..a254127 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- filter.c
+ filter.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.c
deleted file mode 100644
index de97119..0000000
--- a/opengl/tests/filter/filter.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-int main(int argc, char** argv)
-{
- if (argc!=2 && argc!=3) {
- printf("usage: %s <0-6> [pbuffer]\n", argv[0]);
- return 0;
- }
-
- const int test = atoi(argv[1]);
- int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer");
- EGLint s_configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- if (!usePbuffer) {
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- } else {
- printf("using pbuffer\n");
- EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
- surface = eglCreatePbufferSurface(dpy, config, attribs);
- if (surface == EGL_NO_SURFACE) {
- printf("eglCreatePbufferSurface error %x\n", eglGetError());
- }
- }
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- GLint crop[4] = { 0, 4, 4, -4 };
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
-
- // packing is always 4
- uint8_t t8[] = {
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF,
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF };
-
- uint16_t t16[] = {
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
-
- uint16_t t5551[] = {
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000,
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
-
- uint32_t t32[] = {
- 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
- 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
- 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
- 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
- };
-
- switch(test)
- {
- case 1:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
- 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
- break;
- case 2:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
- break;
- case 3:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
- break;
- case 4:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
- 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
- break;
- case 5:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
- break;
- case 6:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
- break;
- }
-
- glDrawTexiOES(0, 0, 0, dim, dim);
-
- if (!usePbuffer) {
- eglSwapBuffers(dpy, surface);
- } else {
- glFinish();
- }
-
- eglTerminate(dpy);
- return 0;
-}
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
new file mode 100644
index 0000000..2351909
--- /dev/null
+++ b/opengl/tests/filter/filter.cpp
@@ -0,0 +1,190 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+#define USE_DRAW_TEXTURE 1
+
+int main(int argc, char** argv)
+{
+ if (argc!=2 && argc!=3) {
+ printf("usage: %s <0-6> [pbuffer]\n", argv[0]);
+ return 0;
+ }
+
+ const int test = atoi(argv[1]);
+ int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer");
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_NONE
+ };
+
+ EGLint numConfigs = -1;
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLConfig config;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = 0;
+ if (!usePbuffer) {
+ window = android_createDisplaySurface();
+ }
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+ if (!usePbuffer) {
+ EGLUtils::selectConfigForNativeWindow(
+ dpy, s_configAttribs, window, &config);
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ } else {
+ printf("using pbuffer\n");
+ eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+ EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
+ surface = eglCreatePbufferSurface(dpy, config, attribs);
+ if (surface == EGL_NO_SURFACE) {
+ printf("eglCreatePbufferSurface error %x\n", eglGetError());
+ }
+ }
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ GLint crop[4] = { 0, 4, 4, -4 };
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ // packing is always 4
+ uint8_t t8[] = {
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF };
+
+ uint16_t t16[] = {
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
+
+ uint16_t t5551[] = {
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
+
+ uint32_t t32[] = {
+ 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+ 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
+ 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
+ 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+ };
+
+ switch(test)
+ {
+ case 1:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+ 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+ break;
+ case 2:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+ break;
+ case 3:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+ break;
+ case 4:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+ 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
+ break;
+ case 5:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
+ break;
+ case 6:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+ break;
+ }
+
+ //glDrawTexiOES(0, 0, 0, dim, dim);
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, dim },
+ { dim, dim },
+ { dim, 0 }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ if (!usePbuffer) {
+ eglSwapBuffers(dpy, surface);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glScissor(0,dim,dim,h-dim);
+ glDisable(GL_SCISSOR_TEST);
+
+ for (int y=0 ; y<dim ; y++) {
+ //glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ //glEnable(GL_SCISSOR_TEST);
+
+#if USE_DRAW_TEXTURE && GL_OES_draw_texture
+ glDrawTexiOES(0, y, 1, dim, dim);
+#else
+ glLoadIdentity();
+ glTranslatef(0, y, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#endif
+
+ if (!usePbuffer) {
+ eglSwapBuffers(dpy, surface);
+ } else {
+ glFinish();
+ }
+ }
+
+ eglTerminate(dpy);
+ return 0;
+}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 8b46cd7..5620814 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- finish.c
+ finish.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.c
deleted file mode 100644
index 45fc758..0000000
--- a/opengl/tests/finish/finish.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <sched.h>
-#include <sys/resource.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-
-long long systemTime()
-{
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
-
-int main(int argc, char** argv)
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
- glDisable(GL_DITHER);
- glShadeModel(GL_FLAT);
-
- long long now, t;
- int i;
-
- char* texels = malloc(512*512*2);
- memset(texels,0xFF,512*512*2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
-
- char* dst = malloc(320*480*2);
- memset(dst, 0, 320*480*2);
- printf("307200 bytes memcpy\n");
- for (i=0 ; i<4 ; i++) {
- now = systemTime();
- memcpy(dst, texels, 320*480*2);
- t = systemTime();
- printf("memcpy() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- }
- free(dst);
-
- free(texels);
-
- setpriority(PRIO_PROCESS, 0, -20);
-
- printf("512x512 unmodified texture, 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 1x1 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 512x512 blit (x2):\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 1x1 blit (x2):\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
-
- printf("512x512 (1x1 texel MODIFIED texture), 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- uint16_t green = 0x7E0;
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
-
- int16_t texel = 0xF800;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &texel);
-
- printf("1x1 unmodified texture, 1x1 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("1x1 unmodified texture, 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("1x1 (1x1 texel MODIFIED texture), 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- uint16_t green = 0x7E0;
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- return 0;
-}
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
new file mode 100644
index 0000000..91f5c45
--- /dev/null
+++ b/opengl/tests/finish/finish.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+ glDisable(GL_DITHER);
+ glShadeModel(GL_FLAT);
+
+ long long now, t;
+ int i;
+
+ char* texels = (char*)malloc(512*512*2);
+ memset(texels,0xFF,512*512*2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
+
+ char* dst = (char*)malloc(320*480*2);
+ memset(dst, 0, 320*480*2);
+ printf("307200 bytes memcpy\n");
+ for (i=0 ; i<4 ; i++) {
+ now = systemTime();
+ memcpy(dst, texels, 320*480*2);
+ t = systemTime();
+ printf("memcpy() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ }
+ free(dst);
+
+ free(texels);
+
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ printf("512x512 unmodified texture, 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 1x1 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 512x512 blit (x2):\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 1x1 blit (x2):\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ printf("512x512 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ uint16_t green = 0x7E0;
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ int16_t texel = 0xF800;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &texel);
+
+ printf("1x1 unmodified texture, 1x1 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("1x1 unmodified texture, 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("1x1 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ uint16_t green = 0x7E0;
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
new file mode 100644
index 0000000..619447c
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ swapinterval.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-swapinterval
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
new file mode 100644
index 0000000..df53b62
--- /dev/null
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -0,0 +1,121 @@
+/*
+ **
+ ** Copyright 2006, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLint numConfigs=0;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+ eglGetConfigs(dpy, NULL, 0, &numConfigs);
+ printf("# configs = %d\n", numConfigs);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ if (surface == EGL_NO_SURFACE) {
+ EGLint err = eglGetError();
+ fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
+ EGLUtils::strerror(err), config, r,g,b,a);
+ return 0;
+ } else {
+ printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+ }
+
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+
+ glViewport(0, 0, w, h);
+ glOrthof(0, w, 0, h, 0, 1);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+
+
+ int time = 10;
+ printf("screen should flash red/green quickly for %d s...\n", time);
+
+ int c = 0;
+ nsecs_t start = systemTime();
+ nsecs_t t;
+ do {
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ glClearColor(0,1,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ t = systemTime() - start;
+ c += 2;
+ } while (int(ns2s(t))<=time);
+
+ double p = (double(t) / c) / 1000000000.0;
+ printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0);
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index 8d5f56d..b2fa185 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- textures.c
+ textures.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.c
deleted file mode 100644
index 214291b..0000000
--- a/opengl/tests/textures/textures.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-int main(int argc, char** argv)
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
-
- GLint crop[4] = { 0, 4, 4, -4 };
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
-
- // packing is always 4
- uint8_t t8[] = {
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF,
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF };
-
- uint16_t t16[] = {
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
-
- uint16_t t5551[] = {
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000,
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
-
- uint32_t t32[] = {
- 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
- 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
- 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
- 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
- };
-
-
- glClear(GL_COLOR_BUFFER_BIT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
- glDrawTexiOES(0, 0, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
- glDrawTexiOES(dim/2, 0, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
- glDrawTexiOES(0, dim/2, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
- glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
-
- eglSwapBuffers(dpy, surface);
- return 0;
-}
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
new file mode 100644
index 0000000..cbe8ffd
--- /dev/null
+++ b/opengl/tests/textures/textures.cpp
@@ -0,0 +1,118 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+
+ GLint crop[4] = { 0, 4, 4, -4 };
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ // packing is always 4
+ uint8_t t8[] = {
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF };
+
+ uint16_t t16[] = {
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
+
+ uint16_t t5551[] = {
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
+
+ uint32_t t32[] = {
+ 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+ 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
+ 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
+ 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+ };
+
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+ glDrawTexiOES(0, 0, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+ glDrawTexiOES(dim/2, 0, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+ glDrawTexiOES(0, dim/2, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+ glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
+
+ eglSwapBuffers(dpy, surface);
+ return 0;
+}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index d84572b..af0a1bd 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -2,6 +2,8 @@
package="com.android.providers.settings"
android:sharedUserId="android.uid.system">
+ <uses-permission android:name="android.permission.BACKUP_DATA" />
+
<application android:allowClearUserData="false"
android:label="@string/app_label"
android:process="system"
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
index 5af416a..734e0cd 100644
--- a/packages/SettingsProvider/etc/bookmarks.xml
+++ b/packages/SettingsProvider/etc/bookmarks.xml
@@ -39,10 +39,12 @@
package="com.android.calendar"
class="com.android.calendar.LaunchActivity"
shortcut="l" />
+<!--
<bookmark
package="com.google.android.apps.maps"
class="com.google.android.maps.MapsActivity"
shortcut="m" />
+-->
<bookmark
package="com.android.music"
class="com.android.music.MusicBrowserActivity"
diff --git a/packages/SettingsProvider/res/values-ja/strings.xml b/packages/SettingsProvider/res/values-ja/strings.xml
deleted file mode 100644
index ffd57e6..0000000
--- a/packages/SettingsProvider/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"ストレージの設定"</string>
-</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index f60ea57..6b20445 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -22,6 +22,7 @@
<bool name="def_airplane_mode_on">false</bool>
<!-- Comma-separated list of bluetooth, wifi, and cell. -->
<string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
+ <string name="airplane_mode_toggleable_radios" translatable="false">wifi</string>
<bool name="def_auto_time">true</bool>
<bool name="def_accelerometer_rotation">true</bool>
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
@@ -36,6 +37,7 @@
user opt-in via Setup Wizard or Settings.
-->
<string name="def_location_providers_allowed" translatable="false">gps</string>
+ <bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
<bool name="def_usb_mass_storage_enabled">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6dd1175..6a1f6f8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -56,7 +56,7 @@
* Database helper class for {@link SettingsProvider}.
* Mostly just has a bit {@link #onCreate} to initialize the database.
*/
-class DatabaseHelper extends SQLiteOpenHelper {
+public class DatabaseHelper extends SQLiteOpenHelper {
/**
* Path to file containing default bookmarks, relative to ANDROID_ROOT.
*/
@@ -64,7 +64,7 @@
private static final String TAG = "SettingsProvider";
private static final String DATABASE_NAME = "settings.db";
- private static final int DATABASE_VERSION = 35;
+ private static final int DATABASE_VERSION = 38;
private Context mContext;
@@ -389,6 +389,21 @@
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);
@@ -397,9 +412,44 @@
} finally {
db.endTransaction();
}
- 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.)
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'");
+ int newValue = (1 << AudioManager.STREAM_RING)
+ | (1 << AudioManager.STREAM_NOTIFICATION)
+ | (1 << AudioManager.STREAM_SYSTEM)
+ | (1 << AudioManager.STREAM_SYSTEM_ENFORCED);
+ db.execSQL("INSERT INTO system ('name', 'value') values ('"
+ + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '"
+ + String.valueOf(newValue) + "')");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 37;
+ }
+
+ if (upgradeVersion == 37) {
+ db.beginTransaction();
+ try {
+ SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+ R.string.airplane_mode_toggleable_radios);
+ stmt.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 38;
+ }
+
if (upgradeVersion != currentVersion) {
Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+ ", must wipe the settings provider");
@@ -560,7 +610,7 @@
// By default, only the ring/notification and system streams are affected
loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
(1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) |
- (1 << AudioManager.STREAM_SYSTEM));
+ (1 << AudioManager.STREAM_SYSTEM) | (1 << AudioManager.STREAM_SYSTEM_ENFORCED));
loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
((1 << AudioManager.STREAM_MUSIC) |
@@ -627,6 +677,9 @@
loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
R.string.def_airplane_mode_radios);
+ loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+ R.string.airplane_mode_toggleable_radios);
+
loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
R.bool.def_auto_time); // Sync time to NITZ
@@ -667,6 +720,9 @@
loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
R.string.def_location_providers_allowed);
+ loadBooleanSetting(stmt, Settings.Secure.ASSISTED_GPS_ENABLED,
+ R.bool.assisted_gps_enabled);
+
loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
R.integer.def_network_preference);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2b36904..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;
@@ -83,6 +83,11 @@
};
private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
+
+ // the key to store the WIFI data under, should be sorted as last, so restore happens last.
+ // use very late unicode character to quasi-guarantee last sort position.
+ private static final String KEY_WIFI_SUPPLICANT = "\uffeeWIFI";
+
private static final String FILE_BT_ROOT = "/data/misc/hcid/";
private SettingsHelper mSettingsHelper;
@@ -113,7 +118,7 @@
stateChecksums[STATE_LOCALE] =
writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
stateChecksums[STATE_WIFI] =
- writeIfChanged(stateChecksums[STATE_WIFI], FILE_WIFI_SUPPLICANT, wifiData, data);
+ writeIfChanged(stateChecksums[STATE_WIFI], KEY_WIFI_SUPPLICANT, wifiData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -122,7 +127,7 @@
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
- enableWifi(false);
+
enableBluetooth(false);
while (data.readNextHeader()) {
@@ -133,12 +138,16 @@
mSettingsHelper.applyAudioSettings();
} else if (KEY_SECURE.equals(key)) {
restoreSettings(data, Settings.Secure.CONTENT_URI);
- } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+ } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
+ int retainedWifiState = enableWifi(false);
restoreFile(FILE_WIFI_SUPPLICANT, data);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
FileUtils.S_IRUSR | FileUtils.S_IWUSR |
FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
+ // retain the previous WIFI state.
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
+ retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
} else if (KEY_SYNC.equals(key)) {
mSettingsHelper.setSyncProviders(data);
} else if (KEY_LOCALE.equals(key)) {
@@ -257,7 +266,7 @@
}
/**
- * Given a cursor sorted by key name and a set of keys sorted by name,
+ * Given a cursor sorted by key name and a set of keys sorted by name,
* extract the required keys and values and write them to a byte array.
* @param sortedCursor
* @param sortedKeys
@@ -373,15 +382,18 @@
return result;
}
- private void enableWifi(boolean enable) {
+ private int enableWifi(boolean enable) {
WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wfm != null) {
+ int state = wfm.getWifiState();
wfm.setWifiEnabled(enable);
+ return state;
}
+ return WifiManager.WIFI_STATE_UNKNOWN;
}
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/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index ca739e6..b13883e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -118,16 +118,19 @@
byte[] getSyncProviders() {
byte[] sync = new byte[1 + PROVIDERS.length];
+ // TODO: Sync backup needs to be moved to SystemBackupAgent
+ /*
try {
sync[0] = (byte) (mContentService.getListenForNetworkTickles() ? 1 : 0);
for (int i = 0; i < PROVIDERS.length; i++) {
sync[i + 1] = (byte)
- (mContentService.getSyncProviderAutomatically(PROVIDERS[i]) ? 1 : 0);
+ (mContentService.getSyncAutomatically(PROVIDERS[i]) ? 1 : 0);
}
} catch (RemoteException re) {
Log.w(TAG, "Unable to backup sync providers");
return sync;
}
+ */
return sync;
}
@@ -136,12 +139,15 @@
try {
backup.readEntityData(sync, 0, sync.length);
+ // TODO: Sync backup needs to be moved to SystemBackupAgent
+ /*
mContentService.setListenForNetworkTickles(sync[0] == 1);
for (int i = 0; i < PROVIDERS.length; i++) {
mContentService.setSyncProviderAutomatically(PROVIDERS[i], sync[i + 1] > 0);
}
} catch (RemoteException re) {
Log.w(TAG, "Unable to restore sync providers");
+ */
} catch (java.io.IOException ioe) {
Log.w(TAG, "Unable to read sync settings");
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c0de9a5..9877342 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -24,9 +24,11 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
@@ -45,8 +47,7 @@
private static final String TABLE_FAVORITES = "favorites";
private static final String TABLE_OLD_FAVORITES = "old_favorites";
- private DatabaseHelper mOpenHelper;
-
+ protected DatabaseHelper mOpenHelper;
private BackupManager mBackupManager;
/**
@@ -398,12 +399,8 @@
// Get the current value for the default sound
Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
- if (soundUri == null) {
- // Fallback on any valid ringtone Uri
- soundUri = RingtoneManager.getValidRingtoneUri(context);
- }
- if (soundUri != null) {
+ if (soundUri != null) {
// Only proxy the openFile call to drm or media providers
String authority = soundUri.getAuthority();
boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
@@ -427,4 +424,64 @@
return super.openFile(uri, mode);
}
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+
+ /*
+ * When a client attempts to openFile the default ringtone or
+ * notification setting Uri, we will proxy the call to the current
+ * default ringtone's Uri (if it is in the DRM or media provider).
+ */
+ int ringtoneType = RingtoneManager.getDefaultType(uri);
+ // Above call returns -1 if the Uri doesn't match a default type
+ if (ringtoneType != -1) {
+ Context context = getContext();
+
+ // Get the current value for the default sound
+ Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
+
+ if (soundUri != null) {
+ // Only proxy the openFile call to drm or media providers
+ String authority = soundUri.getAuthority();
+ boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
+ if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
+
+ if (isDrmAuthority) {
+ try {
+ // Check DRM access permission here, since once we
+ // do the below call the DRM will be checking our
+ // permission, not our caller's permission
+ DrmStore.enforceAccessDrmPermission(context);
+ } catch (SecurityException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = context.getContentResolver().openFileDescriptor(soundUri, mode);
+ return new AssetFileDescriptor(pfd, 0, -1);
+ } catch (FileNotFoundException ex) {
+ // fall through and open the fallback ringtone below
+ }
+ }
+
+ try {
+ return super.openAssetFile(soundUri, mode);
+ } catch (FileNotFoundException ex) {
+ // Since a non-null Uri was specified, but couldn't be opened,
+ // fall back to the built-in ringtone.
+ return context.getResources().openRawResourceFd(
+ com.android.internal.R.raw.fallbackring);
+ }
+ }
+ // no need to fall through and have openFile() try again, since we
+ // already know that will fail.
+ throw new FileNotFoundException(); // or return null ?
+ }
+
+ // Note that this will end up calling openFile() above.
+ return super.openAssetFile(uri, mode);
+ }
}
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index ca00a9b..d839c4e 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
<receiver android:name="SubscribedFeedsBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="GSYNC_TICKLE"/>
</intent-filter>
<intent-filter>
diff --git a/packages/SubscribedFeedsProvider/res/values-cs/strings.xml b/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
index 46de1b1..9b782b0 100644
--- a/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronizace zdrojů"</string>
+ <string name="app_label">"Synchronizace zdrojů"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-de/strings.xml b/packages/SubscribedFeedsProvider/res/values-de/strings.xml
index 7e39aa8..1ade594 100644
--- a/packages/SubscribedFeedsProvider/res/values-de/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Feedsynchronisierung"</string>
+ <string name="app_label">"Feedsynchronisierung"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-es/strings.xml b/packages/SubscribedFeedsProvider/res/values-es/strings.xml
index 9165f65..86c6946 100644
--- a/packages/SubscribedFeedsProvider/res/values-es/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Sincronización de feeds"</string>
+ <string name="app_label">"Sincronización de feeds"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-fr/strings.xml b/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
index f022e70..924b960 100644
--- a/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronisation des flux"</string>
+ <string name="app_label">"Synchronisation des flux"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-it/strings.xml b/packages/SubscribedFeedsProvider/res/values-it/strings.xml
index 1053314..eabb17e 100644
--- a/packages/SubscribedFeedsProvider/res/values-it/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Sincronizzazione feed"</string>
+ <string name="app_label">"Sincronizzazione feed"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-ja/strings.xml b/packages/SubscribedFeedsProvider/res/values-ja/strings.xml
deleted file mode 100644
index b8f2d09..0000000
--- a/packages/SubscribedFeedsProvider/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"フィードの同期"</string>
-</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-nl/strings.xml b/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
index 7dc5495..b9e82d1 100644
--- a/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Feeds synchroniseren"</string>
+ <string name="app_label">"Feeds synchroniseren"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-pl/strings.xml b/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
index 32c4a5e..02da9f3 100644
--- a/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronizowanie kanałów"</string>
+ <string name="app_label">"Synchronizowanie kanałów"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml b/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
index 15307aa..e6643cd 100644
--- a/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"同步資訊提供"</string>
+ <string name="app_label">"同步資訊提供"</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 8b3bedf..b854f86 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -16,13 +16,14 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.os.Bundle;
-import android.os.RemoteException;
import android.text.TextUtils;
-import android.net.Uri;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Calendar;
+import com.google.android.collect.Lists;
+
/**
* A service to handle various intents asynchronously.
*/
@@ -30,7 +31,8 @@
private static final String TAG = "Sync";
private static final String[] sAccountProjection =
- new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
+ new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE};
/** How often to refresh the subscriptions, in milliseconds */
private static final long SUBSCRIPTION_REFRESH_INTERVAL = 1000L * 60 * 60 * 24; // one day
@@ -39,8 +41,7 @@
private static final String sSubscribedFeedsPrefs = "subscribedFeeds";
- private static final String GTALK_DATA_MESSAGE_RECEIVED =
- "android.intent.action.GTALK_DATA_MESSAGE_RECEIVED";
+ private static final String REMOTE_INTENT_ACTION = Intent.ACTION_REMOTE_INTENT;
private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
"com.android.subscribedfeeds.action.REFRESH";
@@ -52,13 +53,14 @@
}
protected void onHandleIntent(Intent intent) {
- if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
- boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
+ if (REMOTE_INTENT_ACTION.equals(intent.getAction())) {
+ boolean fromTrustedServer = intent.getBooleanExtra(
+ "android.intent.extra.from_trusted_server", false);
if (fromTrustedServer) {
- String account = intent.getStringExtra("account");
- String token = intent.getStringExtra("message_token");
+ String accountName = intent.getStringExtra("account");
+ String token = intent.getStringExtra(Intent.EXTRA_REMOTE_INTENT_TOKEN);
- if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
+ if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(token)) {
if (Config.LOGD) {
Log.d(TAG, "Ignoring malformed tickle -- missing account or token.");
}
@@ -67,10 +69,10 @@
if (Config.LOGD) {
Log.d(TAG, "Received network tickle for "
- + account + " - " + token);
+ + accountName + " - " + token);
}
- handleTickle(this, account, token);
+ handleTickle(this, accountName, token);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Ignoring tickle -- not from trusted server.");
@@ -102,16 +104,19 @@
alarmManager.set(AlarmManager.RTC, when, pendingIntent);
}
- private void handleTickle(Context context, String account, String feed) {
+ private void handleTickle(Context context, String accountName, String feed) {
Cursor c = null;
final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? "
+ + "and " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "= ? "
+ "and " + SubscribedFeeds.Feeds.FEED + "= ?";
try {
+ // 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, 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 " + account + ", feed " + feed);
+ + "account " + accountName + ", feed " + feed);
EventLog.writeEvent(LOG_TICKLE, "unknown");
}
while (c.moveToNext()) {
@@ -119,21 +124,14 @@
String authority = c.getString(c.getColumnIndexOrThrow(
SubscribedFeeds.Feeds.AUTHORITY));
EventLog.writeEvent(LOG_TICKLE, authority);
- try {
- if (!ContentResolver.getContentService()
- .getSyncProviderAutomatically(authority)) {
- Log.d(TAG, "supressing tickle since provider " + authority
- + " is configured to not sync automatically");
- continue;
- }
- } catch (RemoteException e) {
+ if (!ContentResolver.getSyncAutomatically(account, authority)) {
+ Log.d(TAG, "supressing tickle since provider " + authority
+ + " is configured to not sync automatically");
continue;
}
- Uri uri = Uri.parse("content://" + authority);
Bundle extras = new Bundle();
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
extras.putString("feed", feed);
- context.getContentResolver().startSync(uri, extras);
+ ContentResolver.requestSync(account, authority, extras);
}
} finally {
if (c != null) c.deactivate();
@@ -150,31 +148,35 @@
*/
private void handleRefreshAlarm(Context context) {
// retrieve the list of accounts from the subscribed feeds
- ArrayList<String> accounts = new ArrayList<String>();
+ ArrayList<Account> accounts = Lists.newArrayList();
ContentResolver contentResolver = context.getContentResolver();
Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
sAccountProjection, null, null, null);
- while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
- continue;
+ try {
+ while (c.moveToNext()) {
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ accounts.add(new Account(accountName, accountType));
}
- accounts.add(account);
+ } finally {
+ c.close();
}
- c.deactivate();
// Clear the auth tokens for all these accounts so that we are sure
// they will still be valid until the next time we refresh them.
- // TODO: add this when the google login service is done
+ // TODO(fredq): add this when the google login service is done
// mark the feeds dirty, by setting the accounts to the same value,
// which will trigger a sync.
try {
ContentValues values = new ContentValues();
- for (String account : accounts) {
- values.put(SyncConstValue._SYNC_ACCOUNT, account);
+ for (Account account : accounts) {
+ 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 + "=?", new String[] {account});
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND "
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
+ 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 9ecc3d6..d87f5e7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -39,7 +39,7 @@
public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
private static final String TAG = "SubscribedFeedsProvider";
private static final String DATABASE_NAME = "subscribedfeeds.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
private static final int FEEDS = 1;
private static final int FEED_ID = 2;
@@ -88,6 +88,7 @@
db.execSQL("CREATE TABLE feeds (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," + // From the sync source
+ "_sync_account_type TEXT," + // From the sync source
"_sync_id TEXT," + // From the sync source
"_sync_time TEXT," + // From the sync source
"_sync_version TEXT," + // From the sync source
@@ -106,8 +107,8 @@
"WHEN old._sync_id is not null " +
"BEGIN " +
"INSERT INTO _deleted_feeds " +
- "(_sync_id, _sync_account, _sync_version) " +
- "VALUES (old._sync_id, old._sync_account, " +
+ "(_sync_id, _sync_account, _sync_account_type, _sync_version) " +
+ "VALUES (old._sync_id, old._sync_account, old._sync_account_type, " +
"old._sync_version);" +
"END");
@@ -116,6 +117,7 @@
"_sync_id TEXT," +
(isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"_sync_mark INTEGER, " + // Used to filter out new rows
"UNIQUE(_sync_id))");
}
@@ -170,7 +172,8 @@
qb.setDistinct(true);
qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
return qb.query(getDatabase(), projection, selection, selectionArgs,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + ","
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
case FEED_ID:
qb.setTables(sFeedsTable);
qb.appendWhere(sFeedsTable + "._id=");
@@ -310,6 +313,8 @@
DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_ACCOUNT, mValues);
DatabaseUtils.cursorStringToContentValues(diffsCursor,
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, mValues);
+ DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
db.replace(mDeletedTable, SubscribedFeeds.Feeds._SYNC_ID, mValues);
}
@@ -369,5 +374,7 @@
ACCOUNTS_PROJECTION_MAP = map;
map.put(SubscribedFeeds.Accounts._COUNT, "COUNT(*) AS _count");
map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT, SubscribedFeeds.Accounts._SYNC_ACCOUNT);
+ map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE);
}
}
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 1bab717..1793587 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -153,7 +153,7 @@
AudioTrack* mAudioOut;
AudioSystem::stream_type mStreamType;
uint32_t mSampleRate;
- AudioSystem::audio_format mAudFormat;
+ uint32_t mAudFormat;
int mNbChannels;
int8_t * mBuffer;
size_t mBufferSize;
@@ -200,7 +200,6 @@
mSampleRate = rate;
mAudFormat = format;
mNbChannels = channel;
-
mStreamType = streamType;
// retrieve system properties to ensure successful creation of the
@@ -221,7 +220,8 @@
if (minBufCount < 2) minBufCount = 2;
int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
- mAudioOut = new AudioTrack(mStreamType, rate, format, channel,
+ mAudioOut = new AudioTrack(mStreamType, rate, format,
+ (channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
minFrameCount > 4096 ? minFrameCount : 4096,
0, 0, 0, 0); // not using an AudioTrack callback
@@ -264,7 +264,7 @@
* Directly speaks using AudioTrack or write to file
*/
static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
- AudioSystem::audio_format format, int channel,
+ uint32_t format, int channel,
int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
//LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
@@ -284,7 +284,7 @@
}
if (bufferSize > 0) {
- prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
+ prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
applyFilter((int16_t*)wav, bufferSize/2);
pJniData->mAudioOut->write(wav, bufferSize);
diff --git a/packages/VpnServices/res/values-cs/strings.xml b/packages/VpnServices/res/values-cs/strings.xml
index 58e211d..5f3522d 100644
--- a/packages/VpnServices/res/values-cs/strings.xml
+++ b/packages/VpnServices/res/values-cs/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Služby VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"Síť VPN %s připojena"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"Síť VPN %s odpojena"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotykem se znovu připojíte k síti VPN."</string>
+ <string name="app_label">"Služby VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-de/strings.xml b/packages/VpnServices/res/values-de/strings.xml
index 23558bb..93fa474 100644
--- a/packages/VpnServices/res/values-de/strings.xml
+++ b/packages/VpnServices/res/values-de/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN-Dienste"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN \"%s\" verbunden"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN \"%s \" getrennt"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Zur Wiederherstellung der Verbindung mit einem VPN berühren"</string>
+ <string name="app_label">"VPN-Dienste"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-es/strings.xml b/packages/VpnServices/res/values-es/strings.xml
index bc7e536..bb4f348 100644
--- a/packages/VpnServices/res/values-es/strings.xml
+++ b/packages/VpnServices/res/values-es/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Servicios VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s conectada"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s desconectada"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toca para volver a conectarte a una red VPN."</string>
+ <string name="app_label">"Servicios VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-fr/strings.xml b/packages/VpnServices/res/values-fr/strings.xml
index 5db5050..4395d03 100644
--- a/packages/VpnServices/res/values-fr/strings.xml
+++ b/packages/VpnServices/res/values-fr/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Services VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s connecté"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s déconnecté"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Touchez l\'écran pour vous reconnecter à un VPN."</string>
+ <string name="app_label">"Services VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-it/strings.xml b/packages/VpnServices/res/values-it/strings.xml
index cc2a4eb..76e0214 100644
--- a/packages/VpnServices/res/values-it/strings.xml
+++ b/packages/VpnServices/res/values-it/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Servizi VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s collegata"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s scollegata"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tocca per riconnetterti a una rete VPN."</string>
+ <string name="app_label">"Servizi VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-ja/strings.xml b/packages/VpnServices/res/values-ja/strings.xml
deleted file mode 100644
index 1158347..0000000
--- a/packages/VpnServices/res/values-ja/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPNサービス"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPNが接続されました"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPNが切断されました"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"タップしてVPNに再接続してください。"</string>
-</resources>
diff --git a/packages/VpnServices/res/values-nl/strings.xml b/packages/VpnServices/res/values-nl/strings.xml
index 359cfe9..9a50f3b 100644
--- a/packages/VpnServices/res/values-nl/strings.xml
+++ b/packages/VpnServices/res/values-nl/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN-services"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPN verbonden"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPN-verbinding verbroken"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Raak aan om opnieuw verbinding te maken met een VPN."</string>
+ <string name="app_label">"VPN-services"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-pl/strings.xml b/packages/VpnServices/res/values-pl/strings.xml
index 17d1dab..d2e8c60 100644
--- a/packages/VpnServices/res/values-pl/strings.xml
+++ b/packages/VpnServices/res/values-pl/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Usługi VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"Połączono z siecią VPN %s"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"Rozłączono z siecią VPN %s"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotknij, aby ponownie połączyć się z siecią VPN."</string>
+ <string name="app_label">"Usługi VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-zh-rTW/strings.xml b/packages/VpnServices/res/values-zh-rTW/strings.xml
index ad8eddf..021077b 100644
--- a/packages/VpnServices/res/values-zh-rTW/strings.xml
+++ b/packages/VpnServices/res/values-zh-rTW/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN 服務"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPN 已連線"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPN 已中斷連線"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"輕觸即可重新連線至 VPN。"</string>
+ <string name="app_label">"VPN 服務"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/preloaded-classes b/preloaded-classes
index 7d1f960..6eb3cf2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,52 +1,26 @@
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
-# Automatically generated by /frameworks/base/tools/preload.
-# percent=75, weight=500, bucket_size=5
-SQLite.Blob
-SQLite.Database
-SQLite.FunctionContext
-SQLite.Stmt
-SQLite.Vm
android.R$styleable
-android.accounts.AccountMonitor
-android.accounts.AccountMonitor$AccountUpdater
-android.accounts.AccountMonitorListener
-android.accounts.AccountsServiceConstants
-android.accounts.IAccountsService
-android.accounts.IAccountsService$Stub
android.app.Activity
-android.app.Activity$ManagedCursor
android.app.ActivityGroup
+android.app.ActivityManager$MemoryInfo$1
android.app.ActivityManagerNative
android.app.ActivityManagerProxy
android.app.ActivityThread
android.app.ActivityThread$ActivityRecord
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
-android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
-android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
android.app.ActivityThread$Idler
-android.app.ActivityThread$NewIntentData
android.app.ActivityThread$PackageInfo
android.app.ActivityThread$PackageInfo$ReceiverDispatcher
-android.app.ActivityThread$PackageInfo$ReceiverDispatcher$Args
android.app.ActivityThread$PackageInfo$ReceiverDispatcher$InnerReceiver
android.app.ActivityThread$PackageInfo$ServiceDispatcher
-android.app.ActivityThread$PackageInfo$ServiceDispatcher$ConnectionInfo
-android.app.ActivityThread$PackageInfo$ServiceDispatcher$DeathMonitor
android.app.ActivityThread$PackageInfo$ServiceDispatcher$InnerConnection
-android.app.ActivityThread$PackageInfo$ServiceDispatcher$RunConnection
android.app.ActivityThread$ProviderRecord
android.app.ActivityThread$ProviderRefCount
-android.app.ActivityThread$ReceiverData
-android.app.ActivityThread$ResourcesKey
-android.app.ActivityThread$ResultData
-android.app.ActivityThread$ServiceArgsData
-android.app.ActivityThread$StopInfo
android.app.AlertDialog
-android.app.AlertDialog$Builder
android.app.Application
android.app.ApplicationContext
android.app.ApplicationContext$ApplicationContentResolver
@@ -54,43 +28,27 @@
android.app.ApplicationContext$ApplicationPackageManager$PackageRemovedReceiver
android.app.ApplicationContext$ApplicationPackageManager$ResourceName
android.app.ApplicationContext$SharedPreferencesImpl
-android.app.ApplicationContext$SharedPreferencesImpl$EditorImpl
android.app.ApplicationLoaders
android.app.ApplicationThreadNative
android.app.Dialog
-android.app.Dialog$1
-android.app.Dialog$ListenersHandler
android.app.ExpandableListActivity
android.app.IActivityManager
-android.app.IActivityManager$ContentProviderHolder
android.app.IActivityManager$ContentProviderHolder$1
-android.app.IAlarmManager
android.app.IAlarmManager$Stub
android.app.IAlarmManager$Stub$Proxy
android.app.IApplicationThread
-android.app.IInstrumentationWatcher
-android.app.IInstrumentationWatcher$Stub
-android.app.INotificationManager
android.app.INotificationManager$Stub
android.app.INotificationManager$Stub$Proxy
android.app.ISearchManager
android.app.ISearchManager$Stub
android.app.ISearchManager$Stub$Proxy
-android.app.ISearchManagerCallback
-android.app.ISearchManagerCallback$Stub
-android.app.IServiceConnection
-android.app.IServiceConnection$Stub
-android.app.ITransientNotification
-android.app.ITransientNotification$Stub
android.app.Instrumentation
android.app.IntentReceiverLeaked
android.app.ListActivity
android.app.ListActivity$1
android.app.ListActivity$2
android.app.LocalActivityManager
-android.app.LocalActivityManager$LocalActivityRecord
android.app.Notification
-android.app.Notification$1
android.app.NotificationManager
android.app.PendingIntent
android.app.PendingIntent$1
@@ -98,585 +56,249 @@
android.app.ReceiverRestrictedContext
android.app.ResultInfo
android.app.ResultInfo$1
-android.app.SearchManager$SearchManagerCallback
-android.app.SearchManager$SearchManagerCallback$1
-android.app.SearchManager$SearchManagerCallback$2
+android.app.SearchDialog
+android.app.SearchDialog$SearchAutoComplete
android.app.Service
android.app.ServiceConnectionLeaked
android.app.TabActivity
-android.appwidget.AppWidgetHostView
-android.appwidget.AppWidgetManager
-android.appwidget.AppWidgetProvider
-android.backup.BackupDataInput
-android.backup.BackupDataInput$EntityHeader
-android.backup.BackupDataOutput
-android.backup.BackupHelperDispatcher
-android.backup.BackupHelperDispatcher$Header
-android.backup.FileBackupHelperBase
-android.bluetooth.BluetoothA2dp
-android.bluetooth.BluetoothAudioGateway
-android.bluetooth.BluetoothDevice
-android.bluetooth.Database
-android.bluetooth.HeadsetBase
-android.bluetooth.IBluetoothA2dp
-android.bluetooth.IBluetoothA2dp$Stub
-android.bluetooth.IBluetoothDevice
-android.bluetooth.IBluetoothDevice$Stub
-android.bluetooth.IBluetoothDevice$Stub$Proxy
-android.bluetooth.RfcommSocket
-android.bluetooth.ScoSocket
-android.content.AsyncQueryHandler
-android.content.AsyncQueryHandler$WorkerArgs
+android.content.AbstractSyncableContentProvider
+android.content.AbstractTableMerger
android.content.AsyncQueryHandler$WorkerHandler
android.content.BroadcastReceiver
android.content.ComponentCallbacks
android.content.ComponentName
android.content.ComponentName$1
-android.content.ContentProvider
android.content.ContentProvider$Transport
-android.content.ContentProviderNative
android.content.ContentProviderProxy
android.content.ContentQueryMap
android.content.ContentQueryMap$1
android.content.ContentResolver
android.content.ContentResolver$CursorWrapperInner
-android.content.ContentResolver$ParcelFileDescriptorInner
-android.content.ContentUris
android.content.ContentValues
-android.content.ContentValues$1
android.content.Context
android.content.ContextWrapper
android.content.DialogInterface
android.content.DialogInterface$OnCancelListener
-android.content.DialogInterface$OnClickListener
android.content.DialogInterface$OnDismissListener
-android.content.DialogInterface$OnKeyListener
-android.content.DialogInterface$OnMultiChoiceClickListener
android.content.IContentProvider
android.content.IContentService
android.content.IContentService$Stub
-android.content.IContentService$Stub$Proxy
-android.content.IIntentReceiver
-android.content.IIntentReceiver$Stub
-android.content.IIntentSender
-android.content.IIntentSender$Stub
-android.content.IIntentSender$Stub$Proxy
-android.content.ISyncAdapter
-android.content.ISyncAdapter$Stub
android.content.Intent
android.content.Intent$1
android.content.IntentFilter
-android.content.IntentFilter$1
android.content.SearchRecentSuggestionsProvider
-android.content.SearchRecentSuggestionsProvider$DatabaseHelper
android.content.ServiceConnection
android.content.SharedPreferences
-android.content.SharedPreferences$Editor
-android.content.SharedPreferences$OnSharedPreferenceChangeListener
-android.content.SyncAdapter
-android.content.SyncAdapter$Transport
-android.content.SyncContext
android.content.SyncResult
+android.content.SyncResult$1
android.content.SyncStats
+android.content.SyncStats$1
+android.content.SyncableContentProvider
android.content.UriMatcher
android.content.pm.ActivityInfo
android.content.pm.ActivityInfo$1
android.content.pm.ApplicationInfo
android.content.pm.ApplicationInfo$1
android.content.pm.ComponentInfo
-android.content.pm.ConfigurationInfo
-android.content.pm.ConfigurationInfo$1
-android.content.pm.IPackageDeleteObserver$Stub
android.content.pm.IPackageManager
android.content.pm.IPackageManager$Stub
android.content.pm.IPackageManager$Stub$Proxy
android.content.pm.InstrumentationInfo
android.content.pm.InstrumentationInfo$1
-android.content.pm.PackageInfo
-android.content.pm.PackageInfo$1
android.content.pm.PackageItemInfo
android.content.pm.PackageManager
-android.content.pm.PathPermission
-android.content.pm.PathPermission$1
+android.content.pm.PackageManager$NameNotFoundException
android.content.pm.PermissionInfo
-android.content.pm.PermissionInfo$1
android.content.pm.ProviderInfo
android.content.pm.ProviderInfo$1
-android.content.pm.ResolveInfo
android.content.pm.ResolveInfo$1
-android.content.pm.ServiceInfo
android.content.pm.ServiceInfo$1
-android.content.pm.Signature
-android.content.pm.Signature$1
-android.content.res.AssetFileDescriptor
-android.content.res.AssetFileDescriptor$1
android.content.res.AssetManager
android.content.res.AssetManager$AssetInputStream
android.content.res.ColorStateList
android.content.res.ColorStateList$1
-android.content.res.CompatibilityInfo
-android.content.res.CompatibilityInfo$1
-android.content.res.CompatibilityInfo$Translator
android.content.res.Configuration
-android.content.res.Configuration$1
-android.content.res.PluralRules
-android.content.res.PluralRules$en
android.content.res.Resources
-android.content.res.Resources$1
android.content.res.Resources$Theme
android.content.res.StringBlock
-android.content.res.StringBlock$StyleIDs
android.content.res.TypedArray
android.content.res.XmlBlock
android.content.res.XmlBlock$Parser
-android.content.res.XmlResourceParser
android.database.AbstractCursor
android.database.AbstractCursor$SelfContentObserver
android.database.AbstractWindowedCursor
android.database.BulkCursorNative
android.database.BulkCursorProxy
android.database.BulkCursorToCursorAdaptor
-android.database.CharArrayBuffer
android.database.ContentObservable
-android.database.ContentObserver
-android.database.ContentObserver$NotificationRunnable
android.database.ContentObserver$Transport
-android.database.CrossProcessCursor
android.database.Cursor
android.database.CursorToBulkCursorAdaptor
android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
android.database.CursorWindow
-android.database.CursorWindow$1
android.database.CursorWrapper
android.database.DataSetObservable
-android.database.DataSetObserver
-android.database.DatabaseUtils
-android.database.DatabaseUtils$InsertHelper
-android.database.IBulkCursor
-android.database.IContentObserver
-android.database.IContentObserver$Stub
android.database.IContentObserver$Stub$Proxy
-android.database.MatrixCursor
-android.database.Observable
-android.database.SQLException
-android.database.sqlite.SQLiteClosable
+android.database.MergeCursor
android.database.sqlite.SQLiteCursor
-android.database.sqlite.SQLiteCursorDriver
android.database.sqlite.SQLiteDatabase
android.database.sqlite.SQLiteDatabase$CursorFactory
-android.database.sqlite.SQLiteDebug
-android.database.sqlite.SQLiteDebug$PagerStats
android.database.sqlite.SQLiteDirectCursorDriver
-android.database.sqlite.SQLiteException
-android.database.sqlite.SQLiteOpenHelper
-android.database.sqlite.SQLiteProgram
android.database.sqlite.SQLiteQuery
-android.database.sqlite.SQLiteQueryBuilder
android.database.sqlite.SQLiteStatement
android.ddm.DdmHandleAppName
android.ddm.DdmHandleExit
android.ddm.DdmHandleHeap
android.ddm.DdmHandleHello
android.ddm.DdmHandleNativeHeap
-android.ddm.DdmHandleProfiling
android.ddm.DdmHandleThread
android.ddm.DdmRegister
-android.debug.JNITest
-android.emoji.EmojiFactory
-android.graphics.AvoidXfermode
android.graphics.Bitmap
-android.graphics.Bitmap$1
-android.graphics.Bitmap$CompressFormat
-android.graphics.Bitmap$Config
-android.graphics.BitmapFactory
-android.graphics.BitmapFactory$Options
android.graphics.BitmapShader
-android.graphics.BlurMaskFilter
-android.graphics.Camera
android.graphics.Canvas
android.graphics.Canvas$EdgeType
android.graphics.Color
-android.graphics.ColorFilter
-android.graphics.ColorMatrixColorFilter
-android.graphics.ComposePathEffect
-android.graphics.ComposeShader
-android.graphics.CornerPathEffect
-android.graphics.DashPathEffect
-android.graphics.DiscretePathEffect
-android.graphics.DrawFilter
-android.graphics.EmbossMaskFilter
android.graphics.Interpolator
-android.graphics.LayerRasterizer
-android.graphics.LightingColorFilter
android.graphics.LinearGradient
-android.graphics.MaskFilter
android.graphics.Matrix
android.graphics.Matrix$ScaleToFit
-android.graphics.Movie
android.graphics.NinePatch
android.graphics.Paint
-android.graphics.Paint$Align
-android.graphics.Paint$Cap
-android.graphics.Paint$FontMetrics
-android.graphics.Paint$FontMetricsInt
-android.graphics.Paint$Join
-android.graphics.Paint$Style
android.graphics.PaintFlagsDrawFilter
android.graphics.Path
android.graphics.Path$Direction
-android.graphics.Path$FillType
-android.graphics.PathDashPathEffect
-android.graphics.PathEffect
-android.graphics.PathMeasure
android.graphics.Picture
-android.graphics.PixelFormat
-android.graphics.PixelXorXfermode
-android.graphics.Point
-android.graphics.PointF
+android.graphics.PorterDuff
android.graphics.PorterDuff$Mode
-android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
-android.graphics.RadialGradient
-android.graphics.Rasterizer
android.graphics.Rect
-android.graphics.Rect$1
android.graphics.RectF
-android.graphics.RectF$1
android.graphics.Region
-android.graphics.Region$1
android.graphics.Region$Op
-android.graphics.RegionIterator
android.graphics.Shader
android.graphics.Shader$TileMode
-android.graphics.SumPathEffect
-android.graphics.SweepGradient
-android.graphics.TemporaryBuffer
android.graphics.Typeface
android.graphics.Xfermode
-android.graphics.drawable.Animatable
-android.graphics.drawable.AnimatedRotateDrawable
-android.graphics.drawable.AnimatedRotateDrawable$AnimatedRotateState
android.graphics.drawable.AnimationDrawable
-android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
android.graphics.drawable.BitmapDrawable$BitmapState
-android.graphics.drawable.ClipDrawable
-android.graphics.drawable.ClipDrawable$ClipState
android.graphics.drawable.ColorDrawable
android.graphics.drawable.ColorDrawable$ColorState
android.graphics.drawable.Drawable
-android.graphics.drawable.Drawable$Callback
-android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
-android.graphics.drawable.DrawableContainer$DrawableContainerState
android.graphics.drawable.GradientDrawable
-android.graphics.drawable.GradientDrawable$1
-android.graphics.drawable.GradientDrawable$GradientState
-android.graphics.drawable.GradientDrawable$Orientation
android.graphics.drawable.LayerDrawable
android.graphics.drawable.LayerDrawable$ChildDrawable
android.graphics.drawable.LayerDrawable$LayerState
android.graphics.drawable.NinePatchDrawable
android.graphics.drawable.NinePatchDrawable$NinePatchState
android.graphics.drawable.PaintDrawable
+android.graphics.drawable.RotateDrawable
+android.graphics.drawable.RotateDrawable$RotateState
+android.graphics.drawable.ScaleDrawable
+android.graphics.drawable.ScaleDrawable$ScaleState
android.graphics.drawable.ShapeDrawable
android.graphics.drawable.ShapeDrawable$ShapeState
android.graphics.drawable.StateListDrawable
android.graphics.drawable.StateListDrawable$StateListState
android.graphics.drawable.TransitionDrawable
android.graphics.drawable.TransitionDrawable$TransitionState
-android.graphics.drawable.shapes.RectShape
android.graphics.drawable.shapes.RoundRectShape
-android.graphics.drawable.shapes.Shape
-android.hardware.Camera
-android.hardware.ISensorService
-android.hardware.ISensorService$Stub
-android.hardware.ISensorService$Stub$Proxy
-android.hardware.Sensor
-android.hardware.SensorEvent
-android.hardware.SensorEventListener
-android.hardware.SensorListener
android.hardware.SensorManager
-android.hardware.SensorManager$1
-android.hardware.SensorManager$LegacyListener
-android.hardware.SensorManager$ListenerDelegate
-android.hardware.SensorManager$ListenerDelegate$1
-android.hardware.SensorManager$LmsFilter
-android.hardware.SensorManager$SensorThread
-android.hardware.SensorManager$SensorThread$SensorThreadRunnable
-android.inputmethodservice.ExtractEditText
-android.inputmethodservice.InputMethodService
android.inputmethodservice.KeyboardView
-android.location.Address
-android.location.Address$1
-android.location.Geocoder
-android.location.GpsSatellite
-android.location.GpsStatus
-android.location.GpsStatus$1
-android.location.ILocationListener
-android.location.ILocationListener$Stub
-android.location.ILocationManager
android.location.ILocationManager$Stub
-android.location.ILocationManager$Stub$Proxy
-android.location.ILocationProvider
-android.location.ILocationProvider$Stub
android.location.Location
-android.location.Location$1
-android.location.LocationListener
-android.location.LocationManager
-android.location.LocationManager$ListenerTransport
-android.location.LocationManager$ListenerTransport$1
-android.location.LocationProvider
-android.media.AmrInputStream
-android.media.AudioFormat
android.media.AudioManager
-android.media.AudioRecord
-android.media.AudioSystem
-android.media.AudioTrack
-android.media.ExifInterface
-android.media.FaceDetector
-android.media.IAudioService
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
-android.media.JetPlayer
-android.media.MediaMetadataRetriever
-android.media.MediaPlayer
-android.media.MediaPlayer$EventHandler
-android.media.MediaPlayer$OnBufferingUpdateListener
-android.media.MediaPlayer$OnCompletionListener
-android.media.MediaPlayer$OnErrorListener
-android.media.MediaPlayer$OnPreparedListener
-android.media.MediaRecorder
-android.media.MediaScanner
-android.media.ResampleInputStream
-android.media.RingtoneManager
-android.media.ToneGenerator
-android.net.ConnectivityManager
-android.net.Credentials
-android.net.DhcpInfo
-android.net.DhcpInfo$1
-android.net.IConnectivityManager
-android.net.IConnectivityManager$Stub
-android.net.IConnectivityManager$Stub$Proxy
-android.net.LocalServerSocket
android.net.LocalSocket
+android.net.LocalSocketAddress
+android.net.LocalSocketAddress$Namespace
android.net.LocalSocketImpl
android.net.LocalSocketImpl$SocketInputStream
android.net.LocalSocketImpl$SocketOutputStream
-android.net.NetworkConnectivityListener
-android.net.NetworkConnectivityListener$ConnectivityBroadcastReceiver
android.net.NetworkConnectivityListener$State
android.net.NetworkInfo
-android.net.NetworkInfo$1
android.net.NetworkInfo$DetailedState
-android.net.NetworkInfo$State
-android.net.NetworkUtils
+android.net.SSLCertificateSocketFactory
android.net.Uri
android.net.Uri$1
android.net.Uri$AbstractHierarchicalUri
android.net.Uri$AbstractPart
-android.net.Uri$Builder
android.net.Uri$HierarchicalUri
android.net.Uri$OpaqueUri
android.net.Uri$Part
android.net.Uri$Part$EmptyPart
android.net.Uri$PathPart
android.net.Uri$PathSegments
-android.net.Uri$PathSegmentsBuilder
android.net.Uri$StringUri
android.net.WebAddress
android.net.http.AndroidHttpClient
android.net.http.AndroidHttpClient$1
android.net.http.AndroidHttpClient$2
android.net.http.AndroidHttpClient$CurlLogger
-android.net.http.AndroidHttpClient$LoggingConfiguration
+android.net.http.DomainNameChecker
android.net.http.CertificateChainValidator
android.net.http.EventHandler
-android.net.http.Headers
-android.net.http.Headers$HeaderCallback
android.net.http.HttpsConnection
-android.net.vpn.IVpnService$Stub
-android.net.vpn.VpnManager
-android.net.vpn.VpnType
-android.net.wifi.IWifiManager
+android.net.http.RequestQueue
+android.net.http.SslError
android.net.wifi.IWifiManager$Stub
-android.net.wifi.IWifiManager$Stub$Proxy
-android.net.wifi.WifiManager
-android.net.wifi.WifiNative
-android.opengl.GLES10
-android.opengl.GLES10Ext
-android.opengl.GLES11
-android.opengl.GLES11Ext
-android.opengl.GLUtils
-android.opengl.Matrix
-android.opengl.Visibility
-android.os.Base64Utils
+android.net.wifi.SupplicantState
+android.net.wifi.WifiConfiguration
+android.net.wifi.WifiInfo
+android.opengl.Material
android.os.Binder
android.os.BinderProxy
android.os.Build
-android.os.Build$VERSION
android.os.Bundle
android.os.Bundle$1
-android.os.Debug
-android.os.Debug$MemoryInfo
android.os.Environment
-android.os.Exec
-android.os.FileObserver$ObserverThread
android.os.FileUtils
-android.os.FileUtils$FileStatus
android.os.Handler
android.os.HandlerThread
-android.os.Hardware
android.os.IBinder
-android.os.IBinder$DeathRecipient
-android.os.ICheckinService
-android.os.ICheckinService$Stub
-android.os.ICheckinService$Stub$Proxy
-android.os.IHardwareService
android.os.IHardwareService$Stub
android.os.IHardwareService$Stub$Proxy
-android.os.IInterface
-android.os.IMessenger
-android.os.IPowerManager
android.os.IPowerManager$Stub
android.os.IPowerManager$Stub$Proxy
android.os.IServiceManager
android.os.Looper
-android.os.MemoryFile
android.os.Message
android.os.Message$1
android.os.MessageQueue
android.os.MessageQueue$IdleHandler
-android.os.NetStat
android.os.Parcel
-android.os.Parcel$1
-android.os.ParcelFileDescriptor
-android.os.ParcelFileDescriptor$1
-android.os.ParcelFileDescriptor$AutoCloseInputStream
-android.os.Parcelable
-android.os.Parcelable$Creator
android.os.PatternMatcher
android.os.PatternMatcher$1
-android.os.Power
android.os.PowerManager
android.os.PowerManager$WakeLock
android.os.PowerManager$WakeLock$1
android.os.Process
-android.os.RemoteException
android.os.ServiceManager
android.os.ServiceManagerNative
android.os.ServiceManagerProxy
-android.os.StatFs
-android.os.SystemClock
-android.os.SystemProperties
-android.os.UEventObserver
android.os.Vibrator
-android.pim.EventRecurrence
android.preference.CheckBoxPreference
android.preference.DialogPreference
android.preference.EditTextPreference
-android.preference.GenericInflater
-android.preference.GenericInflater$Parent
android.preference.ListPreference
-android.preference.ListPreference$1
-android.preference.OnDependencyChangeListener
android.preference.Preference
-android.preference.Preference$BaseSavedState
-android.preference.Preference$BaseSavedState$1
-android.preference.Preference$OnPreferenceChangeInternalListener
-android.preference.Preference$OnPreferenceChangeListener
-android.preference.Preference$OnPreferenceClickListener
android.preference.PreferenceActivity
-android.preference.PreferenceActivity$1
-android.preference.PreferenceCategory
android.preference.PreferenceGroup
android.preference.PreferenceGroupAdapter
-android.preference.PreferenceGroupAdapter$1
-android.preference.PreferenceInflater
android.preference.PreferenceManager
-android.preference.PreferenceManager$OnActivityDestroyListener
-android.preference.PreferenceManager$OnActivityResultListener
-android.preference.PreferenceManager$OnPreferenceTreeClickListener
android.preference.PreferenceScreen
android.preference.RingtonePreference
-android.provider.BaseColumns
-android.provider.Browser
-android.provider.Checkin
-android.provider.Checkin$Events$Tag
-android.provider.Checkin$Properties$Tag
-android.provider.Checkin$Stats
-android.provider.Checkin$Stats$Tag
-android.provider.Contacts$ContactMethods
-android.provider.Contacts$ContactMethodsColumns
-android.provider.Contacts$People
-android.provider.Contacts$PeopleColumns
-android.provider.Contacts$Phones
-android.provider.Contacts$PhonesColumns
-android.provider.Contacts$PresenceColumns
-android.provider.Downloads
-android.provider.Gmail
-android.provider.Gmail$LabelMap
-android.provider.Gmail$PersonalLevel
-android.provider.Gmail$Settings
-android.provider.Im$CommonPresenceColumns
-android.provider.Im$Provider
-android.provider.MediaStore$Audio$AudioColumns
-android.provider.MediaStore$Audio$Media
-android.provider.MediaStore$Images$Media
-android.provider.MediaStore$MediaColumns
-android.provider.SearchRecentSuggestions
-android.provider.Settings$Gservices
-android.provider.Settings$NameValueCache
-android.provider.Settings$NameValueTable
-android.provider.Settings$Secure
-android.provider.Settings$System
-android.provider.SubscribedFeeds$FeedColumns
-android.provider.SubscribedFeeds$Feeds
-android.provider.SyncConstValue
-android.provider.Telephony$Mms
-android.provider.Telephony$MmsSms
-android.provider.Telephony$MmsSms$PendingMessages
-android.provider.Telephony$Threads
-android.provider.UserDictionary$Words
-android.sax.Children
-android.sax.Children$Child
-android.sax.Element
-android.sax.EndTextElementListener
android.sax.RootElement
-android.sax.RootElement$Handler
-android.sax.StartElementListener
-android.security.Keystore
-android.security.Keystore$FileKeystore
-android.security.Md5MessageDigest
-android.security.MessageDigest
-android.security.ServiceCommand
-android.security.Sha1MessageDigest
-android.server.BluetoothA2dpService
-android.server.BluetoothDeviceService
-android.server.BluetoothEventLoop
-android.server.data.BuildData
-android.server.data.CrashData
-android.server.data.StackTraceElementData
-android.server.data.ThrowableData
android.server.search.SearchableInfo
android.server.search.SearchableInfo$1
-android.speech.IRecognitionService$Stub
-android.speech.srec.Recognizer
-android.speech.tts.ITts$Stub
-android.speech.tts.ITts$Stub$Proxy
-android.speech.tts.TextToSpeech
-android.telephony.CellLocation
android.telephony.PhoneNumberUtils
android.telephony.PhoneStateListener
-android.telephony.PhoneStateListener$1
-android.telephony.PhoneStateListener$2
android.telephony.ServiceState
-android.telephony.ServiceState$1
-android.telephony.SignalStrength
android.telephony.TelephonyManager
-android.telephony.gsm.GsmCellLocation
-android.text.AndroidCharacter
-android.text.Annotation
+android.telephony.SmsManager
+android.telephony.SmsMessage
android.text.AutoText
android.text.BoringLayout
android.text.BoringLayout$Metrics
@@ -687,9 +309,7 @@
android.text.GetChars
android.text.GraphicsOperations
android.text.Html$HtmlParser
-android.text.IClipboard$Stub
android.text.InputFilter
-android.text.InputType
android.text.Layout
android.text.Layout$Alignment
android.text.Layout$Directions
@@ -717,38 +337,25 @@
android.text.TextUtils$1
android.text.TextUtils$EllipsizeCallback
android.text.TextUtils$SimpleStringSplitter
-android.text.TextUtils$StringSplitter
android.text.TextUtils$TruncateAt
android.text.TextWatcher
-android.text.format.DateFormat
android.text.format.DateUtils
-android.text.format.Formatter
android.text.format.Time
android.text.method.ArrowKeyMovementMethod
android.text.method.BaseKeyListener
android.text.method.KeyListener
android.text.method.MetaKeyKeyListener
android.text.method.MovementMethod
-android.text.method.NumberKeyListener
-android.text.method.PasswordTransformationMethod
-android.text.method.PasswordTransformationMethod$PasswordCharSequence
-android.text.method.PasswordTransformationMethod$ViewReference
-android.text.method.PasswordTransformationMethod$Visible
android.text.method.QwertyKeyListener
-android.text.method.QwertyKeyListener$Replaced
android.text.method.ReplacementTransformationMethod
-android.text.method.ReplacementTransformationMethod$ReplacementCharSequence
android.text.method.ReplacementTransformationMethod$SpannedReplacementCharSequence
android.text.method.SingleLineTransformationMethod
android.text.method.TextKeyListener
android.text.method.TextKeyListener$Capitalize
android.text.method.TextKeyListener$SettingsObserver
-android.text.method.Touch
-android.text.method.Touch$DragState
android.text.method.TransformationMethod
android.text.style.AlignmentSpan
android.text.style.CharacterStyle
-android.text.style.ClickableSpan
android.text.style.ForegroundColorSpan
android.text.style.LeadingMarginSpan
android.text.style.LineBackgroundSpan
@@ -758,60 +365,27 @@
android.text.style.ReplacementSpan
android.text.style.StyleSpan
android.text.style.URLSpan
-android.text.style.UnderlineSpan
android.text.style.UpdateAppearance
android.text.style.UpdateLayout
android.text.style.WrapTogetherSpan
android.text.util.Linkify
-android.text.util.Linkify$1
-android.text.util.Linkify$2
-android.text.util.Linkify$3
-android.text.util.Linkify$4
-android.text.util.Linkify$MatchFilter
-android.text.util.Linkify$TransformFilter
android.text.util.Regex
-android.text.util.Rfc822Validator
-android.util.AndroidException
android.util.AndroidRuntimeException
android.util.AttributeSet
android.util.DisplayMetrics
-android.util.EventLog
-android.util.EventLog$Event
-android.util.EventLog$List
-android.util.FinitePool
android.util.FloatMath
-android.util.Log
-android.util.LongSparseArray
-android.util.Pool
-android.util.Poolable
-android.util.PoolableManager
-android.util.Pools
-android.util.Printer
android.util.SparseArray
-android.util.SparseBooleanArray
-android.util.SparseIntArray
-android.util.StateSet
-android.util.SynchronizedPool
android.util.TypedValue
-android.util.Xml
+android.util.Xml$XmlSerializerFactory
android.view.AbsSavedState
-android.view.AbsSavedState$1
-android.view.AbsSavedState$2
android.view.ContextMenu
android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
-android.view.Display$CompatibleDisplay
android.view.FocusFinder
android.view.FocusFinder$1
-android.view.GestureDetector
-android.view.GestureDetector$GestureHandler
-android.view.GestureDetector$OnDoubleTapListener
-android.view.GestureDetector$OnGestureListener
android.view.GestureDetector$SimpleOnGestureListener
android.view.Gravity
-android.view.IRotationWatcher
-android.view.IRotationWatcher$Stub
android.view.IWindow
android.view.IWindow$Stub
android.view.IWindowManager
@@ -821,68 +395,44 @@
android.view.IWindowSession$Stub
android.view.IWindowSession$Stub$Proxy
android.view.KeyCharacterMap
-android.view.KeyCharacterMap$KeyData
android.view.KeyEvent
android.view.KeyEvent$1
android.view.KeyEvent$Callback
android.view.LayoutInflater
android.view.LayoutInflater$Factory
-android.view.LayoutInflater$Filter
android.view.Menu
android.view.MenuInflater
-android.view.MenuInflater$MenuState
android.view.MenuItem
android.view.MotionEvent
android.view.MotionEvent$1
android.view.Surface
-android.view.Surface$1
-android.view.Surface$CompatibleCanvas
android.view.SurfaceHolder
-android.view.SurfaceHolder$Callback
-android.view.SurfaceSession
android.view.SurfaceView
-android.view.SurfaceView$1
-android.view.SurfaceView$2
-android.view.SurfaceView$MyWindow
android.view.TouchDelegate
android.view.VelocityTracker
-android.view.VelocityTracker$1
android.view.View
android.view.View$AttachInfo
android.view.View$AttachInfo$Callbacks
android.view.View$BaseSavedState
android.view.View$BaseSavedState$1
-android.view.View$CheckForLongPress
android.view.View$MeasureSpec
-android.view.View$OnClickListener
android.view.View$OnCreateContextMenuListener
-android.view.View$OnFocusChangeListener
-android.view.View$OnKeyListener
-android.view.View$OnLongClickListener
-android.view.View$OnTouchListener
android.view.View$ScrollabilityCache
-android.view.View$UnsetPressedState
android.view.ViewConfiguration
android.view.ViewGroup
android.view.ViewGroup$LayoutParams
android.view.ViewGroup$MarginLayoutParams
-android.view.ViewGroup$OnHierarchyChangeListener
android.view.ViewManager
-android.view.ViewParent
android.view.ViewRoot
android.view.ViewRoot$1
android.view.ViewRoot$InputMethodCallback
android.view.ViewRoot$RunQueue
-android.view.ViewRoot$RunQueue$HandlerAction
android.view.ViewRoot$TrackballAxis
android.view.ViewRoot$W
+android.view.ViewStub
android.view.ViewTreeObserver
android.view.ViewTreeObserver$InternalInsetsInfo
-android.view.ViewTreeObserver$OnGlobalFocusChangeListener
-android.view.ViewTreeObserver$OnGlobalLayoutListener
android.view.ViewTreeObserver$OnPreDrawListener
-android.view.ViewTreeObserver$OnScrollChangedListener
-android.view.ViewTreeObserver$OnTouchModeChangeListener
android.view.Window
android.view.Window$Callback
android.view.Window$LocalWindowManager
@@ -891,231 +441,139 @@
android.view.WindowManager$LayoutParams
android.view.WindowManager$LayoutParams$1
android.view.WindowManagerImpl
-android.view.accessibility.AccessibilityEvent
-android.view.accessibility.AccessibilityEvent$1
-android.view.accessibility.AccessibilityEventSource
-android.view.accessibility.AccessibilityManager
-android.view.accessibility.AccessibilityManager$1
-android.view.accessibility.AccessibilityManager$MyHandler
-android.view.accessibility.IAccessibilityManager
-android.view.accessibility.IAccessibilityManager$Stub
-android.view.accessibility.IAccessibilityManager$Stub$Proxy
-android.view.accessibility.IAccessibilityManagerClient
-android.view.accessibility.IAccessibilityManagerClient$Stub
android.view.animation.AccelerateDecelerateInterpolator
-android.view.animation.AccelerateInterpolator
android.view.animation.AlphaAnimation
android.view.animation.Animation
-android.view.animation.Animation$AnimationListener
-android.view.animation.Animation$Description
android.view.animation.AnimationSet
-android.view.animation.AnimationUtils
-android.view.animation.Interpolator
-android.view.animation.LayoutAnimationController
-android.view.animation.ScaleAnimation
+android.view.animation.LinearInterpolator
android.view.animation.Transformation
-android.view.animation.TranslateAnimation
android.view.inputmethod.BaseInputConnection
android.view.inputmethod.CompletionInfo
android.view.inputmethod.CompletionInfo$1
-android.view.inputmethod.ComposingText
+
android.view.inputmethod.EditorInfo
android.view.inputmethod.EditorInfo$1
+
android.view.inputmethod.ExtractedText
android.view.inputmethod.ExtractedText$1
+
android.view.inputmethod.ExtractedTextRequest
android.view.inputmethod.ExtractedTextRequest$1
+
+android.view.inputmethod.InputBinding
+android.view.inputmethod.InputBinding$1
android.view.inputmethod.InputConnection
-android.view.inputmethod.InputConnectionWrapper
+android.view.inputmethod.InputMethod
+android.view.inputmethod.InputMethod$SessionCallback
+
+android.view.inputmethod.InputMethodInfo
+android.view.inputmethod.InputMethodInfo$1
android.view.inputmethod.InputMethodManager
android.view.inputmethod.InputMethodManager$1
+android.view.inputmethod.InputMethodManager$2
android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
android.view.inputmethod.InputMethodManager$H
+
+android.view.inputmethod.InputMethodSession
+android.view.inputmethod.InputMethodSession$EventCallback
android.webkit.BrowserFrame
-android.webkit.ByteArrayBuilder
-android.webkit.ByteArrayBuilder$Chunk
android.webkit.CacheManager
android.webkit.CallbackProxy
android.webkit.CookieManager
android.webkit.CookieSyncManager
-android.webkit.DataLoader
-android.webkit.FrameLoader
-android.webkit.HttpAuthHandler
android.webkit.HttpDateTime
android.webkit.JWebCoreJavaBridge
android.webkit.LoadListener
-android.webkit.LoadListener$1
android.webkit.MimeTypeMap
-android.webkit.PerfChecker
-android.webkit.SslErrorHandler
-android.webkit.StreamLoader
-android.webkit.TextDialog
android.webkit.URLUtil
android.webkit.WebBackForwardList
android.webkit.WebHistoryItem
android.webkit.WebIconDatabase
android.webkit.WebIconDatabase$EventHandler
android.webkit.WebIconDatabase$EventHandler$1
+android.webkit.WebIconDatabase$EventHandler$IconResult
android.webkit.WebSettings
android.webkit.WebSettings$EventHandler
android.webkit.WebSettings$EventHandler$1
android.webkit.WebSettings$LayoutAlgorithm
android.webkit.WebSettings$RenderPriority
android.webkit.WebSettings$TextSize
-android.webkit.WebSettings$ZoomDensity
android.webkit.WebSyncManager
android.webkit.WebSyncManager$SyncHandler
+android.webkit.WebTextView
android.webkit.WebView
-android.webkit.WebView$1
-android.webkit.WebView$2
-android.webkit.WebView$FocusNode
-android.webkit.WebView$HitTestResult
+android.webkit.WebView$ExtendedZoomControls
android.webkit.WebView$PrivateHandler
android.webkit.WebViewCore
-android.webkit.WebViewCore$DrawData
+android.webkit.WebViewCore$CursorData
android.webkit.WebViewCore$EventHub
android.webkit.WebViewCore$EventHub$1
-android.webkit.WebViewCore$FocusData
android.webkit.WebViewCore$WebCoreThread
android.webkit.WebViewCore$WebCoreThread$1
android.webkit.WebViewDatabase
android.widget.AbsListView
-android.widget.AbsListView$1
-android.widget.AbsListView$2
-android.widget.AbsListView$3
android.widget.AbsListView$CheckForLongPress
android.widget.AbsListView$CheckForTap
-android.widget.AbsListView$FlingRunnable
android.widget.AbsListView$LayoutParams
-android.widget.AbsListView$OnScrollListener
android.widget.AbsListView$PerformClick
android.widget.AbsListView$RecycleBin
-android.widget.AbsListView$RecyclerListener
android.widget.AbsListView$SavedState
android.widget.AbsListView$SavedState$1
-android.widget.AbsListView$WindowRunnnable
android.widget.AbsSeekBar
android.widget.AbsSpinner
-android.widget.AbsSpinner$RecycleBin
-android.widget.AbsSpinner$SavedState
-android.widget.AbsSpinner$SavedState$1
android.widget.AbsoluteLayout
-android.widget.Adapter
+android.widget.AbsoluteLayout$LayoutParams
android.widget.AdapterView
android.widget.AdapterView$AdapterDataSetObserver
-android.widget.AdapterView$OnItemClickListener
-android.widget.AdapterView$OnItemLongClickListener
-android.widget.AdapterView$OnItemSelectedListener
-android.widget.AnalogClock
-android.widget.AppSecurityPermissions
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
-android.widget.AutoCompleteTextView$1
-android.widget.AutoCompleteTextView$2
android.widget.AutoCompleteTextView$DropDownItemClickListener
android.widget.AutoCompleteTextView$DropDownListView
-android.widget.AutoCompleteTextView$ListSelectorHider
-android.widget.AutoCompleteTextView$MyWatcher
-android.widget.AutoCompleteTextView$PassThroughClickListener
-android.widget.AutoCompleteTextView$PopupTouchIntercepter
-android.widget.AutoCompleteTextView$Validator
android.widget.BaseAdapter
android.widget.Button
android.widget.CheckBox
android.widget.Checkable
android.widget.CheckedTextView
-android.widget.Chronometer
android.widget.CompoundButton
-android.widget.CompoundButton$OnCheckedChangeListener
-android.widget.CompoundButton$SavedState
-android.widget.CompoundButton$SavedState$1
android.widget.CursorAdapter
android.widget.CursorAdapter$ChangeObserver
android.widget.CursorAdapter$MyDataSetObserver
-android.widget.CursorFilter
-android.widget.CursorFilter$CursorFilterClient
android.widget.CursorTreeAdapter
-android.widget.DatePicker
android.widget.EditText
-android.widget.ExpandableListConnector
android.widget.ExpandableListView
-android.widget.FastScroller
-android.widget.Filter
-android.widget.Filter$FilterListener
-android.widget.Filter$FilterResults
-android.widget.Filter$RequestArguments
-android.widget.Filter$RequestHandler
-android.widget.Filter$ResultsHandler
-android.widget.FilterQueryProvider
-android.widget.Filterable
android.widget.FrameLayout
android.widget.FrameLayout$LayoutParams
android.widget.Gallery
-android.widget.GridView
android.widget.HeaderViewListAdapter
-android.widget.ImageButton
android.widget.ImageView
android.widget.ImageView$ScaleType
android.widget.LinearLayout
android.widget.LinearLayout$LayoutParams
-android.widget.ListAdapter
android.widget.ListView
android.widget.ListView$ArrowScrollFocusResult
-android.widget.ListView$FixedViewInfo
android.widget.ListView$SavedState
android.widget.ListView$SavedState$1
-android.widget.MediaController
-android.widget.MultiAutoCompleteTextView
android.widget.PopupWindow
-android.widget.PopupWindow$1
-android.widget.PopupWindow$PopupViewContainer
android.widget.ProgressBar
-android.widget.ProgressBar$SavedState
-android.widget.ProgressBar$SavedState$1
android.widget.RadioGroup
android.widget.RatingBar
android.widget.RelativeLayout
-android.widget.RelativeLayout$DependencyGraph
-android.widget.RelativeLayout$DependencyGraph$Node
-android.widget.RelativeLayout$DependencyGraph$Node$1
android.widget.RelativeLayout$LayoutParams
android.widget.RemoteViews
-android.widget.RemoteViews$1
-android.widget.RemoteViews$Action
-android.widget.RemoteViews$ReflectionAction
-android.widget.RemoteViews$SetOnClickPendingIntent
-android.widget.ResourceCursorAdapter
android.widget.ScrollBarDrawable
android.widget.ScrollView
android.widget.Scroller
android.widget.SeekBar
-android.widget.SeekBar$OnSeekBarChangeListener
android.widget.SimpleCursorAdapter
android.widget.SlidingDrawer
android.widget.Spinner
-android.widget.SpinnerAdapter
+android.widget.Spinner$DropDownAdapter
android.widget.TabHost
-android.widget.TabHost$1
-android.widget.TabHost$2
-android.widget.TabHost$ContentStrategy
-android.widget.TabHost$IndicatorStrategy
-android.widget.TabHost$IntentContentStrategy
-android.widget.TabHost$LabelAndIconIndicatorStrategy
-android.widget.TabHost$OnTabChangeListener
-android.widget.TabHost$TabSpec
-android.widget.TabHost$ViewIndicatorStrategy
android.widget.TabWidget
-android.widget.TabWidget$OnTabSelectionChanged
-android.widget.TabWidget$TabClickListener
android.widget.TableLayout
-android.widget.TableLayout$LayoutParams
-android.widget.TableLayout$PassThroughHierarchyChangeListener
android.widget.TableRow
-android.widget.TableRow$ChildrenTracker
-android.widget.TableRow$LayoutParams
android.widget.TextView
-android.widget.TextView$2
-android.widget.TextView$3
+android.widget.TextView$1
android.widget.TextView$Blink
android.widget.TextView$BufferType
android.widget.TextView$ChangeWatcher
@@ -1123,61 +581,33 @@
android.widget.TextView$Drawables
android.widget.TextView$InputContentType
android.widget.TextView$InputMethodState
-android.widget.TextView$OnEditorActionListener
+android.widget.TextView$Marquee
+android.widget.TextView$MenuHandler
android.widget.TextView$SavedState
android.widget.TextView$SavedState$1
-android.widget.TimePicker
-android.widget.Toast
-android.widget.Toast$TN
-android.widget.Toast$TN$1
-android.widget.Toast$TN$2
-android.widget.VideoView
+android.widget.ToggleButton
+android.widget.TwoLineListItem
android.widget.ViewAnimator
android.widget.ViewSwitcher
-android.widget.WrapperListAdapter
android.widget.ZoomButton
-android.widget.ZoomButton$1
-android.widget.ZoomButtonsController
-android.widget.ZoomButtonsController$1
-android.widget.ZoomButtonsController$2
-android.widget.ZoomButtonsController$3
-android.widget.ZoomButtonsController$4
-android.widget.ZoomButtonsController$Container
-android.widget.ZoomButtonsController$OnZoomListener
android.widget.ZoomControls
-com.android.internal.R$drawable
-com.android.internal.R$styleable
-com.android.internal.app.AlertActivity
-com.android.internal.app.AlertController
-com.android.internal.app.AlertController$1
-com.android.internal.app.AlertController$AlertParams
-com.android.internal.app.AlertController$AlertParams$3
-com.android.internal.app.AlertController$ButtonHandler
-com.android.internal.app.AlertController$RecycleListView
-com.android.internal.app.ChooserActivity
-com.android.internal.app.ResolverActivity
-com.android.internal.app.RingtonePickerActivity
-com.android.internal.appwidget.IAppWidgetService
-com.android.internal.appwidget.IAppWidgetService$Stub
-com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
+com.android.internal.database.ArrayListCursor
com.android.internal.database.SortCursor
-com.android.internal.graphics.NativeUtils
-com.android.internal.location.DummyLocationProvider
-com.android.internal.location.GpsLocationProvider
+com.android.internal.appwidget.IAppWidgetService$Stub
+com.android.internal.http.multipart.FilePart
+com.android.internal.http.multipart.MultipartEntity
+com.android.internal.http.multipart.Part
+com.android.internal.http.multipart.PartSource
+com.android.internal.http.multipart.StringPart
com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
-com.android.internal.logging.AndroidHandler$1
com.android.internal.os.AndroidPrintStream
-com.android.internal.os.BinderInternal
com.android.internal.os.BinderInternal$GcWatcher
com.android.internal.os.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.RuntimeInit
com.android.internal.os.RuntimeInit$1
com.android.internal.os.RuntimeInit$UncaughtHandler
-com.android.internal.os.ZygoteConnection
-com.android.internal.os.ZygoteConnection$Arguments
-com.android.internal.os.ZygoteInit
com.android.internal.os.ZygoteInit$MethodAndArgsCaller
com.android.internal.policy.IPolicy
com.android.internal.policy.PolicyManager
@@ -1186,621 +616,287 @@
com.android.internal.policy.impl.PhoneWindow$1
com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback
com.android.internal.policy.impl.PhoneWindow$DecorView
-com.android.internal.policy.impl.PhoneWindow$DrawableFeatureState
com.android.internal.policy.impl.PhoneWindow$PanelFeatureState
com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState
com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState$1
-com.android.internal.policy.impl.PhoneWindowManager
com.android.internal.policy.impl.Policy
-com.android.internal.telephony.BaseCommands
com.android.internal.telephony.Connection$DisconnectCause
-com.android.internal.telephony.GsmAlphabet
-com.android.internal.telephony.IPhoneStateListener
+com.android.internal.telephony.Connection$PostDialState
com.android.internal.telephony.IPhoneStateListener$Stub
-com.android.internal.telephony.IPhoneSubInfo
-com.android.internal.telephony.IPhoneSubInfo$Stub
-com.android.internal.telephony.IPhoneSubInfo$Stub$Proxy
-com.android.internal.telephony.ITelephony
com.android.internal.telephony.ITelephony$Stub
-com.android.internal.telephony.ITelephony$Stub$Proxy
-com.android.internal.telephony.ITelephonyRegistry
-com.android.internal.telephony.ITelephonyRegistry$Stub
-com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
-com.android.internal.telephony.IccCardApplication$PersoSubState
-com.android.internal.telephony.IccProvider
+com.android.internal.telephony.Phone
+com.android.internal.telephony.Phone$DataActivityState
+com.android.internal.telephony.Phone$DataState
com.android.internal.telephony.Phone$State
+com.android.internal.telephony.Phone$SuppService
com.android.internal.telephony.PhoneBase
-com.android.internal.telephony.PhoneProxy
com.android.internal.telephony.PhoneStateIntentReceiver
-com.android.internal.telephony.RIL
-com.android.internal.telephony.SmsMessageBase
+com.android.internal.telephony.IccCard$State
+com.android.internal.telephony.BaseCommands
+com.android.internal.telephony.CallForwardInfo
+com.android.internal.telephony.CommandsInterface
+com.android.internal.telephony.DriverCall
+com.android.internal.telephony.DriverCall$State
+com.android.internal.telephony.gsm.GsmConnection
com.android.internal.telephony.gsm.GSMPhone
-com.android.internal.telephony.gsm.GsmDataConnectionTracker
+com.android.internal.telephony.GsmAlphabet
com.android.internal.telephony.gsm.GsmMmiCode
-com.android.internal.telephony.gsm.MccTable
-com.android.internal.telephony.gsm.SmsMessage
-com.android.internal.telephony.gsm.stk.CommandDetails
+com.android.internal.telephony.gsm.SimCard
+com.android.internal.telephony.ISms$Stub
+com.android.internal.telephony.RIL
+com.android.internal.telephony.ServiceStateTracker
+
+com.android.internal.telephony.gsm.stk.ComprehensionTlvTag
com.android.internal.telephony.gsm.stk.ResultCode
-com.android.internal.util.ArrayUtils
com.android.internal.util.FastXmlSerializer
-com.android.internal.util.XmlUtils
com.android.internal.view.IInputConnectionWrapper
com.android.internal.view.IInputConnectionWrapper$MyHandler
com.android.internal.view.IInputConnectionWrapper$SomeArgs
+
com.android.internal.view.IInputContext
com.android.internal.view.IInputContext$Stub
+com.android.internal.view.IInputContext$Stub$Proxy
+
com.android.internal.view.IInputContextCallback
com.android.internal.view.IInputContextCallback$Stub
com.android.internal.view.IInputContextCallback$Stub$Proxy
+
+com.android.internal.view.IInputMethod
+com.android.internal.view.IInputMethod$Stub
+com.android.internal.view.IInputMethod$Stub$Proxy
+
com.android.internal.view.IInputMethodCallback
com.android.internal.view.IInputMethodCallback$Stub
+com.android.internal.view.IInputMethodCallback$Stub$Proxy
+
com.android.internal.view.IInputMethodClient
com.android.internal.view.IInputMethodClient$Stub
+com.android.internal.view.IInputMethodClient$Stub$Proxy
+
com.android.internal.view.IInputMethodManager
com.android.internal.view.IInputMethodManager$Stub
com.android.internal.view.IInputMethodManager$Stub$Proxy
+
com.android.internal.view.IInputMethodSession
com.android.internal.view.IInputMethodSession$Stub
com.android.internal.view.IInputMethodSession$Stub$Proxy
+
com.android.internal.view.InputBindResult
com.android.internal.view.InputBindResult$1
+
+com.android.internal.view.InputConnectionWrapper
+com.android.internal.view.InputConnectionWrapper$InputContextCallback
com.android.internal.view.menu.ExpandedMenuView
com.android.internal.view.menu.IconMenuItemView
com.android.internal.view.menu.IconMenuView
-com.android.internal.view.menu.IconMenuView$1
-com.android.internal.view.menu.IconMenuView$LayoutParams
-com.android.internal.view.menu.IconMenuView$SavedState
-com.android.internal.view.menu.IconMenuView$SavedState$1
com.android.internal.view.menu.ListMenuItemView
com.android.internal.view.menu.MenuBuilder
com.android.internal.view.menu.MenuBuilder$Callback
-com.android.internal.view.menu.MenuBuilder$ItemInvoker
-com.android.internal.view.menu.MenuBuilder$MenuAdapter
-com.android.internal.view.menu.MenuBuilder$MenuType
+com.android.internal.view.menu.MenuDialogHelper
com.android.internal.view.menu.MenuItemImpl
-com.android.internal.view.menu.MenuView
-com.android.internal.view.menu.MenuView$ItemView
com.android.internal.view.menu.SubMenuBuilder
-com.android.internal.widget.DialogTitle
-com.android.internal.widget.EditableInputConnection
-com.android.internal.widget.LockPatternUtils
+com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+com.android.internal.widget.LockPatternView
com.android.internal.widget.NumberPicker
-com.google.android.collect.Lists
-com.google.android.collect.Maps
-com.google.android.collect.Sets
+com.android.internal.widget.NumberPickerButton
com.google.android.gdata.client.AndroidGDataClient
+com.google.android.gdata.client.AndroidGDataClient$PostRequestCreator
com.google.android.gles_jni.EGLImpl
com.google.android.gles_jni.GLImpl
+com.google.android.mms.ContentType
+com.google.android.mms.pdu.CharacterSets
+com.google.android.mms.pdu.PduPart
com.google.android.mms.pdu.PduPersister
-com.google.android.mms.util.PduCache
com.google.android.net.GoogleHttpClient
-com.google.android.net.GoogleHttpClient$WrappedLayeredSocketFactory
-com.google.android.net.GoogleHttpClient$WrappedSocketFactory
-com.google.android.net.NetworkStatsEntity
-com.google.android.net.SSLClientSessionCacheFactory
com.google.android.net.UrlRules
com.google.android.net.UrlRules$Rule
-com.google.common.Clock
+com.google.android.util.SimplePullParser
com.google.common.Config
-com.google.common.GenericClock
-com.google.common.I18n
-com.google.common.Log
-com.google.common.StaticUtil
-com.google.common.android.AndroidClock
-com.google.common.android.AndroidConfig
-com.google.common.android.AndroidConfig$1
-com.google.common.graphics.FontFactory
-com.google.common.graphics.ImageFactory
-com.google.common.graphics.InterpolatedFontFactory
-com.google.common.graphics.android.AndroidFontFactory
-com.google.common.graphics.android.AndroidImageFactory
-com.google.common.io.BaseConnectionFactory
-com.google.common.io.BaseHttpConnectionFactory
-com.google.common.io.BasePersistentStore
-com.google.common.io.BaseTcpConnectionFactory
-com.google.common.io.ConnectionFactory
-com.google.common.io.GoogleHttpConnection
-com.google.common.io.Gunzipper
-com.google.common.io.Gunzipper$GunzipInterface
-com.google.common.io.HttpConnectionFactory
-com.google.common.io.InMemoryPersistentStore
-com.google.common.io.PersistentStore
-com.google.common.io.PersistentStore$PersistentStoreException
-com.google.common.io.PreferenceStore
-com.google.common.io.TcpConnectionFactory
-com.google.common.io.android.AndroidFixedPersistentStore
-com.google.common.io.android.AndroidHttpClient
-com.google.common.io.android.AndroidHttpClient$1
-com.google.common.io.android.AndroidHttpClient$2
-com.google.common.io.android.AndroidHttpClient$CurlLogger
-com.google.common.io.android.AndroidHttpClient$LoggingConfiguration
-com.google.common.io.android.AndroidHttpConnectionFactory
-com.google.common.io.android.AndroidHttpConnectionFactory$1
-com.google.common.io.android.AndroidHttpConnectionFactory$AndroidGoogleHttpConnection
-com.google.common.io.android.AndroidPersistentStore
-com.google.common.io.android.AndroidTcpConnectionFactory
-com.google.common.io.android.CountingByteChannel$Counter
-com.google.common.io.android.GoogleHttpClient
-com.google.common.io.android.J2SeTcpConnectionFactory
com.google.common.io.protocol.ProtoBuf
com.google.common.io.protocol.ProtoBufType
com.google.common.util.text.TextUtil
-com.google.debug.DebugUtil
-com.google.masf.MobileServiceMux
-com.google.masf.services.LogserviceMessageTypes
-com.google.masf.services.resume.WindowResumeService
-com.google.wireless.gdata.calendar.client.CalendarClient
-com.google.wireless.gdata.contacts.client.ContactsClient
com.ibm.icu4jni.charset.CharsetDecoderICU
com.ibm.icu4jni.charset.CharsetEncoderICU
com.ibm.icu4jni.charset.CharsetICU
-com.ibm.icu4jni.charset.CharsetProviderICU
-com.ibm.icu4jni.charset.NativeConverter
-com.ibm.icu4jni.common.ErrorCode
-com.ibm.icu4jni.lang.UCharacter
-com.ibm.icu4jni.regex.NativeRegEx
com.ibm.icu4jni.text.CollationAttribute
-com.ibm.icu4jni.text.Collator
com.ibm.icu4jni.text.DecimalFormat
com.ibm.icu4jni.text.DecimalFormatSymbols
-com.ibm.icu4jni.text.DecimalFormatSymbols$1
-com.ibm.icu4jni.text.NativeBreakIterator
-com.ibm.icu4jni.text.NativeCollation
-com.ibm.icu4jni.text.NativeDecimalFormat
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatSymbol
com.ibm.icu4jni.text.RuleBasedCollator
-com.ibm.icu4jni.text.RuleBasedNumberFormat
-com.ibm.icu4jni.util.Resources
-com.ibm.icu4jni.util.Resources$ISO4Currencies
-com.ibm.icu4jni.util.Resources$ISO4CurrenciesToDigits
-com.ibm.icu4jni.util.Resources$Locale
dalvik.system.DexFile
-dalvik.system.NativeStart
dalvik.system.PathClassLoader
-dalvik.system.TouchDex
-dalvik.system.VMDebug
-dalvik.system.VMRuntime
-dalvik.system.VMStack
-dalvik.system.Zygote
java.beans.PropertyChangeEvent
java.beans.PropertyChangeListener
java.beans.PropertyChangeSupport
java.io.BufferedInputStream
-java.io.BufferedOutputStream
-java.io.BufferedReader
java.io.ByteArrayInputStream
java.io.ByteArrayOutputStream
-java.io.Closeable
-java.io.DataInput
-java.io.DataInputStream
-java.io.DataOutput
-java.io.DataOutputStream
-java.io.Externalizable
java.io.File
java.io.FileDescriptor
java.io.FileInputStream
java.io.FileInputStream$RepositioningLock
java.io.FileNotFoundException
-java.io.FileOutputStream
java.io.FilterInputStream
-java.io.FilterOutputStream
-java.io.Flushable
java.io.IOException
-java.io.InputStream
-java.io.InputStreamReader
-java.io.InterruptedIOException
-java.io.ObjectInput
-java.io.ObjectInputStream
-java.io.ObjectOutput
-java.io.ObjectOutputStream
java.io.ObjectStreamClass
-java.io.ObjectStreamConstants
-java.io.ObjectStreamException
-java.io.ObjectStreamField
-java.io.ObjectStreamField$1
-java.io.OutputStream
-java.io.PrintStream
java.io.PrintWriter
java.io.RandomAccessFile
java.io.RandomAccessFile$RepositionLock
-java.io.Reader
-java.io.Serializable
-java.io.StreamCorruptedException
-java.io.StringReader
java.io.StringWriter
-java.io.UnsupportedEncodingException
java.io.Writer
-java.lang.AbstractStringBuilder
-java.lang.Appendable
-java.lang.ArrayIndexOutOfBoundsException
-java.lang.Boolean
-java.lang.BootClassLoader
-java.lang.Byte
-java.lang.CharSequence
-java.lang.Character
java.lang.Character$valueOfCache
java.lang.Class
java.lang.ClassCache
-java.lang.ClassCache$EnumComparator
-java.lang.ClassCastException
-java.lang.ClassLoader
-java.lang.ClassLoader$SystemClassLoader
java.lang.ClassNotFoundException
-java.lang.CloneNotSupportedException
-java.lang.Cloneable
-java.lang.Comparable
-java.lang.Double
-java.lang.Enum
-java.lang.Error
-java.lang.Exception
-java.lang.ExceptionInInitializerError
-java.lang.Float
java.lang.IllegalArgumentException
java.lang.IllegalStateException
-java.lang.IncompatibleClassChangeError
-java.lang.IndexOutOfBoundsException
java.lang.Integer
java.lang.Integer$valueOfCache
-java.lang.InternalError
-java.lang.InterruptedException
-java.lang.Iterable
-java.lang.LangAccessImpl
java.lang.LinkageError
java.lang.Long
java.lang.Long$valueOfCache
-java.lang.Math
java.lang.NoClassDefFoundError
-java.lang.NoSuchFieldException
-java.lang.NoSuchMethodException
-java.lang.NullPointerException
-java.lang.Number
java.lang.NumberFormatException
java.lang.Object
-java.lang.OutOfMemoryError
-java.lang.Readable
-java.lang.Runnable
java.lang.Runtime
java.lang.RuntimeException
-java.lang.RuntimePermission
-java.lang.SecurityException
-java.lang.Short
java.lang.Short$valueOfCache
-java.lang.StackOverflowError
-java.lang.StackTraceElement
-java.lang.StrictMath
java.lang.String
-java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
-java.lang.System
-java.lang.SystemProperties
java.lang.Thread
-java.lang.Thread$State
-java.lang.Thread$UncaughtExceptionHandler
-java.lang.ThreadGroup
-java.lang.ThreadGroup$ChildrenGroupsLock
-java.lang.ThreadGroup$ChildrenThreadsLock
java.lang.ThreadLocal
java.lang.ThreadLocal$Values
java.lang.Throwable
-java.lang.UnsatisfiedLinkError
-java.lang.UnsupportedOperationException
-java.lang.VMClassLoader
java.lang.VMThread
-java.lang.VirtualMachineError
-java.lang.Void
-java.lang.annotation.Annotation
-java.lang.ref.Reference
java.lang.ref.ReferenceQueue
java.lang.ref.SoftReference
java.lang.ref.WeakReference
-java.lang.reflect.AccessibleObject
-java.lang.reflect.AnnotatedElement
-java.lang.reflect.Array
java.lang.reflect.Constructor
-java.lang.reflect.Field
-java.lang.reflect.GenericDeclaration
-java.lang.reflect.InvocationHandler
-java.lang.reflect.Member
java.lang.reflect.Method
java.lang.reflect.Modifier
-java.lang.reflect.Proxy
-java.lang.reflect.ReflectionAccessImpl
-java.lang.reflect.Type
java.math.BigDecimal
java.math.BigInt
-java.math.BigInt$Context
java.math.BigInteger
java.math.Multiplication
java.net.ContentHandler
-java.net.DatagramPacket
-java.net.HttpURLConnection
-java.net.Inet4Address
-java.net.Inet6Address
java.net.InetAddress
-java.net.InetAddress$Cache
java.net.InetAddress$CacheElement
java.net.InetAddress$WaitReachable
-java.net.InetSocketAddress
java.net.JarURLConnection
java.net.NegativeCache
java.net.NetPermission
-java.net.NetworkInterface
-java.net.Proxy
-java.net.Proxy$Type
-java.net.ProxySelector
java.net.ProxySelectorImpl
-java.net.ProxySelectorImpl$1
-java.net.ResponseCache
-java.net.ServerSocket
-java.net.Socket
java.net.Socket$ConnectLock
-java.net.SocketAddress
-java.net.SocketImpl
-java.net.SocketOptions
-java.net.SocketTimeoutException
java.net.URI
-java.net.URI$Helper
-java.net.URIEncoderDecoder
-java.net.URISyntaxException
java.net.URL
java.net.URLConnection
java.net.URLConnection$DefaultContentHandler
-java.net.URLEncoder
java.net.URLStreamHandler
-java.nio.BaseByteBuffer
-java.nio.Buffer
-java.nio.BufferFactory
-java.nio.ByteBuffer
java.nio.ByteOrder
-java.nio.CharArrayBuffer
-java.nio.CharBuffer
java.nio.CharSequenceAdapter
java.nio.DirectByteBuffer
-java.nio.HeapByteBuffer
-java.nio.IntToByteBufferAdapter
-java.nio.NIOAccess
-java.nio.ReadWriteCharArrayBuffer
java.nio.ReadWriteDirectByteBuffer
-java.nio.ReadWriteHeapByteBuffer
-java.nio.channels.ByteChannel
-java.nio.channels.Channel
-java.nio.channels.FileChannel
-java.nio.channels.GatheringByteChannel
-java.nio.channels.InterruptibleChannel
-java.nio.channels.ReadableByteChannel
-java.nio.channels.ScatteringByteChannel
-java.nio.channels.WritableByteChannel
-java.nio.channels.spi.AbstractInterruptibleChannel
-java.nio.channels.spi.AbstractInterruptibleChannel$1
-java.nio.charset.Charset
-java.nio.charset.Charset$1
-java.nio.charset.CharsetDecoder
+java.nio.ReadWriteIntArrayBuffer
+java.nio.ReadWriteShortArrayBuffer
+java.nio.ShortBuffer
+java.nio.ShortToByteBufferAdapter
java.nio.charset.CharsetEncoder
-java.nio.charset.CoderResult
-java.nio.charset.CodingErrorAction
-java.nio.charset.spi.CharsetProvider
java.security.AccessControlContext
-java.security.AccessController
-java.security.BasicPermission
java.security.GeneralSecurityException
-java.security.Guard
-java.security.Key
-java.security.KeyFactory
-java.security.KeyFactorySpi
java.security.KeyStore
-java.security.KeyStore$1
-java.security.KeyStoreSpi
java.security.MessageDigest
-java.security.MessageDigestSpi
-java.security.Permission
-java.security.Principal
-java.security.PrivilegedAction
-java.security.PrivilegedExceptionAction
java.security.ProtectionDomain
java.security.Provider
-java.security.Provider$Service
-java.security.Provider$Service$1
-java.security.PublicKey
java.security.SecureRandom
-java.security.SecureRandomSpi
java.security.Security
-java.security.Security$1
-java.security.Security$SecurityDoor
-java.security.cert.CertPath
-java.security.cert.CertPathParameters
java.security.cert.CertPathValidator
-java.security.cert.CertPathValidatorResult
-java.security.cert.CertPathValidatorSpi
-java.security.cert.CertSelector
-java.security.cert.Certificate
java.security.cert.CertificateFactory
-java.security.cert.CertificateFactorySpi
-java.security.cert.PKIXCertPathValidatorResult
java.security.cert.PKIXParameters
-java.security.cert.PolicyNode
java.security.cert.TrustAnchor
java.security.cert.X509CertSelector
java.security.cert.X509Certificate
-java.security.cert.X509Extension
-java.security.interfaces.RSAKey
-java.security.interfaces.RSAPublicKey
-java.security.spec.EncodedKeySpec
-java.security.spec.KeySpec
-java.security.spec.X509EncodedKeySpec
-java.text.AttributedCharacterIterator$Attribute
java.text.Collator
java.text.DateFormat
java.text.DateFormat$Field
-java.text.DateFormatSymbols
java.text.DecimalFormat
-java.text.DecimalFormat$2
java.text.DecimalFormatSymbols
-java.text.FieldPosition
-java.text.Format
-java.text.Format$1
-java.text.Format$Field
+java.text.MessageFormat
java.text.NumberFormat
java.text.RuleBasedCollator
java.text.SimpleDateFormat
-java.util.AbstractCollection
-java.util.AbstractList
java.util.AbstractList$FullListIterator
java.util.AbstractList$SimpleListIterator
-java.util.AbstractMap
-java.util.AbstractQueue
-java.util.AbstractSequentialList
-java.util.AbstractSet
java.util.ArrayList
java.util.Arrays
java.util.Arrays$ArrayList
java.util.Calendar
-java.util.Collection
-java.util.Collections
-java.util.Collections$EmptyList
-java.util.Collections$EmptyMap
-java.util.Collections$EmptySet
java.util.Collections$SynchronizedCollection
-java.util.Collections$SynchronizedSet
-java.util.Collections$UnmodifiableCollection
-java.util.Collections$UnmodifiableCollection$1
java.util.Collections$UnmodifiableList
java.util.Collections$UnmodifiableMap
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
-java.util.Collections$UnmodifiableRandomAccessList
-java.util.Collections$UnmodifiableSet
-java.util.ComparableTimSort
-java.util.Comparator
-java.util.Currency
java.util.Date
-java.util.Dictionary
java.util.EnumMap
-java.util.EnumSet
-java.util.Enumeration
java.util.EventListener
java.util.EventObject
-java.util.Formattable
java.util.Formatter
-java.util.Formatter$FloatUtil
-java.util.Formatter$FormatToken
-java.util.Formatter$ParserStateMachine
-java.util.Formatter$Transformer
java.util.GregorianCalendar
java.util.HashMap
java.util.HashMap$1
-java.util.HashMap$1$1
java.util.HashMap$2
-java.util.HashMap$2$1
+java.util.HashMap$AbstractMapIterator
java.util.HashMap$Entry
+java.util.HashMap$EntryIterator
java.util.HashMap$HashMapEntrySet
-java.util.HashMap$HashMapEntrySet$1
-java.util.HashMap$HashMapIterator
+java.util.HashMap$KeyIterator
+java.util.HashMap$ValueIterator
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$1
-java.util.Hashtable$2
-java.util.Hashtable$2$1
-java.util.Hashtable$4
-java.util.Hashtable$4$1
+java.util.Hashtable$6
+java.util.Hashtable$6$1
java.util.Hashtable$Entry
-java.util.Hashtable$HashEnumerator
+java.util.Hashtable$HashEnumIterator
java.util.Hashtable$HashIterator
java.util.IdentityHashMap
-java.util.Iterator
java.util.LinkedHashMap
-java.util.LinkedHashMap$1
-java.util.LinkedHashMap$1$1
-java.util.LinkedHashMap$LinkedHashIterator
java.util.LinkedHashMap$LinkedHashMapEntry
-java.util.LinkedHashMap$LinkedHashMapEntrySet
-java.util.LinkedHashMap$LinkedHashMapEntrySet$1
java.util.LinkedList
java.util.LinkedList$Link
-java.util.LinkedList$LinkIterator
java.util.List
-java.util.ListIterator
-java.util.ListResourceBundle
java.util.Locale
-java.util.Locale$1
-java.util.Map
-java.util.Map$Entry
-java.util.MapEntry
-java.util.MapEntry$Type
-java.util.Observable
-java.util.Observer
-java.util.PriorityQueue
java.util.Properties
-java.util.PropertyPermission
-java.util.PropertyResourceBundle
-java.util.Queue
java.util.Random
-java.util.RandomAccess
java.util.ResourceBundle
-java.util.ResourceBundle$1
-java.util.ResourceBundle$MissingBundle
-java.util.Scanner
-java.util.Set
java.util.SimpleTimeZone
-java.util.SortedMap
-java.util.SortedSet
-java.util.Stack
-java.util.StringTokenizer
-java.util.TimSort
java.util.TimeZone
-java.util.Timer
java.util.TreeMap
-java.util.TreeMap$2
-java.util.TreeMap$AbstractMapIterator
-java.util.TreeMap$Entry
-java.util.TreeMap$UnboundedKeyIterator
+java.util.TreeMap$MapEntry
java.util.TreeSet
java.util.Vector
java.util.WeakHashMap
-java.util.WeakHashMap$1
-java.util.WeakHashMap$1$1
-java.util.WeakHashMap$2
-java.util.WeakHashMap$2$1
java.util.WeakHashMap$Entry
-java.util.WeakHashMap$Entry$Type
-java.util.WeakHashMap$HashIterator
-java.util.concurrent.AbstractExecutorService
-java.util.concurrent.BlockingQueue
-java.util.concurrent.Callable
java.util.concurrent.ConcurrentHashMap
-java.util.concurrent.CopyOnWriteArrayList
-java.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl
-java.util.concurrent.Executor
-java.util.concurrent.ExecutorService
-java.util.concurrent.Executors
-java.util.concurrent.Executors$DefaultThreadFactory
-java.util.concurrent.Future
-java.util.concurrent.FutureTask
-java.util.concurrent.FutureTask$Sync
+java.util.concurrent.ConcurrentLinkedQueue
+java.util.concurrent.DelayQueue
java.util.concurrent.LinkedBlockingQueue
-java.util.concurrent.LinkedBlockingQueue$Node
-java.util.concurrent.RejectedExecutionHandler
java.util.concurrent.ScheduledThreadPoolExecutor
-java.util.concurrent.SynchronousQueue
-java.util.concurrent.ThreadFactory
-java.util.concurrent.ThreadPoolExecutor
-java.util.concurrent.ThreadPoolExecutor$AbortPolicy
-java.util.concurrent.ThreadPoolExecutor$Worker
+java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue
java.util.concurrent.TimeUnit
+java.util.concurrent.atomic.AtomicBoolean
java.util.concurrent.atomic.AtomicInteger
-java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.UnsafeAccess
java.util.concurrent.locks.AbstractQueuedSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
-java.util.concurrent.locks.Condition
java.util.concurrent.locks.Lock
java.util.concurrent.locks.LockSupport
java.util.concurrent.locks.ReentrantLock
java.util.concurrent.locks.ReentrantLock$FairSync
java.util.concurrent.locks.ReentrantLock$NonfairSync
java.util.concurrent.locks.ReentrantLock$Sync
+java.util.concurrent.locks.ReentrantReadWriteLock
+java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync
java.util.concurrent.locks.UnsafeAccess
java.util.jar.Attributes
java.util.jar.Attributes$Name
@@ -1823,16 +919,10 @@
java.util.logging.LogRecord
java.util.logging.Logger
java.util.logging.LoggingPermission
-java.util.regex.MatchResult
+java.util.logging.SimpleFormatter
java.util.regex.Matcher
java.util.regex.Pattern
-java.util.zip.Adler32
-java.util.zip.CRC32
-java.util.zip.Checksum
-java.util.zip.Deflater
java.util.zip.DeflaterOutputStream
-java.util.zip.GZIPInputStream
-java.util.zip.GZIPOutputStream
java.util.zip.Inflater
java.util.zip.InflaterInputStream
java.util.zip.ZipConstants
@@ -1841,148 +931,48 @@
java.util.zip.ZipFile
java.util.zip.ZipFile$2
java.util.zip.ZipFile$RAFStream
-javax.microedition.khronos.egl.EGL
-javax.microedition.khronos.egl.EGL10
-javax.microedition.khronos.opengles.GL
-javax.microedition.khronos.opengles.GL10
-javax.microedition.khronos.opengles.GL10Ext
-javax.microedition.khronos.opengles.GL11
-javax.microedition.khronos.opengles.GL11Ext
-javax.microedition.khronos.opengles.GL11ExtensionPack
-javax.net.SocketFactory
-javax.net.ssl.DefaultHostnameVerifier
-javax.net.ssl.HostnameVerifier
+javax.microedition.khronos.egl.EGLContext
javax.net.ssl.HttpsURLConnection
-javax.net.ssl.KeyManager
-javax.net.ssl.KeyManagerFactory
-javax.net.ssl.KeyManagerFactory$1
-javax.net.ssl.KeyManagerFactorySpi
-javax.net.ssl.SSLContextSpi
-javax.net.ssl.SSLServerSocket
-javax.net.ssl.SSLSession
-javax.net.ssl.SSLSessionContext
-javax.net.ssl.SSLSocket
-javax.net.ssl.SSLSocketFactory
-javax.net.ssl.SSLSocketFactory$1
-javax.net.ssl.TrustManager
-javax.net.ssl.TrustManagerFactory
-javax.net.ssl.TrustManagerFactory$1
-javax.net.ssl.TrustManagerFactorySpi
-javax.net.ssl.X509ExtendedKeyManager
-javax.net.ssl.X509KeyManager
-javax.net.ssl.X509TrustManager
+javax.net.ssl.SSLHandshakeException
javax.security.auth.x500.X500Principal
-javax.security.cert.Certificate
javax.security.cert.X509Certificate
-javax.security.cert.X509Certificate$1
javax.security.cert.X509Certificate$2
-javax.xml.parsers.DocumentBuilder
-javax.xml.parsers.DocumentBuilderFactory
junit.framework.Assert
-org.apache.commons.codec.BinaryDecoder
-org.apache.commons.codec.BinaryEncoder
-org.apache.commons.codec.Decoder
-org.apache.commons.codec.Encoder
org.apache.commons.codec.binary.Base64
org.apache.commons.codec.binary.Hex
-org.apache.commons.logging.Log
org.apache.commons.logging.LogFactory
org.apache.commons.logging.impl.Jdk14Logger
-org.apache.commons.logging.impl.WeakHashtable
org.apache.harmony.archive.util.Util
-org.apache.harmony.dalvik.NativeTestTarget
org.apache.harmony.dalvik.ddmc.Chunk
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
-org.apache.harmony.kernel.vm.LangAccess
-org.apache.harmony.kernel.vm.ReflectionAccess
-org.apache.harmony.lang.annotation.AnnotationFactory
-org.apache.harmony.lang.annotation.AnnotationMember
+org.apache.harmony.dalvik.ddmc.DdmVmInternal
org.apache.harmony.luni.internal.net.www.protocol.file.FileURLConnection
org.apache.harmony.luni.internal.net.www.protocol.file.Handler
org.apache.harmony.luni.internal.net.www.protocol.http.Handler
-org.apache.harmony.luni.internal.net.www.protocol.http.Header
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpConfiguration
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionManager
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionManager$ConnectionPool
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$1
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$LimitedInputStream
org.apache.harmony.luni.internal.net.www.protocol.https.Handler
org.apache.harmony.luni.internal.net.www.protocol.jar.Handler
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$1
-org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$CacheEntry
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$JarURLConnectionInputStream
-org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$LRUComparator
org.apache.harmony.luni.internal.util.TimezoneGetter
org.apache.harmony.luni.internal.util.ZoneInfo
org.apache.harmony.luni.internal.util.ZoneInfoDB
-org.apache.harmony.luni.net.GenericIPMreq
-org.apache.harmony.luni.net.NetUtil
-org.apache.harmony.luni.net.NetUtil$Action
org.apache.harmony.luni.net.PlainSocketImpl
-org.apache.harmony.luni.net.PlainSocketImpl2
-org.apache.harmony.luni.net.SocketImplProvider
-org.apache.harmony.luni.net.SocketInputStream
-org.apache.harmony.luni.net.SocketOutputStream
-org.apache.harmony.luni.platform.AdapterManager
-org.apache.harmony.luni.platform.Endianness
-org.apache.harmony.luni.platform.IAdaptable
-org.apache.harmony.luni.platform.IAdapterManager
-org.apache.harmony.luni.platform.ICommonDataTypes
-org.apache.harmony.luni.platform.IFileSystem
-org.apache.harmony.luni.platform.IMemorySystem
-org.apache.harmony.luni.platform.INetworkSystem
-org.apache.harmony.luni.platform.ISystemComponent
-org.apache.harmony.luni.platform.OSComponent
-org.apache.harmony.luni.platform.OSComponentFactory
-org.apache.harmony.luni.platform.OSFileSystem
-org.apache.harmony.luni.platform.OSMemory
-org.apache.harmony.luni.platform.OSNetworkSystem
-org.apache.harmony.luni.platform.Platform
org.apache.harmony.luni.platform.PlatformAddress
-org.apache.harmony.luni.platform.PlatformAddressFactory
-org.apache.harmony.luni.util.Base64
-org.apache.harmony.luni.util.FloatingPointParser
-org.apache.harmony.luni.util.FloatingPointParser$StringExponentPair
-org.apache.harmony.luni.util.Inet6Util
-org.apache.harmony.luni.util.MsgHelp
-org.apache.harmony.luni.util.MsgHelp$1
-org.apache.harmony.luni.util.NumberConverter
-org.apache.harmony.luni.util.PriviAction
org.apache.harmony.luni.util.TwoKeyHashMap
-org.apache.harmony.luni.util.TwoKeyHashMap$Entry
-org.apache.harmony.luni.util.TwoKeyHashMap$EntryIteratorImpl
-org.apache.harmony.luni.util.TwoKeyHashMap$ValueIteratorImpl
-org.apache.harmony.luni.util.TwoKeyHashMap$ValuesCollectionImpl
-org.apache.harmony.luni.util.Util
-org.apache.harmony.nio.AddressUtil
-org.apache.harmony.nio.FileChannelFactory
-org.apache.harmony.nio.internal.DirectBuffer
-org.apache.harmony.nio.internal.FileChannelImpl
org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
org.apache.harmony.nio.internal.LockManager
org.apache.harmony.nio.internal.LockManager$1
-org.apache.harmony.nio.internal.WriteOnlyFileChannel
-org.apache.harmony.security.asn1.ASN1Any
+org.apache.harmony.nio.internal.ReadOnlyFileChannel
org.apache.harmony.security.asn1.ASN1BitString
org.apache.harmony.security.asn1.ASN1BitString$ASN1NamedBitList
org.apache.harmony.security.asn1.ASN1Boolean
-org.apache.harmony.security.asn1.ASN1Choice
-org.apache.harmony.security.asn1.ASN1Constants
-org.apache.harmony.security.asn1.ASN1Constructured
org.apache.harmony.security.asn1.ASN1Explicit
org.apache.harmony.security.asn1.ASN1GeneralizedTime
org.apache.harmony.security.asn1.ASN1Implicit
org.apache.harmony.security.asn1.ASN1Integer
org.apache.harmony.security.asn1.ASN1OctetString
-org.apache.harmony.security.asn1.ASN1Oid
-org.apache.harmony.security.asn1.ASN1Oid$1
-org.apache.harmony.security.asn1.ASN1Primitive
-org.apache.harmony.security.asn1.ASN1Sequence
-org.apache.harmony.security.asn1.ASN1SequenceOf
org.apache.harmony.security.asn1.ASN1SetOf
org.apache.harmony.security.asn1.ASN1StringType
org.apache.harmony.security.asn1.ASN1StringType$1
@@ -1992,47 +982,19 @@
org.apache.harmony.security.asn1.ASN1StringType$5
org.apache.harmony.security.asn1.ASN1StringType$6
org.apache.harmony.security.asn1.ASN1StringType$7
-org.apache.harmony.security.asn1.ASN1Time
-org.apache.harmony.security.asn1.ASN1Type
-org.apache.harmony.security.asn1.ASN1TypeCollection
org.apache.harmony.security.asn1.ASN1UTCTime
-org.apache.harmony.security.asn1.ASN1ValueCollection
-org.apache.harmony.security.asn1.BerInputStream
-org.apache.harmony.security.asn1.BerOutputStream
org.apache.harmony.security.asn1.BitString
-org.apache.harmony.security.asn1.DerInputStream
-org.apache.harmony.security.asn1.DerOutputStream
-org.apache.harmony.security.asn1.ObjectIdentifier
org.apache.harmony.security.fortress.Engine
-org.apache.harmony.security.fortress.SecurityAccess
org.apache.harmony.security.fortress.SecurityUtils
org.apache.harmony.security.fortress.Services
-org.apache.harmony.security.fortress.Services$1
-org.apache.harmony.security.internal.nls.Messages
org.apache.harmony.security.pkcs7.ContentInfo
-org.apache.harmony.security.pkcs7.ContentInfo$1
-org.apache.harmony.security.provider.cert.Cache
-org.apache.harmony.security.provider.cert.DRLCertFactory
-org.apache.harmony.security.provider.cert.DRLCertFactory$1
org.apache.harmony.security.provider.cert.X509CertFactoryImpl
org.apache.harmony.security.provider.cert.X509CertImpl
org.apache.harmony.security.provider.cert.X509CertPathImpl
-org.apache.harmony.security.provider.cert.X509CertPathImpl$1
-org.apache.harmony.security.provider.cert.X509CertPathImpl$2
-org.apache.harmony.security.provider.cert.X509CertPathImpl$3
-org.apache.harmony.security.provider.crypto.CryptoProvider
-org.apache.harmony.security.provider.crypto.CryptoProvider$1
org.apache.harmony.security.provider.crypto.RandomBitsSupplier
-org.apache.harmony.security.provider.crypto.RandomBitsSupplier$1
-org.apache.harmony.security.provider.crypto.SHA1Impl
org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl
-org.apache.harmony.security.provider.crypto.SHA1_Data
org.apache.harmony.security.utils.AlgNameMapper
-org.apache.harmony.security.utils.ObjectIdentifier
org.apache.harmony.security.x501.AttributeTypeAndValue
-org.apache.harmony.security.x501.AttributeTypeAndValue$1
-org.apache.harmony.security.x501.AttributeTypeAndValue$2
-org.apache.harmony.security.x501.AttributeTypeAndValueComparator
org.apache.harmony.security.x501.AttributeValue
org.apache.harmony.security.x501.DirectoryString
org.apache.harmony.security.x501.DirectoryString$1
@@ -2044,194 +1006,63 @@
org.apache.harmony.security.x509.BasicConstraints$1
org.apache.harmony.security.x509.Certificate
org.apache.harmony.security.x509.Certificate$1
-org.apache.harmony.security.x509.DNParser
-org.apache.harmony.security.x509.EDIPartyName
-org.apache.harmony.security.x509.EDIPartyName$1
org.apache.harmony.security.x509.Extension
org.apache.harmony.security.x509.Extension$1
org.apache.harmony.security.x509.Extension$2
-org.apache.harmony.security.x509.ExtensionValue
org.apache.harmony.security.x509.Extensions
org.apache.harmony.security.x509.Extensions$1
org.apache.harmony.security.x509.GeneralName
-org.apache.harmony.security.x509.GeneralName$1
org.apache.harmony.security.x509.GeneralNames
-org.apache.harmony.security.x509.GeneralNames$1
org.apache.harmony.security.x509.KeyUsage
org.apache.harmony.security.x509.ORAddress
-org.apache.harmony.security.x509.ORAddress$1
-org.apache.harmony.security.x509.ORAddress$2
-org.apache.harmony.security.x509.OtherName
-org.apache.harmony.security.x509.OtherName$1
org.apache.harmony.security.x509.SubjectPublicKeyInfo
org.apache.harmony.security.x509.SubjectPublicKeyInfo$1
org.apache.harmony.security.x509.TBSCertificate
org.apache.harmony.security.x509.TBSCertificate$1
org.apache.harmony.security.x509.Time
org.apache.harmony.security.x509.Time$1
-org.apache.harmony.security.x509.Utils
org.apache.harmony.security.x509.Validity
org.apache.harmony.security.x509.Validity$1
-org.apache.harmony.text.BidiWrapper
-org.apache.harmony.xml.ExpatAttributes
org.apache.harmony.xml.ExpatParser
-org.apache.harmony.xml.ExpatParser$ClonedAttributes
-org.apache.harmony.xml.ExpatParser$CurrentAttributes
-org.apache.harmony.xml.ExpatParser$ExpatLocator
org.apache.harmony.xml.ExpatPullParser
-org.apache.harmony.xml.ExpatPullParser$ByteDocument
-org.apache.harmony.xml.ExpatPullParser$Document
-org.apache.harmony.xml.ExpatPullParser$Document$SaxHandler
-org.apache.harmony.xml.ExpatPullParser$EndTagEvent
-org.apache.harmony.xml.ExpatPullParser$Event
-org.apache.harmony.xml.ExpatPullParser$NamespaceStack
-org.apache.harmony.xml.ExpatPullParser$NamespaceStack$Builder
-org.apache.harmony.xml.ExpatPullParser$StartDocumentEvent
-org.apache.harmony.xml.ExpatPullParser$StartTagEvent
-org.apache.harmony.xml.ExpatPullParser$TextEvent
org.apache.harmony.xml.ExpatReader
-org.apache.harmony.xml.dom.DOMImplementationImpl
-org.apache.harmony.xml.dom.DocumentImpl
-org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl
-org.apache.harmony.xml.parsers.DocumentBuilderImpl
-org.apache.harmony.xnet.provider.jsse.AbstractSessionContext
org.apache.harmony.xnet.provider.jsse.ClientSessionContext
-org.apache.harmony.xnet.provider.jsse.ClientSessionContext$1
-org.apache.harmony.xnet.provider.jsse.ClientSessionContext$HostAndPort
-org.apache.harmony.xnet.provider.jsse.FileClientSessionCache
-org.apache.harmony.xnet.provider.jsse.FileClientSessionCache$Impl
-org.apache.harmony.xnet.provider.jsse.JSSEProvider
-org.apache.harmony.xnet.provider.jsse.JSSEProvider$1
-org.apache.harmony.xnet.provider.jsse.KeyManagerFactoryImpl
-org.apache.harmony.xnet.provider.jsse.KeyManagerFactoryImpl$1
-org.apache.harmony.xnet.provider.jsse.KeyManagerImpl
-org.apache.harmony.xnet.provider.jsse.NativeCrypto
-org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest
-org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSessionImpl
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$Finalizer
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$LoggerHolder
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream
-org.apache.harmony.xnet.provider.jsse.ProtocolVersion
-org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache
org.apache.harmony.xnet.provider.jsse.SSLContextImpl
org.apache.harmony.xnet.provider.jsse.SSLParameters
-org.apache.harmony.xnet.provider.jsse.ServerSessionContext
-org.apache.harmony.xnet.provider.jsse.ServerSessionContext$1
org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl
-org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl$1
-org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl$2
org.apache.harmony.xnet.provider.jsse.TrustManagerImpl
-org.apache.http.ConnectionReuseStrategy
-org.apache.http.FormattedHeader
-org.apache.http.Header
-org.apache.http.HeaderElement
-org.apache.http.HeaderElementIterator
-org.apache.http.HeaderIterator
-org.apache.http.HttpClientConnection
-org.apache.http.HttpConnection
-org.apache.http.HttpConnectionMetrics
-org.apache.http.HttpEntity
-org.apache.http.HttpEntityEnclosingRequest
-org.apache.http.HttpException
org.apache.http.HttpHost
-org.apache.http.HttpInetConnection
-org.apache.http.HttpMessage
-org.apache.http.HttpRequest
org.apache.http.HttpRequestInterceptor
-org.apache.http.HttpResponse
-org.apache.http.HttpResponseFactory
-org.apache.http.HttpResponseInterceptor
org.apache.http.HttpVersion
-org.apache.http.NameValuePair
-org.apache.http.ProtocolException
-org.apache.http.ProtocolVersion
-org.apache.http.ReasonPhraseCatalog
-org.apache.http.RequestLine
-org.apache.http.StatusLine
-org.apache.http.TokenIterator
-org.apache.http.auth.AuthSchemeFactory
org.apache.http.auth.AuthSchemeRegistry
-org.apache.http.auth.AuthState
-org.apache.http.client.AuthenticationHandler
-org.apache.http.client.ClientProtocolException
-org.apache.http.client.CookieStore
-org.apache.http.client.CredentialsProvider
org.apache.http.client.HttpClient
-org.apache.http.client.HttpRequestRetryHandler
-org.apache.http.client.RedirectHandler
org.apache.http.client.RequestDirector
-org.apache.http.client.ResponseHandler
-org.apache.http.client.UserTokenHandler
-org.apache.http.client.methods.AbortableHttpRequest
-org.apache.http.client.methods.HttpEntityEnclosingRequestBase
-org.apache.http.client.methods.HttpGet
-org.apache.http.client.methods.HttpPost
org.apache.http.client.methods.HttpRequestBase
-org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.params.HttpClientParams
org.apache.http.client.protocol.RequestAddCookies
org.apache.http.client.protocol.RequestDefaultHeaders
org.apache.http.client.protocol.RequestProxyAuthentication
org.apache.http.client.protocol.RequestTargetAuthentication
org.apache.http.client.protocol.ResponseProcessCookies
-org.apache.http.client.utils.URIUtils
-org.apache.http.conn.BasicManagedEntity
-org.apache.http.conn.ClientConnectionManager
-org.apache.http.conn.ClientConnectionOperator
-org.apache.http.conn.ClientConnectionRequest
-org.apache.http.conn.ConnectionKeepAliveStrategy
-org.apache.http.conn.ConnectionReleaseTrigger
-org.apache.http.conn.EofSensorInputStream
-org.apache.http.conn.EofSensorWatcher
-org.apache.http.conn.ManagedClientConnection
-org.apache.http.conn.OperatedClientConnection
-org.apache.http.conn.params.ConnManagerPNames
-org.apache.http.conn.params.ConnManagerParams
org.apache.http.conn.params.ConnManagerParams$1
-org.apache.http.conn.params.ConnPerRoute
-org.apache.http.conn.params.ConnPerRouteBean
-org.apache.http.conn.params.ConnRoutePNames
org.apache.http.conn.params.ConnRouteParams
-org.apache.http.conn.routing.BasicRouteDirector
org.apache.http.conn.routing.HttpRoute
-org.apache.http.conn.routing.HttpRouteDirector
-org.apache.http.conn.routing.HttpRoutePlanner
-org.apache.http.conn.routing.RouteInfo
org.apache.http.conn.routing.RouteInfo$LayerType
org.apache.http.conn.routing.RouteInfo$TunnelType
org.apache.http.conn.routing.RouteTracker
-org.apache.http.conn.scheme.LayeredSocketFactory
org.apache.http.conn.scheme.PlainSocketFactory
org.apache.http.conn.scheme.Scheme
org.apache.http.conn.scheme.SchemeRegistry
-org.apache.http.conn.scheme.SocketFactory
-org.apache.http.conn.ssl.AbstractVerifier
org.apache.http.conn.ssl.AllowAllHostnameVerifier
org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
org.apache.http.conn.ssl.SSLSocketFactory
org.apache.http.conn.ssl.StrictHostnameVerifier
-org.apache.http.conn.ssl.X509HostnameVerifier
-org.apache.http.cookie.ClientCookie
-org.apache.http.cookie.Cookie
-org.apache.http.cookie.CookieAttributeHandler
-org.apache.http.cookie.CookieIdentityComparator
-org.apache.http.cookie.CookieOrigin
-org.apache.http.cookie.CookiePathComparator
-org.apache.http.cookie.CookieSpec
-org.apache.http.cookie.CookieSpecFactory
+org.apache.http.conn.util.InetAddressUtils
org.apache.http.cookie.CookieSpecRegistry
-org.apache.http.cookie.SetCookie
-org.apache.http.entity.AbstractHttpEntity
-org.apache.http.entity.BasicHttpEntity
-org.apache.http.entity.ByteArrayEntity
-org.apache.http.entity.ContentLengthStrategy
-org.apache.http.entity.HttpEntityWrapper
-org.apache.http.entity.StringEntity
-org.apache.http.impl.AbstractHttpClientConnection
org.apache.http.impl.DefaultConnectionReuseStrategy
org.apache.http.impl.DefaultHttpResponseFactory
org.apache.http.impl.EnglishReasonPhraseCatalog
@@ -2241,124 +1072,49 @@
org.apache.http.impl.auth.DigestSchemeFactory
org.apache.http.impl.client.AbstractAuthenticationHandler
org.apache.http.impl.client.AbstractHttpClient
-org.apache.http.impl.client.BasicCookieStore
org.apache.http.impl.client.BasicCredentialsProvider
-org.apache.http.impl.client.ClientParamsStack
-org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
org.apache.http.impl.client.DefaultHttpClient
org.apache.http.impl.client.DefaultHttpRequestRetryHandler
org.apache.http.impl.client.DefaultProxyAuthenticationHandler
org.apache.http.impl.client.DefaultRedirectHandler
-org.apache.http.impl.client.DefaultRequestDirector
org.apache.http.impl.client.DefaultTargetAuthenticationHandler
org.apache.http.impl.client.DefaultUserTokenHandler
org.apache.http.impl.client.EntityEnclosingRequestWrapper
-org.apache.http.impl.client.RequestWrapper
-org.apache.http.impl.client.RoutedRequest
org.apache.http.impl.conn.AbstractClientConnAdapter
-org.apache.http.impl.conn.AbstractPoolEntry
-org.apache.http.impl.conn.AbstractPooledConnAdapter
org.apache.http.impl.conn.DefaultClientConnection
org.apache.http.impl.conn.DefaultClientConnectionOperator
org.apache.http.impl.conn.DefaultHttpRoutePlanner
org.apache.http.impl.conn.DefaultResponseParser
org.apache.http.impl.conn.IdleConnectionHandler
-org.apache.http.impl.conn.IdleConnectionHandler$TimeValues
-org.apache.http.impl.conn.SingleClientConnManager
-org.apache.http.impl.conn.SingleClientConnManager$1
-org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter
-org.apache.http.impl.conn.SingleClientConnManager$PoolEntry
-org.apache.http.impl.conn.tsccm.AbstractConnPool
org.apache.http.impl.conn.tsccm.BasicPoolEntry
org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
-org.apache.http.impl.conn.tsccm.BasicPooledConnAdapter
org.apache.http.impl.conn.tsccm.ConnPoolByRoute
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1
-org.apache.http.impl.conn.tsccm.PoolEntryRequest
-org.apache.http.impl.conn.tsccm.RefQueueHandler
org.apache.http.impl.conn.tsccm.RefQueueWorker
org.apache.http.impl.conn.tsccm.RouteSpecificPool
org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1
-org.apache.http.impl.conn.tsccm.WaitingThreadAborter
-org.apache.http.impl.cookie.AbstractCookieAttributeHandler
-org.apache.http.impl.cookie.AbstractCookieSpec
org.apache.http.impl.cookie.BasicClientCookie
-org.apache.http.impl.cookie.BasicCommentHandler
-org.apache.http.impl.cookie.BasicDomainHandler
-org.apache.http.impl.cookie.BasicExpiresHandler
-org.apache.http.impl.cookie.BasicMaxAgeHandler
-org.apache.http.impl.cookie.BasicPathHandler
-org.apache.http.impl.cookie.BasicSecureHandler
-org.apache.http.impl.cookie.BestMatchSpec
org.apache.http.impl.cookie.BestMatchSpecFactory
-org.apache.http.impl.cookie.BrowserCompatSpec
org.apache.http.impl.cookie.BrowserCompatSpecFactory
-org.apache.http.impl.cookie.CookieSpecBase
org.apache.http.impl.cookie.DateUtils
org.apache.http.impl.cookie.NetscapeDraftSpecFactory
-org.apache.http.impl.cookie.RFC2109DomainHandler
-org.apache.http.impl.cookie.RFC2109Spec
org.apache.http.impl.cookie.RFC2109SpecFactory
-org.apache.http.impl.cookie.RFC2109VersionHandler
-org.apache.http.impl.cookie.RFC2965CommentUrlAttributeHandler
-org.apache.http.impl.cookie.RFC2965DiscardAttributeHandler
-org.apache.http.impl.cookie.RFC2965DomainAttributeHandler
-org.apache.http.impl.cookie.RFC2965PortAttributeHandler
-org.apache.http.impl.cookie.RFC2965Spec
org.apache.http.impl.cookie.RFC2965SpecFactory
-org.apache.http.impl.cookie.RFC2965VersionAttributeHandler
org.apache.http.impl.entity.EntityDeserializer
org.apache.http.impl.entity.EntitySerializer
org.apache.http.impl.entity.LaxContentLengthStrategy
org.apache.http.impl.entity.StrictContentLengthStrategy
-org.apache.http.impl.io.AbstractMessageParser
-org.apache.http.impl.io.AbstractMessageWriter
-org.apache.http.impl.io.AbstractSessionInputBuffer
-org.apache.http.impl.io.AbstractSessionOutputBuffer
-org.apache.http.impl.io.ChunkedInputStream
-org.apache.http.impl.io.ContentLengthInputStream
-org.apache.http.impl.io.ContentLengthOutputStream
org.apache.http.impl.io.HttpRequestWriter
org.apache.http.impl.io.HttpTransportMetricsImpl
org.apache.http.impl.io.SocketInputBuffer
org.apache.http.impl.io.SocketOutputBuffer
-org.apache.http.io.HttpMessageParser
-org.apache.http.io.HttpMessageWriter
-org.apache.http.io.HttpTransportMetrics
-org.apache.http.io.SessionInputBuffer
-org.apache.http.io.SessionOutputBuffer
-org.apache.http.message.AbstractHttpMessage
-org.apache.http.message.BasicHeader
-org.apache.http.message.BasicHeaderElement
-org.apache.http.message.BasicHeaderElementIterator
org.apache.http.message.BasicHeaderValueParser
+org.apache.http.message.BasicHttpEntityEnclosingRequest
org.apache.http.message.BasicHttpResponse
org.apache.http.message.BasicLineFormatter
org.apache.http.message.BasicLineParser
-org.apache.http.message.BasicListHeaderIterator
-org.apache.http.message.BasicNameValuePair
-org.apache.http.message.BasicRequestLine
-org.apache.http.message.BasicStatusLine
-org.apache.http.message.BasicTokenIterator
-org.apache.http.message.BufferedHeader
-org.apache.http.message.HeaderGroup
-org.apache.http.message.HeaderValueParser
-org.apache.http.message.LineFormatter
-org.apache.http.message.LineParser
-org.apache.http.message.ParserCursor
-org.apache.http.params.AbstractHttpParams
org.apache.http.params.BasicHttpParams
-org.apache.http.params.CoreConnectionPNames
-org.apache.http.params.CoreProtocolPNames
-org.apache.http.params.HttpConnectionParams
-org.apache.http.params.HttpParams
-org.apache.http.params.HttpProtocolParams
-org.apache.http.protocol.BasicHttpContext
org.apache.http.protocol.BasicHttpProcessor
org.apache.http.protocol.HTTP
-org.apache.http.protocol.HttpContext
-org.apache.http.protocol.HttpProcessor
org.apache.http.protocol.HttpRequestExecutor
org.apache.http.protocol.HttpRequestInterceptorList
org.apache.http.protocol.HttpResponseInterceptorList
@@ -2370,48 +1126,23 @@
org.apache.http.util.ByteArrayBuffer
org.apache.http.util.CharArrayBuffer
org.apache.http.util.EntityUtils
-org.apache.http.util.LangUtils
org.apache.http.util.VersionInfo
-org.bouncycastle.asn1.ASN1Choice
-org.bouncycastle.asn1.ASN1Collection
-org.bouncycastle.asn1.ASN1Collection$ASN1CollectionEnumeration
-org.bouncycastle.asn1.ASN1Encodable
-org.bouncycastle.asn1.ASN1EncodableVector
-org.bouncycastle.asn1.ASN1InputStream
-org.bouncycastle.asn1.ASN1InputStream$1
-org.bouncycastle.asn1.ASN1Null
-org.bouncycastle.asn1.ASN1OctetString
-org.bouncycastle.asn1.ASN1OutputStream
-org.bouncycastle.asn1.ASN1Sequence
-org.bouncycastle.asn1.ASN1Set
-org.bouncycastle.asn1.ASN1TaggedObject
org.bouncycastle.asn1.DERBitString
-org.bouncycastle.asn1.DERBoolean
-org.bouncycastle.asn1.DEREncodable
-org.bouncycastle.asn1.DEREncodableVector
org.bouncycastle.asn1.DERIA5String
org.bouncycastle.asn1.DERInteger
-org.bouncycastle.asn1.DERNull
org.bouncycastle.asn1.DERObject
org.bouncycastle.asn1.DERObjectIdentifier
org.bouncycastle.asn1.DEROctetString
-org.bouncycastle.asn1.DEROutputStream
org.bouncycastle.asn1.DERPrintableString
org.bouncycastle.asn1.DERSequence
org.bouncycastle.asn1.DERSet
-org.bouncycastle.asn1.DERString
org.bouncycastle.asn1.DERTaggedObject
-org.bouncycastle.asn1.DERTags
org.bouncycastle.asn1.DERUTCTime
org.bouncycastle.asn1.DERUTF8String
-org.bouncycastle.asn1.OIDTokenizer
org.bouncycastle.asn1.OrderedTable
-org.bouncycastle.asn1.iana.IANAObjectIdentifiers
org.bouncycastle.asn1.nist.NISTObjectIdentifiers
-org.bouncycastle.asn1.oiw.OIWObjectIdentifiers
org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
org.bouncycastle.asn1.x509.AlgorithmIdentifier
-org.bouncycastle.asn1.x509.BasicConstraints
org.bouncycastle.asn1.x509.RSAPublicKeyStructure
org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
org.bouncycastle.asn1.x509.TBSCertificateStructure
@@ -2421,53 +1152,26 @@
org.bouncycastle.asn1.x509.X509Extensions
org.bouncycastle.asn1.x509.X509Name
org.bouncycastle.asn1.x509.X509NameElementList
-org.bouncycastle.asn1.x509.X509ObjectIdentifiers
-org.bouncycastle.crypto.CipherParameters
-org.bouncycastle.crypto.Digest
-org.bouncycastle.crypto.ExtendedDigest
-org.bouncycastle.crypto.Mac
-org.bouncycastle.crypto.PBEParametersGenerator
+org.bouncycastle.asn1.x9.X9ObjectIdentifiers
org.bouncycastle.crypto.engines.AESFastEngine
-org.bouncycastle.crypto.generators.PKCS12ParametersGenerator
-org.bouncycastle.crypto.io.MacInputStream
-org.bouncycastle.crypto.macs.HMac
-org.bouncycastle.crypto.params.KeyParameter
-org.bouncycastle.jce.interfaces.BCKeyStore
-org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier
-org.bouncycastle.jce.provider.BouncyCastleProvider
org.bouncycastle.jce.provider.CertPathValidatorUtilities
org.bouncycastle.jce.provider.JCEBlockCipher$AES
org.bouncycastle.jce.provider.JCERSAPublicKey
-org.bouncycastle.jce.provider.JDKKeyFactory
org.bouncycastle.jce.provider.JDKKeyFactory$RSA
org.bouncycastle.jce.provider.JDKKeyStore
org.bouncycastle.jce.provider.JDKKeyStore$StoreEntry
-org.bouncycastle.jce.provider.JDKX509CertificateFactory
org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-org.bouncycastle.jce.provider.PKIXPolicyNode
org.bouncycastle.jce.provider.RSAUtil
org.bouncycastle.jce.provider.X509CertificateObject
-org.bouncycastle.util.Strings
org.ccil.cowan.tagsoup.HTMLScanner
org.ccil.cowan.tagsoup.Parser
org.json.JSONArray
org.json.JSONObject
-org.json.JSONObject$Null
-org.json.JSONTokener
+org.json.JSONStringer
org.kxml2.io.KXmlParser
org.kxml2.io.KXmlSerializer
-org.openssl.NativeBN
-org.w3c.dom.DOMImplementation
-org.xml.sax.Attributes
-org.xml.sax.ContentHandler
-org.xml.sax.DTDHandler
-org.xml.sax.EntityResolver
-org.xml.sax.ErrorHandler
-org.xml.sax.InputSource
-org.xml.sax.Locator
-org.xml.sax.XMLReader
org.xml.sax.helpers.DefaultHandler
-org.xmlpull.v1.XmlPullParser
+org.xml.sax.helpers.NewInstance
org.xmlpull.v1.XmlPullParserFactory
-org.xmlpull.v1.XmlSerializer
+org.xmlpull.v1.sax2.Driver
sun.misc.Unsafe
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6e28515..4eed7fe 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -31,6 +31,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageInfo;
+import android.content.pm.PermissionInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
@@ -46,6 +47,8 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
@@ -91,6 +94,20 @@
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
+ // Event tags -- see system/core/logcat/event-log-tags
+ private static final int BACKUP_DATA_CHANGED_EVENT = 2820;
+ private static final int BACKUP_START_EVENT = 2821;
+ private static final int BACKUP_TRANSPORT_FAILURE_EVENT = 2822;
+ private static final int BACKUP_AGENT_FAILURE_EVENT = 2823;
+ private static final int BACKUP_PACKAGE_EVENT = 2824;
+ private static final int BACKUP_SUCCESS_EVENT = 2825;
+
+ private static final int RESTORE_START_EVENT = 2830;
+ private static final int RESTORE_TRANSPORT_FAILURE_EVENT = 2831;
+ private static final int RESTORE_AGENT_FAILURE_EVENT = 2832;
+ private static final int RESTORE_PACKAGE_EVENT = 2833;
+ private static final int RESTORE_SUCCESS_EVENT = 2834;
+
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -100,18 +117,18 @@
private PowerManager mPowerManager;
private AlarmManager mAlarmManager;
- private boolean mEnabled; // access to this is synchronized on 'this'
- private boolean mProvisioned;
- private PowerManager.WakeLock mWakelock;
- private final BackupHandler mBackupHandler = new BackupHandler();
- private PendingIntent mRunBackupIntent;
- private BroadcastReceiver mRunBackupReceiver;
- private IntentFilter mRunBackupFilter;
+ boolean mEnabled; // access to this is synchronized on 'this'
+ boolean mProvisioned;
+ PowerManager.WakeLock mWakelock;
+ final BackupHandler mBackupHandler = new BackupHandler();
+ PendingIntent mRunBackupIntent;
+ BroadcastReceiver mRunBackupReceiver;
+ IntentFilter mRunBackupFilter;
// map UIDs to the set of backup client services within that UID's app set
- private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
+ final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
= new SparseArray<HashSet<ApplicationInfo>>();
// set of backup services that have pending changes
- private class BackupRequest {
+ class BackupRequest {
public ApplicationInfo appInfo;
public boolean fullBackup;
@@ -125,35 +142,35 @@
}
}
// Backups that we haven't started yet.
- private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
+ HashMap<ApplicationInfo,BackupRequest> mPendingBackups
= new HashMap<ApplicationInfo,BackupRequest>();
// Pseudoname that we use for the Package Manager metadata "package"
- private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+ static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
// locking around the pending-backup management
- private final Object mQueueLock = new Object();
+ final Object mQueueLock = new Object();
// The thread performing the sequence of queued backups binds to each app's agent
// in succession. Bind notifications are asynchronously delivered through the
// Activity Manager; use this lock object to signal when a requested binding has
// completed.
- private final Object mAgentConnectLock = new Object();
- private IBackupAgent mConnectedAgent;
- private volatile boolean mConnecting;
+ final Object mAgentConnectLock = new Object();
+ IBackupAgent mConnectedAgent;
+ volatile boolean mConnecting;
// A similar synchronicity mechanism around clearing apps' data for restore
- private final Object mClearDataLock = new Object();
- private volatile boolean mClearingData;
+ final Object mClearDataLock = new Object();
+ volatile boolean mClearingData;
// Transport bookkeeping
- private final HashMap<String,IBackupTransport> mTransports
+ final HashMap<String,IBackupTransport> mTransports
= new HashMap<String,IBackupTransport>();
- private String mCurrentTransport;
- private IBackupTransport mLocalTransport, mGoogleTransport;
- private RestoreSession mActiveRestoreSession;
+ String mCurrentTransport;
+ IBackupTransport mLocalTransport, mGoogleTransport;
+ RestoreSession mActiveRestoreSession;
- private class RestoreParams {
+ class RestoreParams {
public IBackupTransport transport;
public IRestoreObserver observer;
public long token;
@@ -165,7 +182,7 @@
}
}
- private class ClearParams {
+ class ClearParams {
public IBackupTransport transport;
public PackageInfo packageInfo;
@@ -176,11 +193,17 @@
}
// Where we keep our journal files and other bookkeeping
- private File mBaseStateDir;
- private File mDataDir;
- private File mJournalDir;
- private File mJournal;
- private RandomAccessFile mJournalStream;
+ File mBaseStateDir;
+ File mDataDir;
+ File mJournalDir;
+ File mJournal;
+ RandomAccessFile mJournalStream;
+
+ // Keep a log of all the apps we've ever backed up
+ private File mEverStored;
+ private RandomAccessFile mEverStoredStream;
+ HashSet<String> mEverStoredApps = new HashSet<String>();
+
public BackupManagerService(Context context) {
mContext = context;
@@ -195,7 +218,7 @@
Settings.Secure.BACKUP_ENABLED, 0) != 0;
// !!! TODO: mProvisioned needs to default to 0, not 1.
mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.BACKUP_PROVISIONED, 1) != 0;
+ Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mDataDir = Environment.getDownloadCacheDirectory();
@@ -215,6 +238,9 @@
mJournalDir.mkdirs(); // creates mBaseStateDir along the way
makeJournalLocked(); // okay because no other threads are running yet
+ // Set up the various sorts of package tracking we do
+ initPackageTracking();
+
// Build our mapping of uid to backup client services. This implicitly
// schedules a backup pass on the Package Manager metadata the first
// time anything needs to be backed up.
@@ -249,14 +275,6 @@
// leftover journal files into the pending backup set
parseLeftoverJournals();
- // Register for broadcasts about package install, etc., so we can
- // update the provider list.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
// Power management
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
@@ -281,6 +299,73 @@
}
}
+ private void initPackageTracking() {
+ if (DEBUG) Log.v(TAG, "Initializing package tracking");
+
+ // Keep a log of what apps we've ever backed up. Because we might have
+ // rebooted in the middle of an operation that was removing something from
+ // this log, we sanity-check its contents here and reconstruct it.
+ mEverStored = new File(mBaseStateDir, "processed");
+ File tempProcessedFile = new File(mBaseStateDir, "processed.new");
+ try {
+ // If there are previous contents, parse them out then start a new
+ // file to continue the recordkeeping.
+ if (mEverStored.exists()) {
+ RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rw");
+ mEverStoredStream = new RandomAccessFile(mEverStored, "r");
+
+ // parse its existing contents
+ mEverStoredStream.seek(0);
+ temp.seek(0);
+ try {
+ while (true) {
+ PackageInfo info;
+ String pkg = mEverStoredStream.readUTF();
+ try {
+ info = mPackageManager.getPackageInfo(pkg, 0);
+ mEverStoredApps.add(pkg);
+ temp.writeUTF(pkg);
+ if (DEBUG) Log.v(TAG, " + " + pkg);
+ } catch (NameNotFoundException e) {
+ // nope, this package was uninstalled; don't include it
+ if (DEBUG) Log.v(TAG, " - " + pkg);
+ }
+ }
+ } catch (EOFException e) {
+ // now we're at EOF
+ }
+
+ // Once we've rewritten the backup history log, atomically replace the
+ // old one with the new one then reopen the file for continuing use.
+ temp.close();
+ mEverStoredStream.close();
+ tempProcessedFile.renameTo(mEverStored);
+ }
+ // This will create the file if it doesn't exist
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ mEverStoredStream.seek(mEverStoredStream.length());
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to open known-stored file!");
+ mEverStoredStream = null;
+ }
+
+ // If we were in the middle of removing something from the ever-backed-up
+ // file, there might be a transient "processed.new" file still present.
+ // We've reconstructed a coherent state at this point though, so we can
+ // safely discard that file now.
+ if (tempProcessedFile.exists()) {
+ tempProcessedFile.delete();
+ }
+
+ // Register for broadcasts about package install, etc., so we can
+ // update the provider list.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
private void makeJournalLocked() {
try {
mJournal = File.createTempFile("journal", null, mJournalDir);
@@ -485,6 +570,17 @@
mBackupParticipants.put(uid, set);
}
set.add(pkg.applicationInfo);
+
+ // If we've never seen this app before, schedule a backup for it
+ if (!mEverStoredApps.contains(pkg.packageName)) {
+ if (DEBUG) Log.i(TAG, "New app " + pkg.packageName
+ + " never backed up; scheduling");
+ try {
+ dataChanged(pkg.packageName);
+ } catch (RemoteException e) {
+ // can't happen; it's a local method call
+ }
+ }
}
}
}
@@ -528,6 +624,7 @@
for (ApplicationInfo entry: set) {
if (entry.packageName.equals(pkg.packageName)) {
set.remove(entry);
+ removeEverBackedUp(pkg.packageName);
break;
}
}
@@ -540,15 +637,18 @@
}
// Returns the set of all applications that define an android:backupAgent attribute
- private List<PackageInfo> allAgentPackages() {
+ List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
int flags = PackageManager.GET_SIGNATURES;
List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
int N = packages.size();
for (int a = N-1; a >= 0; a--) {
- ApplicationInfo app = packages.get(a).applicationInfo;
+ PackageInfo pkg = packages.get(a);
+ ApplicationInfo app = pkg.applicationInfo;
if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null) {
+ || app.backupAgentName == null
+ || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
packages.remove(a);
}
}
@@ -570,6 +670,65 @@
addPackageParticipantsLockedInner(packageName, allApps);
}
+ // Called from the backup thread: record that the given app has been successfully
+ // backed up at least once
+ void logBackupComplete(String packageName) {
+ if (mEverStoredStream != null && !packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ synchronized (mEverStoredApps) {
+ if (mEverStoredApps.add(packageName)) {
+ try {
+ mEverStoredStream.writeUTF(packageName);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to log backup of " + packageName + ", ceasing log");
+ try {
+ mEverStoredStream.close();
+ } catch (IOException ioe) {
+ // we're dropping it; no need to handle an exception on close here
+ }
+ mEverStoredStream = null;
+ }
+ }
+ }
+ }
+ }
+
+ // Remove our awareness of having ever backed up the given package
+ void removeEverBackedUp(String packageName) {
+ if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName
+ + ", new set:");
+
+ if (mEverStoredStream != null) {
+ synchronized (mEverStoredApps) {
+ // Rewrite the file and rename to overwrite. If we reboot in the middle,
+ // we'll recognize on initialization time that the package no longer
+ // exists and fix it up then.
+ File tempKnownFile = new File(mBaseStateDir, "processed.new");
+ try {
+ mEverStoredStream.close();
+ RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rw");
+ mEverStoredApps.remove(packageName);
+ for (String s : mEverStoredApps) {
+ known.writeUTF(s);
+ if (DEBUG) Log.v(TAG, " " + s);
+ }
+ known.close();
+ tempKnownFile.renameTo(mEverStored);
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ } catch (IOException e) {
+ // Bad: we couldn't create the new copy. For safety's sake we
+ // abandon the whole process and remove all what's-backed-up
+ // state entirely, meaning we'll force a backup pass for every
+ // participant on the next boot or [re]install.
+ Log.w(TAG, "Error rewriting backed-up set; halting log");
+ mEverStoredStream = null;
+ mEverStoredApps.clear();
+ tempKnownFile.delete();
+ mEverStored.delete();
+ }
+ }
+ }
+ }
+
// Return the given transport
private IBackupTransport getTransport(String transportName) {
synchronized (mTransports) {
@@ -637,6 +796,14 @@
synchronized(mClearDataLock) {
mClearingData = true;
+ /* This is causing some critical processes to be killed during setup.
+ Temporarily revert this change until we find a better solution.
+ try {
+ mActivityManager.clearApplicationUserData(packageName, observer);
+ } catch (RemoteException e) {
+ // can't happen because the activity manager is in this process
+ }
+ */
mPackageManager.clearApplicationUserData(packageName, observer);
// only wait 10 seconds for the clear data to happen
@@ -654,7 +821,7 @@
class ClearDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded)
- throws android.os.RemoteException {
+ throws RemoteException {
synchronized(mClearDataLock) {
mClearingData = false;
mClearDataLock.notifyAll();
@@ -687,49 +854,64 @@
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
// Backups run at background priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // The package manager doesn't have a proper <application> etc, but since
- // it's running here in the system process we can just set up its agent
- // directly and use a synthetic BackupRequest. We always run this pass
- // because it's cheap and this way we guarantee that we don't get out of
- // step even if we're selecting among various transports at run time.
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentPackages());
- BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
- pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
- processOneBackup(pmRequest,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()),
- mTransport);
-
- // Now run all the backups in our queue
- doQueuedBackups(mTransport);
-
- // Finally, tear down the transport
try {
- if (!mTransport.finishBackup()) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in finishBackup()");
+ EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
+
+ // The package manager doesn't have a proper <application> etc, but since
+ // it's running here in the system process we can just set up its agent
+ // directly and use a synthetic BackupRequest. We always run this pass
+ // because it's cheap and this way we guarantee that we don't get out of
+ // step even if we're selecting among various transports at run time.
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentPackages());
+ BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+ pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneBackup(pmRequest,
+ IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
+
+ // Now run all the backups in our queue
+ int count = mQueue.size();
+ doQueuedBackups(mTransport);
+
+ // Finally, tear down the transport
+ if (mTransport.finishBackup()) {
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(BACKUP_SUCCESS_EVENT, count, millis);
+ } else {
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
+ Log.e(TAG, "Transport error in finishBackup()");
}
- } catch (RemoteException e) {
- Log.e(TAG, "Error in finishBackup()", e);
- }
- if (!mJournal.delete()) {
- Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
+ if (!mJournal.delete()) {
+ Log.e(TAG, "Unable to remove backup journal file " + mJournal);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error in backup thread", e);
+ } finally {
+ // Only once we're entirely finished do we release the wakelock
+ mWakelock.release();
}
-
- // Only once we're entirely finished do we release the wakelock
- mWakelock.release();
}
private void doQueuedBackups(IBackupTransport transport) {
for (BackupRequest request : mQueue) {
Log.d(TAG, "starting agent for backup of " + request);
+ // Don't run backup, even if requested, if the target app does not have
+ // the requisite permission
+ if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ request.appInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "Skipping backup of unprivileged package "
+ + request.appInfo.packageName);
+ continue;
+ }
+
IBackupAgent agent = null;
int mode = (request.fullBackup)
? IApplicationThread.BACKUP_MODE_FULL
@@ -749,19 +931,27 @@
Log.v(TAG, "bind/backup threw");
e.printStackTrace();
}
-
}
}
void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) {
final String packageName = request.appInfo.packageName;
- Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ // !!! TODO: get the state file dir from the transport
+ File savedStateName = new File(mStateDir, packageName);
+ File backupDataName = new File(mDataDir, packageName + ".data");
+ File newStateName = new File(mStateDir, packageName + ".new");
+
+ ParcelFileDescriptor savedState = null;
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
+ PackageInfo packInfo;
try {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
// be unraveled.
- PackageInfo packInfo;
if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
// The metadata 'package' is synthetic
packInfo = new PackageInfo();
@@ -771,68 +961,65 @@
PackageManager.GET_SIGNATURES);
}
- // !!! TODO: get the state file dir from the transport
- File savedStateName = new File(mStateDir, packageName);
- File backupDataName = new File(mDataDir, packageName + ".data");
- File newStateName = new File(mStateDir, packageName + ".new");
-
// In a full backup, we pass a null ParcelFileDescriptor as
// the saved-state "file"
- ParcelFileDescriptor savedState = (request.fullBackup) ? null
- : ParcelFileDescriptor.open(savedStateName,
+ if (!request.fullBackup) {
+ savedState = ParcelFileDescriptor.open(savedStateName,
ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE);
+ ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
+ }
- backupDataName.delete();
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
- newStateName.delete();
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
// Run the target's backup pass
- boolean success = false;
- try {
- agent.doBackup(savedState, backupData, newState);
- success = true;
- } finally {
- if (savedState != null) {
- savedState.close();
- }
- backupData.close();
- newState.close();
- }
-
- // Now propagate the newly-backed-up data to the transport
- if (success) {
- if (DEBUG) Log.v(TAG, "doBackup() success");
- if (backupDataName.length() > 0) {
- backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
- if (!transport.performBackup(packInfo, backupData)) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in performBackup()");
- }
- } else {
- if (DEBUG) {
- Log.i(TAG, "no backup data written; not calling transport");
- }
- }
-
- // After successful transport, delete the now-stale data
- // and juggle the files so that next time we supply the agent
- // with the new state file it just created.
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
- }
+ agent.doBackup(savedState, backupData, newState);
+ logBackupComplete(packageName);
+ if (DEBUG) Log.v(TAG, "doBackup() success");
} catch (Exception e) {
Log.e(TAG, "Error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_AGENT_FAILURE_EVENT, packageName, e.toString());
+ backupDataName.delete();
+ newStateName.delete();
+ return;
+ } finally {
+ try { if (savedState != null) savedState.close(); } catch (IOException e) {}
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ savedState = backupData = newState = null;
+ }
+
+ // Now propagate the newly-backed-up data to the transport
+ try {
+ int size = (int) backupDataName.length();
+ if (size > 0) {
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ if (!transport.performBackup(packInfo, backupData)) throw new Exception();
+ } else {
+ if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
+ }
+
+ // After successful transport, delete the now-stale data
+ // and juggle the files so that next time we supply the agent
+ // with the new state file it just created.
+ backupDataName.delete();
+ newStateName.renameTo(savedStateName);
+ EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
+ } catch (Exception e) {
+ Log.e(TAG, "Transport error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+ return;
+ } finally {
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
}
}
}
@@ -878,7 +1065,6 @@
private IBackupTransport mTransport;
private IRestoreObserver mObserver;
private long mToken;
- private RestoreSet mImage;
private File mStateDir;
class RestoreRequest {
@@ -908,14 +1094,15 @@
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
- + " mObserver=" + mObserver + " mToken=" + mToken);
+ + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken));
/**
* Restore sequence:
*
* 1. get the restore set description for our identity
* 2. for each app in the restore set:
- * 3.a. if it's restorable on this device, add it to the restore queue
+ * 2.a. if it's restorable on this device, add it to the restore queue
* 3. for each app in the restore queue:
* 3.a. clear the app data
* 3.b. get the restore data for the app from the transport
@@ -923,25 +1110,18 @@
* 3.d. agent.doRestore() with the data from the server
* 3.e. unbind the agent [and kill the app?]
* 4. shut down the transport
+ *
+ * On errors, we try our best to recover and move on to the next
+ * application, but if necessary we abort the whole operation --
+ * the user is waiting, after al.
*/
int error = -1; // assume error
// build the set of apps to restore
try {
- RestoreSet[] images = mTransport.getAvailableRestoreSets();
- if (images == null) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error getting restore sets");
- return;
- }
-
- if (images.length == 0) {
- Log.i(TAG, "No restore sets available");
- return;
- }
-
- mImage = images[0];
+ // TODO: Log this before getAvailableRestoreSets, somehow
+ EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName());
// Get the list of all packages which have backup enabled.
// (Include the Package Manager metadata pseudo-package first.)
@@ -966,22 +1146,26 @@
}
if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error starting restore operation");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
}
String packageName = mTransport.nextRestorePackage();
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting first restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
Log.i(TAG, "No restore data available");
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, 0, millis);
return;
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ "\", found only \"" + packageName + "\"");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager data missing");
return;
}
@@ -994,23 +1178,25 @@
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
if (!pmAgent.hasMetadata()) {
- Log.i(TAG, "No restore metadata available, so not restoring settings");
+ Log.e(TAG, "No restore metadata available, so not restoring settings");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager restore metadata missing");
return;
}
int count = 0;
for (;;) {
packageName = mTransport.nextRestorePackage();
+
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting next restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
break;
}
if (mObserver != null) {
- ++count;
try {
mObserver.onUpdate(count);
} catch (RemoteException e) {
@@ -1022,21 +1208,34 @@
Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
if (metaInfo == null) {
Log.e(TAG, "Missing metadata for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package metadata missing");
continue;
}
- int flags = PackageManager.GET_SIGNATURES;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ PackageInfo packageInfo;
+ try {
+ int flags = PackageManager.GET_SIGNATURES;
+ packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Invalid package restoring data", e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package missing on device");
+ continue;
+ }
+
if (metaInfo.versionCode > packageInfo.versionCode) {
- Log.w(TAG, "Package " + packageName
- + " restore version [" + metaInfo.versionCode
- + "] is too new for installed version ["
- + packageInfo.versionCode + "]");
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Log.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, message);
continue;
}
if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
Log.w(TAG, "Signature mismatch restoring " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Signature mismatch");
continue;
}
@@ -1052,11 +1251,14 @@
IApplicationThread.BACKUP_MODE_RESTORE);
if (agent == null) {
Log.w(TAG, "Can't find backup agent for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Restore agent missing");
continue;
}
try {
processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ ++count;
} finally {
// unbind even on timeout or failure, just in case
mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
@@ -1065,21 +1267,19 @@
// if we get this far, report success to the observer
error = 0;
- } catch (NameNotFoundException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Invalid paackage restoring data", e);
- } catch (RemoteException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error restoring data", e);
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, count, millis);
+ } catch (Exception e) {
+ Log.e(TAG, "Error in restore thread", e);
} finally {
+ if (DEBUG) Log.d(TAG, "finishing restore mObserver=" + mObserver);
+
try {
mTransport.finishRestore();
} catch (RemoteException e) {
Log.e(TAG, "Error finishing restore", e);
}
- Log.d(TAG, "finishing restore mObserver=" + mObserver);
-
if (mObserver != null) {
try {
mObserver.restoreFinished(error);
@@ -1098,51 +1298,64 @@
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
- Log.d(TAG, "processOneRestore packageName=" + packageName);
+ if (DEBUG) Log.d(TAG, "processOneRestore packageName=" + packageName);
+
+ // Don't restore to unprivileged packages
+ if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ packageName) != PackageManager.PERMISSION_GRANTED) {
+ Log.d(TAG, "Skipping restore of unprivileged package " + packageName);
+ }
// !!! TODO: get the dirs from the transport
File backupDataName = new File(mDataDir, packageName + ".restore");
- backupDataName.delete();
- try {
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ File newStateName = new File(mStateDir, packageName + ".new");
+ File savedStateName = new File(mStateDir, packageName);
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
+ try {
// Run the transport's restore pass
- // Run the target's backup pass
- try {
- if (!mTransport.getRestoreData(backupData)) {
- // STOPSHIP TODO: Handle this error somehow?
- Log.e(TAG, "Error getting restore data for " + packageName);
- return;
- }
- } finally {
- backupData.close();
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
+
+ if (!mTransport.getRestoreData(backupData)) {
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ return;
}
// Okay, we have the data. Now have the agent do the restore.
- File newStateName = new File(mStateDir, packageName + ".new");
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
-
+ backupData.close();
backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- agent.doRestore(backupData, appVersionCode, newState);
- } finally {
- newState.close();
- backupData.close();
- }
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
+
+ agent.doRestore(backupData, appVersionCode, newState);
// if everything went okay, remember the recorded state now
- File savedStateName = new File(mStateDir, packageName);
newStateName.renameTo(savedStateName);
+ int size = (int) backupDataName.length();
+ EventLog.writeEvent(RESTORE_PACKAGE_EVENT, packageName, size);
} catch (Exception e) {
Log.e(TAG, "Error restoring data for " + packageName, e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, e.toString());
+
+ // If the agent fails restore, it might have put the app's data
+ // into an incoherent state. For consistency we wipe its data
+ // again in this case before propagating the exception
+ clearApplicationDataSynchronous(packageName);
+ } finally {
+ backupDataName.delete();
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ backupData = newState = null;
}
}
}
@@ -1188,6 +1401,7 @@
// Record that we need a backup pass for the caller. Since multiple callers
// may share a uid, we need to note all candidates within that uid and schedule
// a backup pass for each of them.
+ EventLog.writeEvent(BACKUP_DATA_CHANGED_EVENT, packageName);
// If the caller does not hold the BACKUP permission, it can only request a
// backup of its own data.
@@ -1235,7 +1449,8 @@
}
}
} else {
- Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'");
+ Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
+ + " uid=" + Binder.getCallingUid());
}
}
@@ -1288,10 +1503,12 @@
if (DEBUG) Log.v(TAG, "Found the app - running clear process");
// found it; fire off the clear request
synchronized (mQueueLock) {
+ long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
new ClearParams(getTransport(mCurrentTransport), info));
mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
}
break;
}
@@ -1301,7 +1518,7 @@
// Run a backup pass immediately for any applications that have declared
// that they have pending updates.
public void backupNow() throws RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "backupNow");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
synchronized (mQueueLock) {
@@ -1370,13 +1587,13 @@
// Report whether the backup mechanism is currently enabled
public boolean isBackupEnabled() {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
return mEnabled; // no need to synchronize just to read it
}
// Report the name of the currently active transport
public String getCurrentTransport() {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getCurrentTransport");
Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
return mCurrentTransport;
@@ -1405,7 +1622,7 @@
// name is not one of the available transports, no action is taken and the method
// returns null.
public String selectBackupTransport(String transport) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
synchronized (mTransports) {
String prevTransport = null;
@@ -1459,7 +1676,7 @@
// Hand off a restore session
public IRestoreSession beginRestoreSession(String transport) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
synchronized(this) {
if (mActiveRestoreSession != null) {
@@ -1484,55 +1701,71 @@
}
// --- Binder interface ---
- public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ public synchronized RestoreSet[] getAvailableRestoreSets() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
try {
- synchronized(this) {
- if (mRestoreSets == null) {
+ if (mRestoreTransport == null) {
+ Log.w(TAG, "Null transport getting restore sets");
+ return null;
+ }
+ if (mRestoreSets == null) { // valid transport; do the one-time fetch
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
+ if (mRestoreSets == null) EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
}
return mRestoreSets;
- }
- } catch (RuntimeException e) {
- Log.d(TAG, "getAvailableRestoreSets exception");
- e.printStackTrace();
- throw e;
+ } catch (Exception e) {
+ Log.e(TAG, "Error in getAvailableRestoreSets", e);
+ return null;
}
}
- public int performRestore(long token, IRestoreObserver observer)
- throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "performRestore");
+ public synchronized int performRestore(long token, IRestoreObserver observer) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
- Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
+ if (DEBUG) Log.d(TAG, "performRestore token=" + Long.toHexString(token)
+ + " observer=" + observer);
- if (mRestoreSets != null) {
- for (int i = 0; i < mRestoreSets.length; i++) {
- if (token == mRestoreSets[i].token) {
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token);
- mBackupHandler.sendMessage(msg);
- return 0;
- }
- }
- } else {
- if (DEBUG) Log.v(TAG, "No current restore set, not doing restore");
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Log.e(TAG, "Ignoring performRestore() with no restore set");
+ return -1;
}
+
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+ }
+
+ Log.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
return -1;
}
- public void endRestoreSession() throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ public synchronized void endRestoreSession() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"endRestoreSession");
- Log.d(TAG, "endRestoreSession");
+ if (DEBUG) Log.d(TAG, "endRestoreSession");
- mRestoreTransport.finishRestore();
- mRestoreTransport = null;
- synchronized(BackupManagerService.this) {
+ synchronized (this) {
+ try {
+ if (mRestoreTransport != null) mRestoreTransport.finishRestore();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in finishRestore", e);
+ } finally {
+ mRestoreTransport = null;
+ }
+ }
+
+ synchronized (BackupManagerService.this) {
if (BackupManagerService.this.mActiveRestoreSession == this) {
BackupManagerService.this.mActiveRestoreSession = null;
} else {
@@ -1546,8 +1779,6 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
- long oldId = Binder.clearCallingIdentity();
-
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ " / " + (!mProvisioned ? "not " : "") + "provisioned");
pw.println("Available transports:");
@@ -1566,12 +1797,14 @@
pw.println(" " + app.toString());
}
}
+ pw.println("Ever backed up: " + mEverStoredApps.size());
+ for (String pkg : mEverStoredApps) {
+ pw.println(" " + pkg);
+ }
pw.println("Pending: " + mPendingBackups.size());
for (BackupRequest req : mPendingBackups.values()) {
pw.println(" " + req);
}
-
- Binder.restoreCallingIdentity(oldId);
}
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 90d8c9d..26fee89 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -45,7 +45,6 @@
import java.io.PrintWriter;
-
/**
* <p>BatteryService monitors the charging status, and charge level of the device
* battery. When these values change this service broadcasts the new values
@@ -92,6 +91,9 @@
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
+ private static final int BATTERY_LEVEL_CLOSE_WARNING = 20;
+ private static final int BATTERY_LEVEL_WARNING = 15;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -120,6 +122,7 @@
private long mDischargeStartTime;
private int mDischargeStartLevel;
+ private boolean mSentLowBatteryBroadcast = false;
public BatteryService(Context context) {
mContext = context;
@@ -171,6 +174,22 @@
return mBatteryLevel;
}
+ void systemReady() {
+ // check our power situation now that it is safe to display the shutdown dialog.
+ shutdownIfNoPower();
+ }
+
+ private final void shutdownIfNoPower() {
+ // shut down gracefully if our battery is critically low and we are not powered.
+ // wait until the system has booted before attempting to display the shutdown dialog.
+ if (mBatteryLevel == 0 && !isPowered() && ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
+
private native void native_update();
private synchronized final void update() {
@@ -178,7 +197,9 @@
boolean logOutlier = false;
long dischargeDuration = 0;
-
+
+ shutdownIfNoPower();
+
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
@@ -250,16 +271,28 @@
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
+ Intent statusIntent = new Intent();
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (mPlugType != 0 && mLastPlugType == 0) {
- Intent intent = new Intent(Intent.ACTION_POWER_CONNECTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent);
+ statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
+ mContext.sendBroadcast(statusIntent);
}
else if (mPlugType == 0 && mLastPlugType != 0) {
- Intent intent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent);
+ statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
+ mContext.sendBroadcast(statusIntent);
}
+
+ final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+ final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+ /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+ * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
+ * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
+ */
+ final boolean sendBatteryLow = !plugged
+ && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mBatteryLevel < BATTERY_LEVEL_WARNING
+ && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
@@ -269,8 +302,17 @@
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
-
+
sendIntent();
+ if (sendBatteryLow) {
+ mSentLowBatteryBroadcast = true;
+ statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
+ mContext.sendBroadcast(statusIntent);
+ } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING) {
+ mSentLowBatteryBroadcast = false;
+ statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
+ mContext.sendBroadcast(statusIntent);
+ }
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 493bd09..72a1192 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -30,51 +30,136 @@
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import com.android.internal.telephony.Phone;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String TAG = "ConnectivityService";
// Event log tags (must be in sync with event-log-tags)
private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020;
+ // how long to wait before switching back to a radio's default network
+ private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
+ // system property that can override the above value
+ private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
+ "android.telephony.apn-restore";
+
/**
* Sometimes we want to refer to the individual network state
* trackers separately, and sometimes we just want to treat them
* abstractly.
*/
private NetworkStateTracker mNetTrackers[];
- private WifiStateTracker mWifiStateTracker;
- private MobileDataStateTracker mMobileDataStateTracker;
+
+ /**
+ * A per Net list of the PID's that requested access to the net
+ * used both as a refcount and for per-PID DNS selection
+ */
+ private List mNetRequestersPids[];
+
private WifiWatchdogService mWifiWatchdogService;
+ // priority order of the nettrackers
+ // (excluding dynamically set mNetworkPreference)
+ // TODO - move mNetworkTypePreference into this
+ private int[] mPriorityList;
+
private Context mContext;
private int mNetworkPreference;
- private NetworkStateTracker mActiveNetwork;
+ private int mActiveDefaultNetwork = -1;
private int mNumDnsEntries;
- private static int sDnsChangeCounter;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
+ private Handler mHandler;
+
+ // list of DeathRecipients used to make sure features are turned off when
+ // a process dies
+ private List mFeatureUsers;
+
+ private boolean mSystemReady;
+ private ArrayList<Intent> mDeferredBroadcasts;
+
+ private class NetworkAttributes {
+ /**
+ * Class for holding settings read from resources.
+ */
+ public String mName;
+ public int mType;
+ public int mRadio;
+ public int mPriority;
+ public NetworkAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ if (fragments[1].toLowerCase().equals("wifi")) {
+ mRadio = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mRadio = ConnectivityManager.TYPE_MOBILE;
+ }
+ if (mName.equals("default")) {
+ mType = mRadio;
+ } else if (mName.equals("mms")) {
+ mType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (mName.equals("supl")) {
+ mType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (mName.equals("dun")) {
+ mType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (mName.equals("hipri")) {
+ mType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ mPriority = Integer.parseInt(fragments[2]);
+ }
+ public boolean isDefault() {
+ return (mType == mRadio);
+ }
+ }
+ NetworkAttributes[] mNetAttributes;
+
+ private class RadioAttributes {
+ public String mName;
+ public int mPriority;
+ public int mSimultaneity;
+ public int mType;
+ public RadioAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ mPriority = Integer.parseInt(fragments[1]);
+ mSimultaneity = Integer.parseInt(fragments[2]);
+ if (mName.equals("wifi")) {
+ mType = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mType = ConnectivityManager.TYPE_MOBILE;
+ }
+ }
+ }
+ RadioAttributes[] mRadioAttributes;
+
private static class ConnectivityThread extends Thread {
private Context mContext;
-
+
private ConnectivityThread(Context context) {
super("ConnectivityThread");
mContext = context;
@@ -89,11 +174,11 @@
}
Looper.loop();
}
-
+
public static ConnectivityService getServiceInstance(Context context) {
ConnectivityThread thread = new ConnectivityThread(context);
thread.start();
-
+
synchronized (thread) {
while (sServiceInstance == null) {
try {
@@ -101,27 +186,71 @@
thread.wait();
} catch (InterruptedException ignore) {
Log.e(TAG,
- "Unexpected InterruptedException while waiting for ConnectivityService thread");
+ "Unexpected InterruptedException while waiting"+
+ " for ConnectivityService thread");
}
}
}
-
+
return sServiceInstance;
}
}
-
+
public static ConnectivityService getInstance(Context context) {
return ConnectivityThread.getServiceInstance(context);
}
-
+
private ConnectivityService(Context context) {
if (DBG) Log.v(TAG, "ConnectivityService starting up");
mContext = context;
- mNetTrackers = new NetworkStateTracker[2];
- Handler handler = new MyHandler();
-
+ mNetTrackers = new NetworkStateTracker[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mHandler = new MyHandler();
+
mNetworkPreference = getPersistedNetworkPreference();
-
+
+ // Load device network attributes from resources
+ mNetAttributes = new NetworkAttributes[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mRadioAttributes = new RadioAttributes[
+ ConnectivityManager.MAX_RADIO_TYPE+1];
+ String[] naStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.networkAttributes);
+ // TODO - what if the setting has gaps/unknown types?
+ for (String a : naStrings) {
+ NetworkAttributes n = new NetworkAttributes(a);
+ mNetAttributes[n.mType] = n;
+ }
+ String[] raStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.radioAttributes);
+ for (String a : raStrings) {
+ RadioAttributes r = new RadioAttributes(a);
+ mRadioAttributes[r.mType] = r;
+ }
+
+ // high priority first
+ mPriorityList = new int[naStrings.length];
+ {
+ int priority = 0; //lowest
+ int nextPos = naStrings.length-1;
+ while (nextPos>-1) {
+ for (int i = 0; i < mNetAttributes.length; i++) {
+ if(mNetAttributes[i].mPriority == priority) {
+ mPriorityList[nextPos--] = i;
+ }
+ }
+ priority++;
+ }
+ }
+
+ mNetRequestersPids =
+ new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
+ for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) {
+ mNetRequestersPids[i] = new ArrayList();
+ }
+
+ mFeatureUsers = new ArrayList();
+
/*
* Create the network state trackers for Wi-Fi and mobile
* data. Maybe this could be done with a factory class,
@@ -130,15 +259,36 @@
* to change very often.
*/
if (DBG) Log.v(TAG, "Starting Wifi Service.");
- mWifiStateTracker = new WifiStateTracker(context, handler);
- WifiService wifiService = new WifiService(context, mWifiStateTracker);
+ WifiStateTracker wst = new WifiStateTracker(context, mHandler);
+ WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
+ mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
- mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
- mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker;
-
- mActiveNetwork = null;
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT,
+ "MOBILE");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS,
+ "MOBILE_MMS");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL,
+ "MOBILE_SUPL");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN,
+ "MOBILE_DUN");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI,
+ "MOBILE_HIPRI");
+
mNumDnsEntries = 0;
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
@@ -148,16 +298,17 @@
t.startMonitoring();
// Constructing this starts it too
- mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker);
+ mWifiWatchdogService = new WifiWatchdogService(context, wst);
}
/**
- * Sets the preferred network.
+ * Sets the preferred network.
* @param preference the new preference
*/
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
- if (ConnectivityManager.isNetworkTypeValid(preference)) {
+ if (ConnectivityManager.isNetworkTypeValid(preference) &&
+ mNetAttributes[preference].isDefault()) {
if (mNetworkPreference != preference) {
persistNetworkPreference(preference);
mNetworkPreference = preference;
@@ -173,9 +324,10 @@
private void persistNetworkPreference(int networkPreference) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
+ Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
+ networkPreference);
}
-
+
private int getPersistedNetworkPreference() {
final ContentResolver cr = mContext.getContentResolver();
@@ -187,31 +339,25 @@
return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
}
-
+
/**
- * Make the state of network connectivity conform to the preference settings.
+ * Make the state of network connectivity conform to the preference settings
* In this method, we only tear down a non-preferred network. Establishing
* a connection to the preferred network is taken care of when we handle
* the disconnect event from the non-preferred network
* (see {@link #handleDisconnect(NetworkInfo)}).
*/
private void enforcePreference() {
- if (mActiveNetwork == null)
+ if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
return;
- for (NetworkStateTracker t : mNetTrackers) {
- if (t == mActiveNetwork) {
- int netType = t.getNetworkInfo().getType();
- int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ?
- ConnectivityManager.TYPE_MOBILE :
- ConnectivityManager.TYPE_WIFI);
+ if (!mNetTrackers[mNetworkPreference].isAvailable())
+ return;
- if (t.getNetworkInfo().getType() != mNetworkPreference) {
- NetworkStateTracker otherTracker = mNetTrackers[otherNetType];
- if (otherTracker.isAvailable()) {
- teardown(t);
- }
- }
+ for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
+ if (t != mNetworkPreference &&
+ mNetTrackers[t].getNetworkInfo().isConnected()) {
+ teardown(mNetTrackers[t]);
}
}
}
@@ -229,13 +375,21 @@
* Return NetworkInfo for the active (i.e., connected) network interface.
* It is assumed that at most one network is active at a time. If more
* than one is active, it is indeterminate which will be returned.
- * @return the info for the active network, or {@code null} if none is active
+ * @return the info for the active network, or {@code null} if none is
+ * active
*/
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
- for (NetworkStateTracker t : mNetTrackers) {
+ for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
+ if (!mNetAttributes[type].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker t = mNetTrackers[type];
NetworkInfo info = t.getNetworkInfo();
if (info.isConnected()) {
+ if (DBG && type != mActiveDefaultNetwork) Log.e(TAG,
+ "connected default network is not " +
+ "mActiveDefaultNetwork!");
return info;
}
}
@@ -280,36 +434,198 @@
return tracker != null && tracker.setRadio(turnOn);
}
- public int startUsingNetworkFeature(int networkType, String feature) {
+ private class FeatureUser implements IBinder.DeathRecipient {
+ int mNetworkType;
+ String mFeature;
+ IBinder mBinder;
+ int mPid;
+ int mUid;
+
+ FeatureUser(int type, String feature, IBinder binder) {
+ super();
+ mNetworkType = type;
+ mFeature = feature;
+ mBinder = binder;
+ mPid = getCallingPid();
+ mUid = getCallingUid();
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public void binderDied() {
+ Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
+ mNetworkType + ", " + mFeature + ", " + mBinder);
+ stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid);
+ }
+
+ }
+
+ public int startUsingNetworkFeature(int networkType, String feature,
+ IBinder binder) {
+ if (DBG) {
+ Log.d(TAG, "startUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
- return -1;
+ return Phone.APN_REQUEST_FAILED;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ mFeatureUsers.add(new FeatureUser(networkType, feature, binder));
}
- return -1;
+
+ // TODO - move this into the MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if(networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ }
+ NetworkStateTracker network = mNetTrackers[usedNetworkType];
+ if (network != null) {
+ if (usedNetworkType != networkType) {
+ Integer currentPid = new Integer(getCallingPid());
+
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ NetworkInfo ni = network.getNetworkInfo();
+
+ if (ni.isAvailable() == false) {
+ if (DBG) Log.d(TAG, "special network not available");
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
+ // this gets used for per-pid dns when connected
+ mNetRequestersPids[usedNetworkType].add(currentPid);
+ }
+
+ if (ni.isConnectedOrConnecting() == true) {
+ if (ni.isConnected() == true) {
+ // add the pid-specific dns
+ handleDnsConfigurationChange();
+ if (DBG) Log.d(TAG, "special network already active");
+ return Phone.APN_ALREADY_ACTIVE;
+ }
+ if (DBG) Log.d(TAG, "special network already connecting");
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ // check if the radio in play can make another contact
+ // assume if cannot for now
+
+ // since we have to drop the default on this radio, setup
+ // an automatic event to switch back
+ if(mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio) ||
+ radio.getNetworkInfo().isConnectedOrConnecting()) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK,
+ radio);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
+ radio), getRestoreDefaultNetworkDelay());
+ }
+ if (DBG) Log.d(TAG, "reconnecting to special network");
+ network.reconnect();
+ return Phone.APN_REQUEST_STARTED;
+ } else {
+ return network.startUsingNetworkFeature(feature,
+ getCallingPid(), getCallingUid());
+ }
+ }
+ return Phone.APN_TYPE_NOT_AVAILABLE;
}
public int stopUsingNetworkFeature(int networkType, String feature) {
+ return stopUsingNetworkFeature(networkType, feature, getCallingPid(),
+ getCallingUid());
+ }
+
+ private int stopUsingNetworkFeature(int networkType, String feature,
+ int pid, int uid) {
+ if (DBG) {
+ Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return -1;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ for (int i=0; i < mFeatureUsers.size(); i++) {
+ FeatureUser u = (FeatureUser)mFeatureUsers.get(i);
+ if (uid == u.mUid && pid == u.mPid &&
+ networkType == u.mNetworkType &&
+ TextUtils.equals(feature, u.mFeature)) {
+ u.unlinkDeathRecipient();
+ mFeatureUsers.remove(i);
+ break;
+ }
+ }
}
- return -1;
+
+ // TODO - move to MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if (networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ }
+ NetworkStateTracker tracker = mNetTrackers[usedNetworkType];
+ if(usedNetworkType != networkType) {
+ Integer currentPid = new Integer(pid);
+ if (mNetRequestersPids[usedNetworkType].remove(currentPid)) {
+ reassessPidDns(pid, true);
+ }
+ if (mNetRequestersPids[usedNetworkType].size() != 0) {
+ if (DBG) Log.d(TAG, "not tearing down special network - " +
+ "others still using it");
+ return 1;
+ }
+
+ tracker.teardown();
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ // Check if we want to revert to the default
+ if (mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio)) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio);
+ radio.reconnect();
+ }
+ return 1;
+ } else {
+ return tracker.stopUsingNetworkFeature(feature, pid, uid);
+ }
}
/**
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface.
- * @param networkType the type of the network over which traffic to the specified
- * host is to be routed
- * @param hostAddress the IP address of the host to which the route is desired
+ * @param networkType the type of the network over which traffic to the
+ * specified host is to be routed
+ * @param hostAddress the IP address of the host to which the route is
+ * desired
* @return {@code true} on success, {@code false} on failure
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -329,7 +645,8 @@
if (getNumConnectedNetworks() > 1) {
return tracker.requestRouteToHost(hostAddress);
} else {
- return tracker.getNetworkInfo().getType() == networkType;
+ return (mNetAttributes[networkType].isDefault() &&
+ tracker.getNetworkInfo().isConnected());
}
}
@@ -340,7 +657,7 @@
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.BACKGROUND_DATA, 1) == 1;
}
-
+
/**
* @see ConnectivityManager#setBackgroundDataSetting(boolean)
*/
@@ -348,22 +665,24 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
"ConnectivityService");
-
+
if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0);
-
+ Settings.Secure.BACKGROUND_DATA,
+ allowBackgroundDataUsage ? 1 : 0);
+
Intent broadcast = new Intent(
ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
mContext.sendBroadcast(broadcast);
- }
-
+ }
+
private int getNumConnectedNetworks() {
int numConnectedNets = 0;
for (NetworkStateTracker nt : mNetTrackers) {
- if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
+ if (nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
++numConnectedNets;
}
}
@@ -371,64 +690,47 @@
}
private void enforceAccessPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
- "ConnectivityService");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE,
+ "ConnectivityService");
}
private void enforceChangePermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
- "ConnectivityService");
-
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "ConnectivityService");
}
/**
- * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network,
- * we ignore it. If it is for the active network, we send out a broadcast.
- * But first, we check whether it might be possible to connect to a different
- * network.
+ * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
+ * network, we ignore it. If it is for the active network, we send out a
+ * broadcast. But first, we check whether it might be possible to connect
+ * to a different network.
* @param info the {@code NetworkInfo} for the network
*/
private void handleDisconnect(NetworkInfo info) {
if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+ int prevNetType = info.getType();
- mNetTrackers[info.getType()].setTeardownRequested(false);
+ mNetTrackers[prevNetType].setTeardownRequested(false);
/*
* If the disconnected network is not the active one, then don't report
* this as a loss of connectivity. What probably happened is that we're
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
- if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
- return;
-
- NetworkStateTracker newNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- newNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- newNet = mMobileDataStateTracker;
- }
-
- /**
- * See if the other network is available to fail over to.
- * If is not available, we enable it anyway, so that it
- * will be able to connect when it does become available,
- * but we report a total loss of connectivity rather than
- * report that we are attempting to fail over.
- */
- NetworkInfo switchTo = null;
- if (newNet.isAvailable()) {
- mActiveNetwork = newNet;
- switchTo = newNet.getNetworkInfo();
- switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting()) {
- newNet.reconnect();
+ if (!mNetAttributes[prevNetType].isDefault()) {
+ List pids = mNetRequestersPids[prevNetType];
+ for (int i = 0; i<pids.size(); i++) {
+ Integer pid = (Integer)pids.get(i);
+ // will remove them because the net's no longer connected
+ // need to do this now as only now do we know the pids and
+ // can properly null things that are no longer referenced.
+ reassessPidDns(pid.intValue(), false);
}
- } else {
- newNet.reconnect();
}
- boolean otherNetworkConnected = false;
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (info.isFailover()) {
@@ -439,31 +741,95 @@
intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
+ info.getExtraInfo());
}
- if (switchTo != null) {
- otherNetworkConnected = switchTo.isConnected();
- if (DBG) {
- if (otherNetworkConnected) {
- Log.v(TAG, "Switching to already connected " + switchTo.getTypeName());
- } else {
- Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName());
+
+ /*
+ * If this is a default network, check if other defaults are available
+ * or active
+ */
+ NetworkStateTracker newNet = null;
+ if (mNetAttributes[prevNetType].isDefault()) {
+ if (DBG) Log.d(TAG, "disconnecting a default network");
+ if (mActiveDefaultNetwork == prevNetType) {
+ mActiveDefaultNetwork = -1;
+ }
+
+ int newType = -1;
+ int newPriority = -1;
+ for (int checkType=0; checkType <=
+ ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
+ if (checkType == prevNetType) {
+ continue;
+ }
+ if (mNetAttributes[checkType].isDefault()) {
+ /* TODO - if we have multiple nets we could use
+ * we may want to put more thought into which we choose
+ */
+ if (checkType == mNetworkPreference) {
+ newType = checkType;
+ break;
+ }
+ if (mRadioAttributes[mNetAttributes[checkType].mRadio].
+ mPriority > newPriority) {
+ newType = checkType;
+ newPriority = mRadioAttributes[mNetAttributes[newType].
+ mRadio].mPriority;
+ }
}
}
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
- } else {
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
- if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() +
- (switchTo == null ? "" : " other=" + switchTo.getTypeName()));
- mContext.sendStickyBroadcast(intent);
+ if (newType != -1) {
+ newNet = mNetTrackers[newType];
+ /**
+ * See if the other network is available to fail over to.
+ * If is not available, we enable it anyway, so that it
+ * will be able to connect when it does become available,
+ * but we report a total loss of connectivity rather than
+ * report that we are attempting to fail over.
+ */
+ if (newNet.isAvailable()) {
+ NetworkInfo switchTo = newNet.getNetworkInfo();
+ switchTo.setFailover(true);
+ if (!switchTo.isConnectedOrConnecting()) {
+ newNet.reconnect();
+ }
+ if (DBG) {
+ if (switchTo.isConnected()) {
+ Log.v(TAG, "Switching to already connected " +
+ switchTo.getTypeName());
+ } else {
+ Log.v(TAG, "Attempting to switch to " +
+ switchTo.getTypeName());
+ }
+ }
+ intent.putExtra(ConnectivityManager.
+ EXTRA_OTHER_NETWORK_INFO, switchTo);
+ } else {
+ newNet.reconnect();
+ }
+ } else {
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
+ true);
+ }
+ }
+
+ // do this before we broadcast the change
+ handleConnectivityChange();
+
+ if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " +
+ info.getTypeName() +
+ (newNet == null || !newNet.isAvailable() ? "" : " other=" +
+ newNet.getNetworkInfo().getTypeName()));
+
+ sendStickyBroadcast(intent);
/*
- * If the failover network is already connected, then immediately send out
- * a followup broadcast indicating successful failover
+ * If the failover network is already connected, then immediately send
+ * out a followup broadcast indicating successful failover
*/
- if (switchTo != null && otherNetworkConnected)
- sendConnectedBroadcast(switchTo);
+ if (newNet != null && newNet.getNetworkInfo().isConnected())
+ sendConnectedBroadcast(newNet.getNetworkInfo());
}
private void sendConnectedBroadcast(NetworkInfo info) {
@@ -477,9 +843,10 @@
intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
+ info.getExtraInfo());
}
- mContext.sendStickyBroadcast(intent);
+ sendStickyBroadcast(intent);
}
/**
@@ -488,106 +855,128 @@
*/
private void handleConnectionFailure(NetworkInfo info) {
mNetTrackers[info.getType()].setTeardownRequested(false);
- if (getActiveNetworkInfo() == null) {
- String reason = info.getReason();
- String extraInfo = info.getExtraInfo();
- if (DBG) {
- String reasonText;
- if (reason == null) {
- reasonText = ".";
- } else {
- reasonText = " (" + reason + ").";
- }
- Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
+ String reason = info.getReason();
+ String extraInfo = info.getExtraInfo();
+
+ if (DBG) {
+ String reasonText;
+ if (reason == null) {
+ reasonText = ".";
+ } else {
+ reasonText = " (" + reason + ").";
}
-
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
+ " failed" + reasonText);
+ }
+
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ if (getActiveNetworkInfo() == null) {
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- if (reason != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
+ }
+ if (reason != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
+ }
+ if (extraInfo != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
+ }
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ info.setFailover(false);
+ }
+ 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);
}
- if (extraInfo != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
+ }
+ }
+
+ 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;
}
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- info.setFailover(false);
- }
- mContext.sendStickyBroadcast(intent);
}
}
private void handleConnect(NetworkInfo info) {
- if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName());
+ if (DBG) Log.d(TAG, "Handle CONNECT for " + info.getTypeName());
+
+ int type = info.getType();
// snapshot isFailover, because sendConnectedBroadcast() resets it
boolean isFailover = info.isFailover();
- NetworkStateTracker thisNet = mNetTrackers[info.getType()];
- NetworkStateTracker deadnet = null;
- NetworkStateTracker otherNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- otherNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- otherNet = mMobileDataStateTracker;
- }
- /*
- * Check policy to see whether we are connected to a non-preferred
- * network that now needs to be torn down.
- */
- NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
- NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
- if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
- if (mNetworkPreference == ConnectivityManager.TYPE_WIFI)
- deadnet = mMobileDataStateTracker;
- else
- deadnet = mWifiStateTracker;
- }
+ NetworkStateTracker thisNet = mNetTrackers[type];
- boolean toredown = false;
+ // if this is a default net and other default is running
+ // kill the one not preferred
+ if (mNetAttributes[type].isDefault()) {
+ if (DBG) Log.d(TAG, "connecting to a default network");
+ if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
+ if ((type != mNetworkPreference &&
+ mNetAttributes[mActiveDefaultNetwork].mPriority >
+ mNetAttributes[type].mPriority) ||
+ mNetworkPreference == mActiveDefaultNetwork) {
+ // don't accept this one
+ if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +
+ "to torn down network " + info.getTypeName());
+ teardown(thisNet);
+ return;
+ } else {
+ // tear down the other
+ NetworkStateTracker otherNet =
+ mNetTrackers[mActiveDefaultNetwork];
+ if (DBG) Log.v(TAG, "Policy requires " +
+ otherNet.getNetworkInfo().getTypeName() +
+ " teardown");
+ if (!teardown(otherNet)) {
+ Log.e(TAG, "Network declined teardown request");
+ return;
+ }
+ if (isFailover) {
+ otherNet.releaseWakeLock();
+ }
+ }
+ }
+ mActiveDefaultNetwork = type;
+ }
thisNet.setTeardownRequested(false);
- if (!mTestMode && deadnet != null) {
- if (DBG) Log.v(TAG, "Policy requires " +
- deadnet.getNetworkInfo().getTypeName() + " teardown");
- toredown = teardown(deadnet);
- if (DBG && !toredown) {
- Log.d(TAG, "Network declined teardown request");
- }
- }
-
- /*
- * Note that if toredown is true, deadnet cannot be null, so there is
- * no danger of a null pointer exception here..
- */
- if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
- mActiveNetwork = thisNet;
- if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName());
- thisNet.updateNetworkSettings();
- sendConnectedBroadcast(info);
- if (isFailover) {
- otherNet.releaseWakeLock();
- }
- } else {
- if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " +
- info.getTypeName());
- }
+ if (DBG) Log.d(TAG, "Sending CONNECT bcast for " + info.getTypeName());
+ thisNet.updateNetworkSettings();
+ handleConnectivityChange();
+ sendConnectedBroadcast(info);
}
private void handleScanResultsAvailable(NetworkInfo info) {
int networkType = info.getType();
if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network."
- + " Don't know how to handle.");
+ if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " +
+ info.getTypeName() + " network. Don't know how to handle.");
}
-
+
mNetTrackers[networkType].interpretScanResultsAvailable();
}
- private void handleNotificationChange(boolean visible, int id, Notification notification) {
+ private void handleNotificationChange(boolean visible, int id,
+ Notification notification) {
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
-
+
if (visible) {
notificationManager.notify(id, notification);
} else {
@@ -604,80 +993,173 @@
* table entries exist.
*/
private void handleConnectivityChange() {
+ if (DBG) Log.d(TAG, "handleConnectivityChange");
/*
+ * If a non-default network is enabled, add the host routes that
+ * will allow it's DNS servers to be accessed. Only
* If both mobile and wifi are enabled, add the host routes that
* will allow MMS traffic to pass on the mobile network. But
* remove the default route for the mobile network, so that there
* will be only one default route, to ensure that all traffic
* except MMS will travel via Wi-Fi.
*/
- int numConnectedNets = handleConfigurationChange();
- if (numConnectedNets > 1) {
- mMobileDataStateTracker.addPrivateRoutes();
- mMobileDataStateTracker.removeDefaultRoute();
- } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) {
- mMobileDataStateTracker.removePrivateRoutes();
- mMobileDataStateTracker.restoreDefaultRoute();
+ handleDnsConfigurationChange();
+
+ for (int netType : mPriorityList) {
+ if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].addDefaultRoute();
+ } else {
+ mNetTrackers[netType].addPrivateDnsRoutes();
+ }
+ } else {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].removeDefaultRoute();
+ } else {
+ mNetTrackers[netType].removePrivateDnsRoutes();
+ }
+ }
}
}
- private int handleConfigurationChange() {
- /*
- * Set DNS properties. Always put Wi-Fi entries at the front of
- * the list if it is active.
- */
- int index = 1;
- String lastDns = "";
- int numConnectedNets = 0;
- int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
- int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
+ /**
+ * Adjust the per-process dns entries (net.dns<x>.<pid>) based
+ * on the highest priority active net which this process requested.
+ * If there aren't any, clear it out
+ */
+ private void reassessPidDns(int myPid, boolean doBump)
+ {
+ if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid);
+ for(int i : mPriorityList) {
+ if (mNetAttributes[i].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker nt = mNetTrackers[i];
+ if (nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
+ List pids = mNetRequestersPids[i];
+ for (int j=0; j<pids.size(); j++) {
+ Integer pid = (Integer)pids.get(j);
+ if (pid.intValue() == myPid) {
+ String[] dnsList = nt.getNameServers();
+ writePidDns(dnsList, myPid);
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ }
+ }
+ }
+ // nothing found - delete
+ for (int i = 1; ; i++) {
+ String prop = "net.dns" + i + "." + myPid;
+ if (SystemProperties.get(prop).length() == 0) {
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ SystemProperties.set(prop, "");
+ }
+ }
- for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
+ private void writePidDns(String[] dnsList, int pid) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + j++ + "." + pid, dns);
+ }
+ }
+ }
+
+ private void bumpDns() {
+ /*
+ * Bump the property that tells the name resolver library to reread
+ * the DNS server list from the properties.
+ */
+ String propVal = SystemProperties.get("net.dnschange");
+ int n = 0;
+ if (propVal.length() != 0) {
+ try {
+ n = Integer.parseInt(propVal);
+ } catch (NumberFormatException e) {}
+ }
+ SystemProperties.set("net.dnschange", "" + (n+1));
+ }
+
+ private void handleDnsConfigurationChange() {
+ if (DBG) Log.d(TAG, "handleDnsConfig Change");
+ // add default net's dns entries
+ for (int x = mPriorityList.length-1; x>= 0; x--) {
+ int netType = mPriorityList[x];
NetworkStateTracker nt = mNetTrackers[netType];
- if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
- ++numConnectedNets;
+ if (DBG) Log.d(TAG, " checking " + nt);
+ if (nt != null && nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
+ if (DBG) Log.d(TAG, " connected");
String[] dnsList = nt.getNameServers();
- for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
- // skip duplicate entries
- if (!dnsList[i].equals(lastDns)) {
- SystemProperties.set("net.dns" + index++, dnsList[i]);
- lastDns = dnsList[i];
+ if (mNetAttributes[netType].isDefault()) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + j++, dns);
+ }
+ }
+ for (int k=j ; k<mNumDnsEntries; k++) {
+ SystemProperties.set("net.dns" + j, "");
+ }
+ mNumDnsEntries = j;
+ } else {
+ // set per-pid dns for attached secondary nets
+ List pids = mNetRequestersPids[netType];
+ for (int y=0; y< pids.size(); y++) {
+ Integer pid = (Integer)pids.get(y);
+ writePidDns(dnsList, pid.intValue());
}
}
}
}
- // Null out any DNS properties that are no longer used
- for (int i = index; i <= mNumDnsEntries; i++) {
- SystemProperties.set("net.dns" + i, "");
+
+ bumpDns();
+ }
+
+ private int getRestoreDefaultNetworkDelay() {
+ String restoreDefaultNetworkDelayStr = SystemProperties.get(
+ NETWORK_RESTORE_DELAY_PROP_NAME);
+ if(restoreDefaultNetworkDelayStr != null &&
+ restoreDefaultNetworkDelayStr.length() != 0) {
+ try {
+ return Integer.valueOf(restoreDefaultNetworkDelayStr);
+ } catch (NumberFormatException e) {
+ }
}
- mNumDnsEntries = index - 1;
- // Notify the name resolver library of the change
- SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
- return numConnectedNets;
+ return RESTORE_DEFAULT_NETWORK_DELAY;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump ConnectivityService from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
+ pw.println("Permission Denial: can't dump ConnectivityService " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
return;
}
- if (mActiveNetwork == null) {
- pw.println("No active network");
- } else {
- pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName());
- }
pw.println();
for (NetworkStateTracker nst : mNetTrackers) {
+ if (nst.getNetworkInfo().isConnected()) {
+ pw.println("Active network: " + nst.getNetworkInfo().
+ getTypeName());
+ }
pw.println(nst.getNetworkInfo());
pw.println(nst);
pw.println();
}
}
+ // must be stateless - things change under us.
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
@@ -685,46 +1167,54 @@
switch (msg.what) {
case NetworkStateTracker.EVENT_STATE_CHANGED:
info = (NetworkInfo) msg.obj;
- if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " +
+ if (DBG) Log.d(TAG, "ConnectivityChange for " +
+ info.getTypeName() + ": " +
info.getState() + "/" + info.getDetailedState());
// Connectivity state changed:
// [31-13] Reserved for future use
- // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
- // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [12-9] Network subtype (for mobile network, as defined
+ // by TelephonyManager)
+ // [8-3] Detailed state ordinal (as defined by
+ // NetworkInfo.DetailedState)
// [2-0] Network type (as defined by ConnectivityManager)
int eventLogParam = (info.getType() & 0x7) |
((info.getDetailedState().ordinal() & 0x3f) << 3) |
(info.getSubtype() << 9);
- EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
-
- if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+ EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED,
+ eventLogParam);
+
+ if (info.getDetailedState() ==
+ NetworkInfo.DetailedState.FAILED) {
handleConnectionFailure(info);
- } else if (info.getState() == NetworkInfo.State.DISCONNECTED) {
+ } else if (info.getState() ==
+ NetworkInfo.State.DISCONNECTED) {
handleDisconnect(info);
} else if (info.getState() == NetworkInfo.State.SUSPENDED) {
// TODO: need to think this over.
- // the logic here is, handle SUSPENDED the same as DISCONNECTED. The
- // only difference being we are broadcasting an intent with NetworkInfo
- // that's suspended. This allows the applications an opportunity to
- // handle DISCONNECTED and SUSPENDED differently, or not.
+ // the logic here is, handle SUSPENDED the same as
+ // DISCONNECTED. The only difference being we are
+ // broadcasting an intent with NetworkInfo that's
+ // suspended. This allows the applications an
+ // opportunity to handle DISCONNECTED and SUSPENDED
+ // differently, or not.
handleDisconnect(info);
} else if (info.getState() == NetworkInfo.State.CONNECTED) {
handleConnect(info);
}
- handleConnectivityChange();
break;
case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
info = (NetworkInfo) msg.obj;
handleScanResultsAvailable(info);
break;
-
+
case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
- handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj);
+ handleNotificationChange(msg.arg1 == 1, msg.arg2,
+ (Notification) msg.obj);
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
- handleConfigurationChange();
+ handleDnsConfigurationChange();
break;
case NetworkStateTracker.EVENT_ROAMING_CHANGED:
@@ -734,6 +1224,15 @@
case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
// fill me in
break;
+ case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
+ for (NetworkStateTracker net : mNetTrackers) {
+ NetworkInfo i = net.getNetworkInfo();
+ if (i.isConnected() &&
+ !mNetAttributes[i.getType()].isDefault()) {
+ teardown(net);
+ }
+ }
+ break;
}
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
new file mode 100644
index 0000000..68ff416
--- /dev/null
+++ b/services/java/com/android/server/DockObserver.java
@@ -0,0 +1,115 @@
+/*
+ * 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.app.ActivityManagerNative;
+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() {
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+
+ // TODO: Should we require a permission?
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Broadcasting dock state " + mDockState);
+ }
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ }
+
+ 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 5bc9b5f..7597f85 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -37,6 +37,9 @@
import android.os.SystemClock;
import android.util.Log;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
public class HardwareService extends IHardwareService.Stub {
private static final String TAG = "HardwareService";
@@ -50,9 +53,62 @@
static final int LIGHT_FLASH_NONE = 0;
static final int LIGHT_FLASH_TIMED = 1;
+ private final LinkedList<Vibration> mVibrations;
+ private Vibration mCurrentVibration;
+
private boolean mAttentionLightOn;
private boolean mPulsing;
+ private class Vibration implements IBinder.DeathRecipient {
+ private final IBinder mToken;
+ private final long mTimeout;
+ private final long mStartTime;
+ private final long[] mPattern;
+ private final int mRepeat;
+
+ Vibration(IBinder token, long millis) {
+ this(token, millis, null, 0);
+ }
+
+ Vibration(IBinder token, long[] pattern, int repeat) {
+ this(token, 0, pattern, repeat);
+ }
+
+ private Vibration(IBinder token, long millis, long[] pattern,
+ int repeat) {
+ mToken = token;
+ mTimeout = millis;
+ mStartTime = SystemClock.uptimeMillis();
+ mPattern = pattern;
+ mRepeat = repeat;
+ }
+
+ public void binderDied() {
+ synchronized (mVibrations) {
+ mVibrations.remove(this);
+ if (this == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
+ }
+
+ public boolean hasLongerTimeout(long millis) {
+ if (mTimeout == 0) {
+ // This is a pattern, return false to play the simple
+ // vibration.
+ return false;
+ }
+ if ((mStartTime + mTimeout)
+ < (SystemClock.uptimeMillis() + millis)) {
+ // If this vibration will end before the time passed in, let
+ // the new vibration play.
+ return false;
+ }
+ return true;
+ }
+ }
+
HardwareService(Context context) {
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
@@ -66,6 +122,8 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
+ mVibrations = new LinkedList<Vibration>();
+
mBatteryStats = BatteryStatsService.getService();
IntentFilter filter = new IntentFilter();
@@ -78,13 +136,24 @@
super.finalize();
}
- public void vibrate(long milliseconds) {
+ public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
- doCancelVibrate();
- vibratorOn(milliseconds);
+ if (mCurrentVibration != null
+ && mCurrentVibration.hasLongerTimeout(milliseconds)) {
+ // Ignore this vibration since the current vibration will play for
+ // longer than milliseconds.
+ return;
+ }
+ Vibration vib = new Vibration(token, milliseconds);
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
+ }
}
private boolean isAll0(long[] pattern) {
@@ -121,34 +190,25 @@
return;
}
- synchronized (this) {
- Death death = new Death(token);
- try {
- token.linkToDeath(death, 0);
- } catch (RemoteException e) {
- return;
+ Vibration vib = new Vibration(token, pattern, repeat);
+ try {
+ token.linkToDeath(vib, 0);
+ } catch (RemoteException e) {
+ return;
+ }
+
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ if (repeat >= 0) {
+ mVibrations.addFirst(vib);
+ startNextVibrationLocked();
+ } else {
+ // A negative repeat means that this pattern is not meant
+ // to repeat. Treat it like a simple vibration.
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
}
-
- Thread oldThread = mThread;
-
- if (oldThread != null) {
- // stop the old one
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- }
-
- if (mDeath != null) {
- mToken.unlinkToDeath(mDeath, 0);
- }
-
- mDeath = death;
- mToken = token;
-
- // start the new thread
- mThread = new VibrateThread(pattern, repeat);
- mThread.start();
}
}
finally {
@@ -156,7 +216,7 @@
}
}
- public void cancelVibrate() {
+ public void cancelVibrate(IBinder token) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.VIBRATE,
"cancelVibrate");
@@ -164,7 +224,13 @@
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ final Vibration vib = removeVibrationLocked(token);
+ if (vib == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
}
finally {
Binder.restoreCallingIdentity(identity);
@@ -277,27 +343,74 @@
}
};
- private void doCancelVibrate() {
- synchronized (this) {
- if (mThread != null) {
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- mThread = null;
+ private final Runnable mVibrationRunnable = new Runnable() {
+ public void run() {
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
}
- vibratorOff();
+ }
+ };
+
+ // Lock held on mVibrations
+ private void doCancelVibrateLocked() {
+ if (mThread != null) {
+ synchronized (mThread) {
+ mThread.mDone = true;
+ mThread.notify();
+ }
+ mThread = null;
+ }
+ vibratorOff();
+ mH.removeCallbacks(mVibrationRunnable);
+ }
+
+ // Lock held on mVibrations
+ private void startNextVibrationLocked() {
+ if (mVibrations.size() <= 0) {
+ return;
+ }
+ mCurrentVibration = mVibrations.getFirst();
+ startVibrationLocked(mCurrentVibration);
+ }
+
+ // Lock held on mVibrations
+ private void startVibrationLocked(final Vibration vib) {
+ if (vib.mTimeout != 0) {
+ vibratorOn(vib.mTimeout);
+ mH.postDelayed(mVibrationRunnable, vib.mTimeout);
+ } else {
+ // mThread better be null here. doCancelVibrate should always be
+ // called before startNextVibrationLocked or startVibrationLocked.
+ mThread = new VibrateThread(vib);
+ mThread.start();
}
}
+ // Lock held on mVibrations
+ private Vibration removeVibrationLocked(IBinder token) {
+ ListIterator<Vibration> iter = mVibrations.listIterator(0);
+ while (iter.hasNext()) {
+ Vibration vib = iter.next();
+ if (vib.mToken == token) {
+ iter.remove();
+ return vib;
+ }
+ }
+ // We might be looking for a simple vibration which is only stored in
+ // mCurrentVibration.
+ if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
+ return mCurrentVibration;
+ }
+ return null;
+ }
+
private class VibrateThread extends Thread {
- long[] mPattern;
- int mRepeat;
+ final Vibration mVibration;
boolean mDone;
- VibrateThread(long[] pattern, int repeat) {
- mPattern = pattern;
- mRepeat = repeat;
+ VibrateThread(Vibration vib) {
+ mVibration = vib;
mWakeLock.acquire();
}
@@ -323,8 +436,9 @@
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
synchronized (this) {
int index = 0;
- long[] pattern = mPattern;
+ long[] pattern = mVibration.mPattern;
int len = pattern.length;
+ int repeat = mVibration.mRepeat;
long duration = 0;
while (!mDone) {
@@ -347,50 +461,37 @@
HardwareService.this.vibratorOn(duration);
}
} else {
- if (mRepeat < 0) {
+ if (repeat < 0) {
break;
} else {
- index = mRepeat;
+ index = repeat;
duration = 0;
}
}
}
- if (mDone) {
- // make sure vibrator is off if we were cancelled.
- // otherwise, it will turn off automatically
- // when the last timeout expires.
- HardwareService.this.vibratorOff();
- }
mWakeLock.release();
}
- synchronized (HardwareService.this) {
+ synchronized (mVibrations) {
if (mThread == this) {
mThread = null;
}
+ if (!mDone) {
+ // If this vibration finished naturally, start the next
+ // vibration.
+ mVibrations.remove(mVibration);
+ startNextVibrationLocked();
+ }
}
}
};
- private class Death implements IBinder.DeathRecipient {
- IBinder mMe;
-
- Death(IBinder me) {
- mMe = me;
- }
-
- public void binderDied() {
- synchronized (HardwareService.this) {
- if (mMe == mToken) {
- doCancelVibrate();
- }
- }
- }
- }
-
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ mVibrations.clear();
+ }
}
}
};
@@ -407,8 +508,6 @@
private final IBatteryStats mBatteryStats;
volatile VibrateThread mThread;
- volatile Death mDeath;
- volatile IBinder mToken;
private int mNativePointer;
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9b0a2d4..bee3108 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -41,10 +41,16 @@
private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_TTY = (1 << 2);
+ private static final int BIT_FM_HEADSET = (1 << 3);
+ private static final int BIT_FM_SPEAKER = (1 << 4);
+
private int mHeadsetState;
+ private int mPrevHeadsetState;
private String mHeadsetName;
- private boolean mAudioRouteNeedsUpdate;
- private AudioManager mAudioManager;
+ private boolean mPendingIntent;
private final Context mContext;
private final WakeLock mWakeLock; // held while there is a pending route change
@@ -76,6 +82,7 @@
String newName = mHeadsetName;
int newState = mHeadsetState;
+ mPrevHeadsetState = mHeadsetState;
try {
FileReader file = new FileReader(HEADSET_STATE_PATH);
int len = file.read(buffer, 0, 1024);
@@ -91,20 +98,25 @@
Log.e(TAG, "" , e);
}
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
update(newName, newState);
}
private synchronized final void update(String newName, int newState) {
if (newName != mHeadsetName || newState != mHeadsetState) {
- boolean isUnplug = (newState == 0 && mHeadsetState == 1);
+ boolean isUnplug = false;
+ if ( (mHeadsetState & BIT_HEADSET) > 0 || (mHeadsetState & BIT_HEADSET_NO_MIC) > 0) {
+ if ((newState & BIT_HEADSET) == 0 && (newState & BIT_HEADSET_NO_MIC) == 0)
+ isUnplug = true;
+ }
mHeadsetName = newName;
+ mPrevHeadsetState = mHeadsetState;
mHeadsetState = newState;
- mAudioRouteNeedsUpdate = true;
-
- sendIntent(isUnplug);
+ mPendingIntent = true;
if (isUnplug) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
@@ -113,12 +125,13 @@
mWakeLock.acquire();
mHandler.sendEmptyMessageDelayed(0, 1000);
} else {
- updateAudioRoute();
+ sendIntent();
+ mPendingIntent = false;
}
}
}
- private synchronized final void sendIntent(boolean isUnplug) {
+ private synchronized final void sendIntent() {
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -128,24 +141,15 @@
// TODO: Should we require a permission?
ActivityManagerNative.broadcastStickyIntent(intent, null);
-
- if (isUnplug) {
- intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- }
- }
-
- private synchronized final void updateAudioRoute() {
- if (mAudioRouteNeedsUpdate) {
- mAudioManager.setWiredHeadsetOn(mHeadsetState == 1);
- mAudioRouteNeedsUpdate = false;
- }
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- updateAudioRoute();
+ if (mPendingIntent) {
+ sendIntent();
+ mPendingIntent = false;
+ }
mWakeLock.release();
}
};
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 7b8a2a4..e1bce73 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -23,9 +23,14 @@
import android.view.WindowManagerPolicy;
public class InputDevice {
+ static final boolean DEBUG_POINTERS = false;
+
/** Amount that trackball needs to move in order to generate a key event. */
static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
+ /** Maximum number of pointers we will track and report. */
+ static final int MAX_POINTERS = 10;
+
final int id;
final int classes;
final String name;
@@ -34,9 +39,13 @@
final AbsoluteInfo absPressure;
final AbsoluteInfo absSize;
- long mDownTime = 0;
+ long mKeyDownTime = 0;
int mMetaKeysState = 0;
+ // For use by KeyInputQueue for keeping track of the current touch
+ // data in the old non-multi-touch protocol.
+ final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
+
final MotionState mAbs = new MotionState(0, 0);
final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
TRACKBALL_MOVEMENT_THRESHOLD);
@@ -48,146 +57,503 @@
float yMoveScale;
MotionEvent currentMove = null;
boolean changed = false;
- boolean down = false;
- boolean lastDown = false;
- long downTime = 0;
- int x = 0;
- int y = 0;
- int pressure = 1;
- int size = 0;
+ long mDownTime = 0;
+
+ // The currently assigned pointer IDs, corresponding to the last data.
+ int[] mPointerIds = new int[MAX_POINTERS];
+
+ // This is the last generated pointer data, ordered to match
+ // mPointerIds.
+ int mLastNumPointers = 0;
+ final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
+
+ // This is the next set of pointer data being generated. It is not
+ // in any known order, and will be propagated in to mLastData
+ // as part of mapping it to the appropriate pointer IDs.
+ // Note that we have one extra sample of data here, to help clients
+ // avoid doing bounds checking.
+ int mNextNumPointers = 0;
+ final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
+ + MotionEvent.NUM_SAMPLE_DATA];
+
+ // Temporary data structures for doing the pointer ID mapping.
+ final int[] mLast2Next = new int[MAX_POINTERS];
+ final int[] mNext2Last = new int[MAX_POINTERS];
+ final long[] mNext2LastDistance = new long[MAX_POINTERS];
+
+ // Temporary data structure for generating the final motion data.
+ final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
+
+ // This is not used here, but can be used by callers for state tracking.
+ int mAddingPointerOffset = 0;
+ final boolean[] mDown = new boolean[MAX_POINTERS];
MotionState(int mx, int my) {
xPrecision = mx;
yPrecision = my;
xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
+ for (int i=0; i<MAX_POINTERS; i++) {
+ mPointerIds[i] = i;
+ }
}
- MotionEvent generateMotion(InputDevice device, long curTime,
- boolean isAbs, Display display, int orientation,
+ private boolean assignPointer(int nextIndex, boolean allowOverlap) {
+ final int lastNumPointers = mLastNumPointers;
+ final int[] next2Last = mNext2Last;
+ final long[] next2LastDistance = mNext2LastDistance;
+ final int[] last2Next = mLast2Next;
+ final int[] lastData = mLastData;
+ final int[] nextData = mNextData;
+ final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
+ + nextIndex + " dataOff=" + id);
+ final int x1 = nextData[id + MotionEvent.SAMPLE_X];
+ final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
+
+ long bestDistance = -1;
+ int bestIndex = -1;
+ for (int j=0; j<lastNumPointers; j++) {
+ if (!allowOverlap && last2Next[j] < 0) {
+ continue;
+ }
+ final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
+ final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
+ final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
+ final long distance = xd*(long)xd + yd*(long)yd;
+ if (j == 0 || distance < bestDistance) {
+ bestDistance = distance;
+ bestIndex = j;
+ }
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
+ + " best old index=" + bestIndex + " (distance="
+ + bestDistance + ")");
+ next2Last[nextIndex] = bestIndex;
+ next2LastDistance[nextIndex] = bestDistance;
+
+ if (bestIndex < 0) {
+ return true;
+ }
+
+ if (last2Next[bestIndex] == -1) {
+ last2Next[bestIndex] = nextIndex;
+ return false;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
+ + " has multiple best new pointers!");
+
+ last2Next[bestIndex] = -2;
+ return true;
+ }
+
+ private int updatePointerIdentifiers() {
+ final int[] lastData = mLastData;
+ final int[] nextData = mNextData;
+ final int nextNumPointers = mNextNumPointers;
+ final int lastNumPointers = mLastNumPointers;
+
+ if (nextNumPointers == 1 && lastNumPointers == 1) {
+ System.arraycopy(nextData, 0, lastData, 0,
+ MotionEvent.NUM_SAMPLE_DATA);
+ return -1;
+ }
+
+ // Clear our old state.
+ final int[] last2Next = mLast2Next;
+ for (int i=0; i<lastNumPointers; i++) {
+ last2Next[i] = -1;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Update pointers: lastNumPointers=" + lastNumPointers
+ + " nextNumPointers=" + nextNumPointers);
+
+ // Figure out the closes new points to the previous points.
+ final int[] next2Last = mNext2Last;
+ final long[] next2LastDistance = mNext2LastDistance;
+ boolean conflicts = false;
+ for (int i=0; i<nextNumPointers; i++) {
+ conflicts |= assignPointer(i, true);
+ }
+
+ // Resolve ambiguities in pointer mappings, when two or more
+ // new pointer locations find their best previous location is
+ // the same.
+ if (conflicts) {
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
+
+ for (int i=0; i<lastNumPointers; i++) {
+ if (last2Next[i] != -2) {
+ continue;
+ }
+
+ // Note that this algorithm is far from perfect. Ideally
+ // we should do something like the one described at
+ // http://portal.acm.org/citation.cfm?id=997856
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Resolving last index #" + i);
+
+ int numFound;
+ do {
+ numFound = 0;
+ long worstDistance = 0;
+ int worstJ = -1;
+ for (int j=0; j<nextNumPointers; j++) {
+ if (next2Last[j] != i) {
+ continue;
+ }
+ numFound++;
+ if (worstDistance < next2LastDistance[j]) {
+ worstDistance = next2LastDistance[j];
+ worstJ = j;
+ }
+ }
+
+ if (worstJ >= 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Worst new pointer: " + worstJ
+ + " (distance=" + worstDistance + ")");
+ if (assignPointer(worstJ, false)) {
+ // In this case there is no last pointer
+ // remaining for this new one!
+ next2Last[worstJ] = -1;
+ }
+ }
+ } while (numFound > 2);
+ }
+ }
+
+ int retIndex = -1;
+
+ if (lastNumPointers < nextNumPointers) {
+ // We have one or more new pointers that are down. Create a
+ // new pointer identifier for one of them.
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
+ int nextId = 0;
+ int i=0;
+ while (i < lastNumPointers) {
+ if (mPointerIds[i] > nextId) {
+ // Found a hole, insert the pointer here.
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Inserting new pointer at hole " + i);
+ System.arraycopy(mPointerIds, i, mPointerIds,
+ i+1, lastNumPointers-i);
+ System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
+ lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
+ (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
+ break;
+ }
+ i++;
+ nextId++;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "New pointer id " + nextId + " at index " + i);
+
+ mLastNumPointers++;
+ retIndex = i;
+ mPointerIds[i] = nextId;
+
+ // And assign this identifier to the first new pointer.
+ for (int j=0; j<nextNumPointers; j++) {
+ if (next2Last[j] < 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Assigning new id to new pointer index " + j);
+ next2Last[j] = i;
+ break;
+ }
+ }
+ }
+
+ // Propagate all of the current data into the appropriate
+ // location in the old data to match the pointer ID that was
+ // assigned to it.
+ for (int i=0; i<nextNumPointers; i++) {
+ int lastIndex = next2Last[i];
+ if (lastIndex >= 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Copying next pointer index " + i
+ + " to last index " + lastIndex);
+ System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
+ lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
+ MotionEvent.NUM_SAMPLE_DATA);
+ }
+ }
+
+ if (lastNumPointers > nextNumPointers) {
+ // One or more pointers has gone up. Find the first one,
+ // and adjust accordingly.
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
+ for (int i=0; i<lastNumPointers; i++) {
+ if (last2Next[i] == -1) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Removing old pointer at index " + i);
+ retIndex = i;
+ break;
+ }
+ }
+ }
+
+ return retIndex;
+ }
+
+ void removeOldPointer(int index) {
+ final int lastNumPointers = mLastNumPointers;
+ if (index >= 0 && index < lastNumPointers) {
+ System.arraycopy(mPointerIds, index+1, mPointerIds,
+ index, lastNumPointers-index-1);
+ System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
+ mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
+ (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
+ mLastNumPointers--;
+ }
+ }
+
+ MotionEvent generateAbsMotion(InputDevice device, long curTime,
+ long curTimeNano, Display display, int orientation,
int metaState) {
- if (!changed) {
+
+ if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
return null;
}
- float scaledX = x;
- float scaledY = y;
- float temp;
- float scaledPressure = 1.0f;
- float scaledSize = 0;
+ final int lastNumPointers = mLastNumPointers;
+ final int nextNumPointers = mNextNumPointers;
+ if (mNextNumPointers > MAX_POINTERS) {
+ Log.w("InputDevice", "Number of pointers " + mNextNumPointers
+ + " exceeded maximum of " + MAX_POINTERS);
+ mNextNumPointers = MAX_POINTERS;
+ }
+
+ int upOrDownPointer = updatePointerIdentifiers();
+
+ final float[] reportData = mReportData;
+ final int[] rawData = mLastData;
+
+ final int numPointers = mLastNumPointers;
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
+ + numPointers + " pointers (going from " + lastNumPointers
+ + " to " + nextNumPointers + ")");
+
+ for (int i=0; i<numPointers; i++) {
+ final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
+ reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
+ reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
+ reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
+ reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
+ }
+
+ int action;
int edgeFlags = 0;
- if (isAbs) {
- int w = display.getWidth()-1;
- int h = display.getHeight()-1;
- if (orientation == Surface.ROTATION_90
- || orientation == Surface.ROTATION_270) {
- int tmp = w;
- w = h;
- h = tmp;
+ if (nextNumPointers != lastNumPointers) {
+ if (nextNumPointers > lastNumPointers) {
+ if (lastNumPointers == 0) {
+ action = MotionEvent.ACTION_DOWN;
+ mDownTime = curTime;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ }
+ } else {
+ if (numPointers == 1) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_POINTER_UP
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ }
}
- if (device.absX != null) {
- scaledX = ((scaledX-device.absX.minValue)
- / device.absX.range) * w;
- }
- if (device.absY != null) {
- scaledY = ((scaledY-device.absY.minValue)
- / device.absY.range) * h;
- }
- if (device.absPressure != null) {
- scaledPressure =
- ((pressure-device.absPressure.minValue)
- / (float)device.absPressure.range);
- }
- if (device.absSize != null) {
- scaledSize =
- ((size-device.absSize.minValue)
- / (float)device.absSize.range);
- }
- switch (orientation) {
- case Surface.ROTATION_90:
- temp = scaledX;
- scaledX = scaledY;
- scaledY = w-temp;
- break;
- case Surface.ROTATION_180:
- scaledX = w-scaledX;
- scaledY = h-scaledY;
- break;
- case Surface.ROTATION_270:
- temp = scaledX;
- scaledX = h-scaledY;
- scaledY = temp;
- break;
- }
-
- if (scaledX == 0) {
- edgeFlags += MotionEvent.EDGE_LEFT;
- } else if (scaledX == display.getWidth() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_RIGHT;
- }
-
- if (scaledY == 0) {
- edgeFlags += MotionEvent.EDGE_TOP;
- } else if (scaledY == display.getHeight() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_BOTTOM;
- }
-
+ currentMove = null;
} else {
- scaledX *= xMoveScale;
- scaledY *= yMoveScale;
+ action = MotionEvent.ACTION_MOVE;
+ }
+
+ final int dispW = display.getWidth()-1;
+ final int dispH = display.getHeight()-1;
+ int w = dispW;
+ int h = dispH;
+ if (orientation == Surface.ROTATION_90
+ || orientation == Surface.ROTATION_270) {
+ int tmp = w;
+ w = h;
+ h = tmp;
+ }
+
+ final AbsoluteInfo absX = device.absX;
+ final AbsoluteInfo absY = device.absY;
+ final AbsoluteInfo absPressure = device.absPressure;
+ final AbsoluteInfo absSize = device.absSize;
+ for (int i=0; i<numPointers; i++) {
+ final int j = i * MotionEvent.NUM_SAMPLE_DATA;
+
+ if (absX != null) {
+ reportData[j + MotionEvent.SAMPLE_X] =
+ ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
+ / absX.range) * w;
+ }
+ if (absY != null) {
+ reportData[j + MotionEvent.SAMPLE_Y] =
+ ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
+ / absY.range) * h;
+ }
+ if (absPressure != null) {
+ reportData[j + MotionEvent.SAMPLE_PRESSURE] =
+ ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
+ / (float)absPressure.range);
+ }
+ if (absSize != null) {
+ reportData[j + MotionEvent.SAMPLE_SIZE] =
+ ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
+ / (float)absSize.range);
+ }
+
switch (orientation) {
- case Surface.ROTATION_90:
- temp = scaledX;
- scaledX = scaledY;
- scaledY = -temp;
+ case Surface.ROTATION_90: {
+ final float temp = reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
+ reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
break;
- case Surface.ROTATION_180:
- scaledX = -scaledX;
- scaledY = -scaledY;
+ }
+ case Surface.ROTATION_180: {
+ reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
break;
- case Surface.ROTATION_270:
- temp = scaledX;
- scaledX = -scaledY;
- scaledY = temp;
+ }
+ case Surface.ROTATION_270: {
+ final float temp = reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
+ reportData[j + MotionEvent.SAMPLE_Y] = temp;
break;
+ }
}
}
- changed = false;
- if (down != lastDown) {
- int action;
- lastDown = down;
- if (down) {
- action = MotionEvent.ACTION_DOWN;
- downTime = curTime;
- } else {
- action = MotionEvent.ACTION_UP;
+ // We only consider the first pointer when computing the edge
+ // flags, since they are global to the event.
+ if (action == MotionEvent.ACTION_DOWN) {
+ if (reportData[MotionEvent.SAMPLE_X] <= 0) {
+ edgeFlags |= MotionEvent.EDGE_LEFT;
+ } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
+ edgeFlags |= MotionEvent.EDGE_RIGHT;
}
- currentMove = null;
- if (!isAbs) {
- x = y = 0;
+ if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
+ edgeFlags |= MotionEvent.EDGE_TOP;
+ } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
+ edgeFlags |= MotionEvent.EDGE_BOTTOM;
}
- return MotionEvent.obtain(downTime, curTime, action,
- scaledX, scaledY, scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
- } else {
- if (currentMove != null) {
- if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
- + " y=" + scaledY + " to " + currentMove);
- currentMove.addBatch(curTime, scaledX, scaledY,
- scaledPressure, scaledSize, metaState);
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
- }
- return null;
- }
- MotionEvent me = MotionEvent.obtain(downTime, curTime,
- MotionEvent.ACTION_MOVE, scaledX, scaledY,
- scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
- currentMove = me;
- return me;
}
+
+ if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x="
+ + reportData[MotionEvent.SAMPLE_X]
+ + " y=" + reportData[MotionEvent.SAMPLE_Y]
+ + " to " + currentMove);
+ currentMove.addBatch(curTime, reportData, metaState);
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
+ }
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
+ curTimeNano, action, numPointers, mPointerIds, reportData,
+ metaState, xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
+ currentMove = me;
+ }
+
+ if (nextNumPointers < lastNumPointers) {
+ removeOldPointer(upOrDownPointer);
+ }
+
+ return me;
+ }
+
+ boolean hasMore() {
+ return mLastNumPointers != mNextNumPointers;
+ }
+
+ void finish() {
+ mNextNumPointers = mAddingPointerOffset = 0;
+ mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
+ }
+
+ MotionEvent generateRelMotion(InputDevice device, long curTime,
+ long curTimeNano, int orientation, int metaState) {
+
+ final float[] scaled = mReportData;
+
+ // For now we only support 1 pointer with relative motions.
+ scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
+ scaled[MotionEvent.SAMPLE_SIZE] = 0;
+ int edgeFlags = 0;
+
+ int action;
+ if (mNextNumPointers != mLastNumPointers) {
+ mNextData[MotionEvent.SAMPLE_X] =
+ mNextData[MotionEvent.SAMPLE_Y] = 0;
+ if (mNextNumPointers > 0 && mLastNumPointers == 0) {
+ action = MotionEvent.ACTION_DOWN;
+ mDownTime = curTime;
+ } else if (mNextNumPointers == 0) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
+ }
+ mLastNumPointers = mNextNumPointers;
+ currentMove = null;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
+ }
+
+ scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
+ scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
+ switch (orientation) {
+ case Surface.ROTATION_90: {
+ final float temp = scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_Y] = -temp;
+ break;
+ }
+ case Surface.ROTATION_180: {
+ scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
+ break;
+ }
+ case Surface.ROTATION_270: {
+ final float temp = scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_Y] = temp;
+ break;
+ }
+ }
+
+ if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x="
+ + scaled[MotionEvent.SAMPLE_X]
+ + " y=" + scaled[MotionEvent.SAMPLE_Y]
+ + " to " + currentMove);
+ currentMove.addBatch(curTime, scaled, metaState);
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
+ }
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
+ curTimeNano, action, 1, mPointerIds, scaled, metaState,
+ xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
+ currentMove = me;
+ }
+ return me;
}
}
diff --git a/services/java/com/android/server/JournaledFile.java b/services/java/com/android/server/JournaledFile.java
new file mode 100644
index 0000000..3d1f52d
--- /dev/null
+++ b/services/java/com/android/server/JournaledFile.java
@@ -0,0 +1,107 @@
+/*
+ * 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 com.android.server;
+
+import java.io.File;
+import java.io.IOException;
+
+public class JournaledFile {
+ File mReal;
+ File mTemp;
+ boolean mWriting;
+
+ public JournaledFile(File real, File temp) {
+ mReal = real;
+ mTemp = temp;
+ }
+
+ /** Returns the file for you to read.
+ * @more
+ * Prefers the real file. If it doesn't exist, uses the temp one, and then copies
+ * it to the real one. If there is both a real file and a temp one, assumes that the
+ * temp one isn't fully written and deletes it.
+ */
+ public File chooseForRead() {
+ File result;
+ if (mReal.exists()) {
+ result = mReal;
+ if (mTemp.exists()) {
+ mTemp.delete();
+ }
+ } else if (mTemp.exists()) {
+ result = mTemp;
+ mTemp.renameTo(mReal);
+ } else {
+ return mReal;
+ }
+ return result;
+ }
+
+ /**
+ * Returns a file for you to write.
+ * @more
+ * If a write is already happening, throws. In other words, you must provide your
+ * own locking.
+ * <p>
+ * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes.
+ */
+ public File chooseForWrite() {
+ if (mWriting) {
+ throw new IllegalStateException("uncommitted write already in progress");
+ }
+ if (!mReal.exists()) {
+ // If the real one doesn't exist, it's either because this is the first time
+ // or because something went wrong while copying them. In this case, we can't
+ // trust anything that's in temp. In order to have the chooseForRead code not
+ // use the temporary one until it's fully written, create an empty file
+ // for real, which will we'll shortly delete.
+ try {
+ mReal.createNewFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ if (mTemp.exists()) {
+ mTemp.delete();
+ }
+ mWriting = true;
+ return mTemp;
+ }
+
+ /**
+ * Commit changes.
+ */
+ public void commit() {
+ if (!mWriting) {
+ throw new IllegalStateException("no file to commit");
+ }
+ mWriting = false;
+ mTemp.renameTo(mReal);
+ }
+
+ /**
+ * Roll back changes.
+ */
+ public void rollback() {
+ if (!mWriting) {
+ throw new IllegalStateException("no file to roll back");
+ }
+ mWriting = false;
+ mTemp.delete();
+ }
+}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 411cd6b..7ca12f21 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,10 +18,13 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.os.SystemClock;
+import android.os.Environment;
+import android.os.LatencyTimer;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
+import android.util.Xml;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -29,10 +32,30 @@
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
- SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ static final boolean DEBUG_VIRTUAL_KEYS = false;
+ static final boolean DEBUG_POINTERS = false;
+
+ private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
+
+ final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
+ final HapticFeedbackCallback mHapticFeedbackCallback;
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -43,10 +66,14 @@
int mCacheCount;
Display mDisplay = null;
+ int mDisplayWidth;
+ int mDisplayHeight;
int mOrientation = Surface.ROTATION_0;
int[] mKeyRotationMap = null;
+ VirtualKey mPressedVirtualKey = null;
+
PowerManager.WakeLock mWakeLock;
static final int[] KEY_90_MAP = new int[] {
@@ -73,14 +100,21 @@
public static final int FILTER_REMOVE = 0;
public static final int FILTER_KEEP = 1;
public static final int FILTER_ABORT = -1;
-
+
+ private static final boolean MEASURE_LATENCY = false;
+ private LatencyTimer lt;
+
public interface FilterCallback {
int filterEvent(QueuedEvent ev);
}
+ public interface HapticFeedbackCallback {
+ void virtualKeyFeedback(KeyEvent event);
+ }
+
static class QueuedEvent {
InputDevice inputDevice;
- long when;
+ long whenNano;
int flags; // From the raw event
int classType; // One of the class constants in InputEvent
Object event;
@@ -88,7 +122,7 @@
void copyFrom(QueuedEvent that) {
this.inputDevice = that.inputDevice;
- this.when = that.when;
+ this.whenNano = that.whenNano;
this.flags = that.flags;
this.classType = that.classType;
this.event = that.event;
@@ -106,7 +140,144 @@
QueuedEvent next;
}
- KeyInputQueue(Context context) {
+ /**
+ * A key that exists as a part of the touch-screen, outside of the normal
+ * display area of the screen.
+ */
+ static class VirtualKey {
+ int scancode;
+ int centerx;
+ int centery;
+ int width;
+ int height;
+
+ int hitLeft;
+ int hitTop;
+ int hitRight;
+ int hitBottom;
+
+ InputDevice lastDevice;
+ int lastKeycode;
+
+ boolean checkHit(int x, int y) {
+ return (x >= hitLeft && x <= hitRight
+ && y >= hitTop && y <= hitBottom);
+ }
+
+ void computeHitRect(InputDevice dev, int dw, int dh) {
+ if (dev == lastDevice) {
+ return;
+ }
+
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
+ + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
+
+ lastDevice = dev;
+
+ int minx = dev.absX.minValue;
+ int maxx = dev.absX.maxValue;
+
+ int halfw = width/2;
+ int left = centerx - halfw;
+ int right = centerx + halfw;
+ hitLeft = minx + ((left*maxx-minx)/dw);
+ hitRight = minx + ((right*maxx-minx)/dw);
+
+ int miny = dev.absY.minValue;
+ int maxy = dev.absY.maxValue;
+
+ int halfh = height/2;
+ int top = centery - halfh;
+ int bottom = centery + halfh;
+ hitTop = miny + ((top*maxy-miny)/dh);
+ hitBottom = miny + ((bottom*maxy-miny)/dh);
+ }
+ }
+
+ private void readVirtualKeys(String deviceName) {
+ try {
+ FileInputStream fis = new FileInputStream(
+ "/sys/board_properties/virtualkeys." + deviceName);
+ InputStreamReader isr = new InputStreamReader(fis);
+ BufferedReader br = new BufferedReader(isr);
+ String str = br.readLine();
+ if (str != null) {
+ String[] it = str.split(":");
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
+ final int N = it.length-6;
+ for (int i=0; i<=N; i+=6) {
+ if (!"0x01".equals(it[i])) {
+ Log.w(TAG, "Unknown virtual key type at elem #" + i
+ + ": " + it[i]);
+ continue;
+ }
+ try {
+ VirtualKey sb = new VirtualKey();
+ sb.scancode = Integer.parseInt(it[i+1]);
+ sb.centerx = Integer.parseInt(it[i+2]);
+ sb.centery = Integer.parseInt(it[i+3]);
+ sb.width = Integer.parseInt(it[i+4]);
+ sb.height = Integer.parseInt(it[i+5]);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
+ + sb.scancode + ": center=" + sb.centerx + ","
+ + sb.centery + " size=" + sb.width + "x"
+ + sb.height);
+ mVirtualKeys.add(sb);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Bad number at region " + i + " in: "
+ + str, e);
+ }
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No virtual keys found");
+ } catch (IOException e) {
+ Log.w(TAG, "Error reading virtual keys", e);
+ }
+ }
+
+ private void readExcludedDevices() {
+ // Read partner-provided list of excluded input devices
+ XmlPullParser parser = null;
+ // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
+ File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
+ FileReader confreader = null;
+ try {
+ confreader = new FileReader(confFile);
+ parser = Xml.newPullParser();
+ parser.setInput(confreader);
+ XmlUtils.beginDocument(parser, "devices");
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (!"device".equals(parser.getName())) {
+ break;
+ }
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ Log.d(TAG, "addExcludedDevice " + name);
+ addExcludedDevice(name);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // It's ok if the file does not exist.
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+ } finally {
+ try { if (confreader != null) confreader.close(); } catch (IOException e) { }
+ }
+ }
+
+ KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
+ mHapticFeedbackCallback = hapticFeedbackCallback;
+
+ readExcludedDevices();
+
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -123,6 +294,12 @@
public void setDisplay(Display display) {
mDisplay = display;
+
+ // We assume at this point that the display dimensions reflect the
+ // natural, unrotated display. We will perform hit tests for soft
+ // buttons based on that display.
+ mDisplayWidth = display.getWidth();
+ mDisplayHeight = display.getHeight();
}
public void getInputConfiguration(Configuration config) {
@@ -149,6 +326,10 @@
config.navigation
= Configuration.NAVIGATION_TRACKBALL;
//Log.i("foo", "***** HAVE TRACKBALL!");
+ } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
+ config.navigation
+ = Configuration.NAVIGATION_DPAD;
+ //Log.i("foo", "***** HAVE DPAD!");
}
}
}
@@ -157,6 +338,7 @@
public static native String getDeviceName(int deviceId);
public static native int getDeviceClasses(int deviceId);
+ public static native void addExcludedDevice(String deviceName);
public static native boolean getAbsoluteInfo(int deviceId, int axis,
InputDevice.AbsoluteInfo outInfo);
public static native int getSwitchState(int sw);
@@ -165,6 +347,7 @@
public static native int getScancodeState(int deviceId, int sw);
public static native int getKeycodeState(int sw);
public static native int getKeycodeState(int deviceId, int sw);
+ public static native int scancodeToKeycode(int deviceId, int scancode);
public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
@@ -181,12 +364,13 @@
Thread mThread = new Thread("InputDeviceReader") {
public void run() {
+ Log.d(TAG, "InputDeviceReader.run()");
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
- try {
- RawInputEvent ev = new RawInputEvent();
- while (true) {
+ RawInputEvent ev = new RawInputEvent();
+ while (true) {
+ try {
InputDevice di;
// block, doesn't release the monitor
@@ -208,6 +392,9 @@
synchronized (mFirst) {
di = newInputDevice(ev.deviceId);
mDevices.put(ev.deviceId, di);
+ if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ readVirtualKeys(di.name);
+ }
configChanged = true;
}
} else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
@@ -241,7 +428,7 @@
if (configChanged) {
synchronized (mFirst) {
- addLocked(di, SystemClock.uptimeMillis(), 0,
+ addLocked(di, System.nanoTime(), 0,
RawInputEvent.CLASS_CONFIGURATION_CHANGED,
null);
}
@@ -256,6 +443,7 @@
// timebase as SystemClock.uptimeMillis().
//curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
final long curTime = SystemClock.uptimeMillis();
+ final long curTimeNano = System.nanoTime();
//Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
final int classes = di.classes;
@@ -271,44 +459,92 @@
boolean down;
if (ev.value != 0) {
down = true;
- di.mDownTime = curTime;
+ di.mKeyDownTime = curTime;
} else {
down = false;
}
int keycode = rotateKeyCodeLocked(ev.keycode);
- addLocked(di, curTime, ev.flags,
+ addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
- newKeyEvent(di, di.mDownTime, curTime, down,
+ newKeyEvent(di, di.mKeyDownTime, curTime, down,
keycode, 0, scancode,
((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
? KeyEvent.FLAG_WOKE_HERE : 0));
} else if (ev.type == RawInputEvent.EV_KEY) {
if (ev.scancode == RawInputEvent.BTN_TOUCH &&
- (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ (classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
di.mAbs.changed = true;
- di.mAbs.down = ev.value != 0;
- }
- if (ev.scancode == RawInputEvent.BTN_MOUSE &&
+ di.mAbs.mDown[0] = ev.value != 0;
+ } else if (ev.scancode == RawInputEvent.BTN_2 &&
+ (classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
+ di.mAbs.changed = true;
+ di.mAbs.mDown[1] = ev.value != 0;
+ } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
(classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
di.mRel.changed = true;
- di.mRel.down = ev.value != 0;
+ di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
send = true;
}
} else if (ev.type == RawInputEvent.EV_ABS &&
+ (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
+ if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_PRESSURE] = ev.value;
+ } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_X] = ev.value;
+ if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ + di.mAbs.mAddingPointerOffset
+ + " X:" + ev.value);
+ } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_Y] = ev.value;
+ if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ + di.mAbs.mAddingPointerOffset
+ + " Y:" + ev.value);
+ } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_SIZE] = ev.value;
+ }
+
+ } else if (ev.type == RawInputEvent.EV_ABS &&
(classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ // Finger 1
if (ev.scancode == RawInputEvent.ABS_X) {
di.mAbs.changed = true;
- di.mAbs.x = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_Y) {
di.mAbs.changed = true;
- di.mAbs.y = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
di.mAbs.changed = true;
- di.mAbs.pressure = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_PRESSURE] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
di.mAbs.changed = true;
- di.mAbs.size = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_SIZE] = ev.value;
+
+ // Finger 2
+ } else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
+ di.mAbs.changed = true;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_X] = ev.value;
+ } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
+ di.mAbs.changed = true;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_Y] = ev.value;
}
} else if (ev.type == RawInputEvent.EV_REL &&
@@ -316,50 +552,277 @@
// Add this relative movement into our totals.
if (ev.scancode == RawInputEvent.REL_X) {
di.mRel.changed = true;
- di.mRel.x += ev.value;
+ di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
} else if (ev.scancode == RawInputEvent.REL_Y) {
di.mRel.changed = true;
- di.mRel.y += ev.value;
+ di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
}
}
- if (send || ev.type == RawInputEvent.EV_SYN) {
+ if (ev.type == RawInputEvent.EV_SYN
+ && ev.scancode == RawInputEvent.SYN_MT_REPORT
+ && di.mAbs != null) {
+ di.mAbs.changed = true;
+ if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
+ // If the value is <= 0, the pointer is not
+ // down, so keep it in the count.
+
+ if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_PRESSURE] != 0) {
+ final int num = di.mAbs.mNextNumPointers+1;
+ di.mAbs.mNextNumPointers = num;
+ if (DEBUG_POINTERS) Log.v(TAG,
+ "MT_REPORT: now have " + num + " pointers");
+ final int newOffset = (num <= InputDevice.MAX_POINTERS)
+ ? (num * MotionEvent.NUM_SAMPLE_DATA)
+ : (InputDevice.MAX_POINTERS *
+ MotionEvent.NUM_SAMPLE_DATA);
+ di.mAbs.mAddingPointerOffset = newOffset;
+ di.mAbs.mNextData[newOffset
+ + MotionEvent.SAMPLE_PRESSURE] = 0;
+ } else {
+ if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
+ }
+ }
+ } else if (send || (ev.type == RawInputEvent.EV_SYN
+ && ev.scancode == RawInputEvent.SYN_REPORT)) {
if (mDisplay != null) {
if (!mHaveGlobalMetaState) {
computeGlobalMetaStateLocked();
}
MotionEvent me;
- me = di.mAbs.generateMotion(di, curTime, true,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
- + " y=" + di.mAbs.y + " ev=" + me);
- if (me != null) {
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i(TAG, "Enqueueing: " + me);
+
+ InputDevice.MotionState ms = di.mAbs;
+ if (ms.changed) {
+ ms.changed = false;
+
+ if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
+ ms.mNextNumPointers = 0;
+ if (ms.mDown[0]) {
+ System.arraycopy(di.curTouchVals, 0,
+ ms.mNextData, 0,
+ MotionEvent.NUM_SAMPLE_DATA);
+ ms.mNextNumPointers++;
+ }
+ if (ms.mDown[1]) {
+ System.arraycopy(di.curTouchVals,
+ MotionEvent.NUM_SAMPLE_DATA,
+ ms.mNextData,
+ ms.mNextNumPointers
+ * MotionEvent.NUM_SAMPLE_DATA,
+ MotionEvent.NUM_SAMPLE_DATA);
+ ms.mNextNumPointers++;
+ }
}
- addLocked(di, curTime, ev.flags,
- RawInputEvent.CLASS_TOUCHSCREEN, me);
+
+ boolean doMotion = !monitorVirtualKey(di,
+ ev, curTime, curTimeNano);
+
+ if (doMotion && ms.mNextNumPointers > 0
+ && ms.mLastNumPointers == 0) {
+ doMotion = !generateVirtualKeyDown(di,
+ ev, curTime, curTimeNano);
+ }
+
+ if (doMotion) {
+ // XXX Need to be able to generate
+ // multiple events here, for example
+ // if two fingers change up/down state
+ // at the same time.
+ do {
+ me = ms.generateAbsMotion(di, curTime,
+ curTimeNano, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Absolute: x="
+ + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
+ + " y="
+ + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
+ + " ev=" + me);
+ if (me != null) {
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i(TAG, "Enqueueing: " + me);
+ }
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TOUCHSCREEN, me);
+ }
+ } while (ms.hasMore());
+ }
+
+ ms.finish();
}
- me = di.mRel.generateMotion(di, curTime, false,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
- + " y=" + di.mRel.y + " ev=" + me);
- if (me != null) {
- addLocked(di, curTime, ev.flags,
- RawInputEvent.CLASS_TRACKBALL, me);
+
+ ms = di.mRel;
+ if (ms.changed) {
+ ms.changed = false;
+
+ me = ms.generateRelMotion(di, curTime,
+ curTimeNano,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Relative: x="
+ + di.mRel.mNextData[MotionEvent.SAMPLE_X]
+ + " y="
+ + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
+ + " ev=" + me);
+ if (me != null) {
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TRACKBALL, me);
+ }
+
+ ms.finish();
}
}
}
}
+
+ } catch (RuntimeException exc) {
+ Log.e(TAG, "InputReaderThread uncaught exception", exc);
}
}
- catch (RuntimeException exc) {
- Log.e(TAG, "InputReaderThread uncaught exception", exc);
- }
}
};
+ private boolean isInsideDisplay(InputDevice dev) {
+ final InputDevice.AbsoluteInfo absx = dev.absX;
+ final InputDevice.AbsoluteInfo absy = dev.absY;
+ final InputDevice.MotionState absm = dev.mAbs;
+ if (absx == null || absy == null || absm == null) {
+ return true;
+ }
+
+ if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
+ && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
+ && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
+ && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input ("
+ + absm.mNextData[MotionEvent.SAMPLE_X]
+ + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
+ + ") inside of display");
+ return true;
+ }
+
+ return false;
+ }
+
+ private VirtualKey findVirtualKey(InputDevice dev) {
+ final int N = mVirtualKeys.size();
+ if (N <= 0) {
+ return null;
+ }
+
+ final InputDevice.MotionState absm = dev.mAbs;
+ for (int i=0; i<N; i++) {
+ VirtualKey sb = mVirtualKeys.get(i);
+ sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test ("
+ + absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
+ + sb.scancode + " - (" + sb.hitLeft
+ + "," + sb.hitTop + ")-(" + sb.hitRight + ","
+ + sb.hitBottom + ")");
+ if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
+ absm.mNextData[MotionEvent.SAMPLE_Y])) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
+ return sb;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
+ long curTime, long curTimeNano) {
+ if (isInsideDisplay(di)) {
+ // Didn't consume event.
+ return false;
+ }
+
+
+ VirtualKey vk = findVirtualKey(di);
+ if (vk != null) {
+ final InputDevice.MotionState ms = di.mAbs;
+ mPressedVirtualKey = vk;
+ vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
+ ms.mLastNumPointers = ms.mNextNumPointers;
+ di.mKeyDownTime = curTime;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key down for: " + vk.scancode
+ + " (keycode=" + vk.lastKeycode + ")");
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ }
+
+ // We always consume the event, even if we didn't
+ // generate a key event. There are two reasons for
+ // this: to avoid spurious touches when holding
+ // the edges of the device near the touchscreen,
+ // and to avoid reporting events if there are virtual
+ // keys on the touchscreen outside of the display
+ // area.
+ // Note that for all of this we are only looking at the
+ // first pointer, since what we are handling here is the
+ // first pointer going down, and this is the coordinate
+ // that will be used to dispatch the event.
+ if (false) {
+ final InputDevice.AbsoluteInfo absx = di.absX;
+ final InputDevice.AbsoluteInfo absy = di.absY;
+ final InputDevice.MotionState absm = di.mAbs;
+ Log.v(TAG, "Rejecting ("
+ + absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
+ + absx.minValue + "," + absy.minValue
+ + ")-(" + absx.maxValue + ","
+ + absx.maxValue + ")");
+ }
+ return true;
+ }
+
+ private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
+ long curTime, long curTimeNano) {
+ VirtualKey vk = mPressedVirtualKey;
+ if (vk == null) {
+ return false;
+ }
+
+ final InputDevice.MotionState ms = di.mAbs;
+ if (ms.mNextNumPointers <= 0) {
+ mPressedVirtualKey = null;
+ ms.mLastNumPointers = 0;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode);
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ return true;
+
+ } else if (isInsideDisplay(di)) {
+ // Whoops the pointer has moved into
+ // the display area! Cancel the
+ // virtual key and start a pointer
+ // motion.
+ mPressedVirtualKey = null;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode);
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ ms.mLastNumPointers = 0;
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Returns a new meta state for the given keys and old state.
*/
@@ -506,8 +969,8 @@
if (ev.event == ev.inputDevice.mRel.currentMove) {
if (false) Log.i(TAG, "Detach rel " + ev.event);
ev.inputDevice.mRel.currentMove = null;
- ev.inputDevice.mRel.x = 0;
- ev.inputDevice.mRel.y = 0;
+ ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
+ ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
}
recycleLocked(ev);
}
@@ -530,7 +993,7 @@
}
}
- private QueuedEvent obtainLocked(InputDevice device, long when,
+ private QueuedEvent obtainLocked(InputDevice device, long whenNano,
int flags, int classType, Object event) {
QueuedEvent ev;
if (mCacheCount == 0) {
@@ -542,7 +1005,7 @@
mCacheCount--;
}
ev.inputDevice = device;
- ev.when = when;
+ ev.whenNano = whenNano;
ev.flags = flags;
ev.classType = classType;
ev.event = event;
@@ -561,13 +1024,13 @@
}
}
- private void addLocked(InputDevice device, long when, int flags,
+ private void addLocked(InputDevice device, long whenNano, int flags,
int classType, Object event) {
boolean poke = mFirst.next == mLast;
- QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
+ QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
QueuedEvent p = mLast.prev;
- while (p != mFirst && ev.when < p.when) {
+ while (p != mFirst && ev.whenNano < p.whenNano) {
p = p.prev;
}
@@ -578,8 +1041,15 @@
ev.inQueue = true;
if (poke) {
+ long time;
+ if (MEASURE_LATENCY) {
+ time = System.nanoTime();
+ }
mFirst.notify();
mWakeLock.acquire();
+ if (MEASURE_LATENCY) {
+ lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
+ }
}
}
@@ -593,7 +1063,12 @@
InputDevice.AbsoluteInfo absY;
InputDevice.AbsoluteInfo absPressure;
InputDevice.AbsoluteInfo absSize;
- if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
+ absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X");
+ absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y");
+ absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
+ absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
+ } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X");
absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y");
absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure");
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/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index 5a42e76..3c366da 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -30,8 +30,8 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) {
- if (!intent.getBooleanExtra("from_trusted_server", false)) {
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index aac7124..5dad8d0 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -96,7 +96,7 @@
private Vibrator mVibrator = new Vibrator();
// adb
- private int mBatteryPlugged;
+ private boolean mUsbConnected;
private boolean mAdbEnabled = false;
private boolean mAdbNotificationShown = false;
private Notification mAdbNotification;
@@ -310,8 +310,11 @@
mBatteryFull = batteryFull;
updateLights();
}
-
- mBatteryPlugged = intent.getIntExtra("plugged", 0);
+ } else if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
+ mUsbConnected = true;
+ updateAdbNotification();
+ } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
+ mUsbConnected = false;
updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
@@ -380,6 +383,8 @@
// register for battery changed notifications
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_UMS_CONNECTED);
+ filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(mIntentReceiver, filter);
@@ -954,7 +959,7 @@
// security feature that we don't want people customizing the platform
// to accidentally lose.
private void updateAdbNotification() {
- if (mAdbEnabled && mBatteryPlugged == BatteryManager.BATTERY_PLUGGED_USB) {
+ if (mAdbEnabled && mUsbConnected) {
if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
return;
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 89f854e..aac13b6 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1138,25 +1138,57 @@
|| p2 == null || p2.mExtras == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(p1, p2);
+ return checkSignaturesLP(p1.mSignatures, p2.mSignatures);
}
}
- int checkSignaturesLP(PackageParser.Package p1, PackageParser.Package p2) {
- if (p1.mSignatures == null) {
- return p2.mSignatures == null
+ public int checkUidSignatures(int uid1, int uid2) {
+ synchronized (mPackages) {
+ Signature[] s1;
+ Signature[] s2;
+ Object obj = mSettings.getUserIdLP(uid1);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ s1 = ((SharedUserSetting)obj).signatures.mSignatures;
+ } else if (obj instanceof PackageSetting) {
+ s1 = ((PackageSetting)obj).signatures.mSignatures;
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ obj = mSettings.getUserIdLP(uid2);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ s2 = ((SharedUserSetting)obj).signatures.mSignatures;
+ } else if (obj instanceof PackageSetting) {
+ s2 = ((PackageSetting)obj).signatures.mSignatures;
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ return checkSignaturesLP(s1, s2);
+ }
+ }
+
+ int checkSignaturesLP(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
: PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
}
- if (p2.mSignatures == null) {
+ if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
- final int N1 = p1.mSignatures.length;
- final int N2 = p2.mSignatures.length;
+ final int N1 = s1.length;
+ final int N2 = s2.length;
for (int i=0; i<N1; i++) {
boolean match = false;
for (int j=0; j<N2; j++) {
- if (p1.mSignatures[i].equals(p2.mSignatures[j])) {
+ if (s1[i].equals(s2[j])) {
match = true;
break;
}
@@ -1677,6 +1709,9 @@
}
}
+ /**
+ * @deprecated
+ */
public void querySyncProviders(List outNames, List outInfo) {
synchronized (mPackages) {
Iterator<Map.Entry<String, PackageParser.Provider>> i
@@ -2904,9 +2939,9 @@
allowed = true;
} else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
|| p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- allowed = (checkSignaturesLP(p.owner, pkg)
+ allowed = (checkSignaturesLP(p.owner.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (checkSignaturesLP(mPlatformPackage, pkg)
+ || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -3553,7 +3588,8 @@
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) {
+ if(checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
+ != PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 79d78ad1..1249289 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -29,6 +29,10 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -58,7 +62,8 @@
import java.util.Observable;
import java.util.Observer;
-class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
+class PowerManagerService extends IPowerManager.Stub
+ implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
private static final String TAG = "PowerManagerService";
static final String PARTIAL_NAME = "PowerManagerService";
@@ -72,7 +77,8 @@
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.SCREEN_DIM_WAKE_LOCK
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.FULL_WAKE_LOCK;
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
// time since last state: time since last event:
// The short keylight delay comes from Gservices; this is the default.
@@ -138,6 +144,7 @@
private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private int[] mBroadcastWhy = new int[3];
private int mPartialCount = 0;
+ private int mProximityCount = 0;
private int mPowerState;
private boolean mOffBecauseOfUser;
private int mUserState;
@@ -175,6 +182,8 @@
private IActivityManager mActivityService;
private IBatteryStats mBatteryStats;
private BatteryService mBatteryService;
+ private SensorManager mSensorManager;
+ private Sensor mProximitySensor;
private boolean mDimScreen = true;
private long mNextTimeout;
private volatile int mPokey = 0;
@@ -536,6 +545,7 @@
wl.minState = SCREEN_DIM;
break;
case PowerManager.PARTIAL_WAKE_LOCK:
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
// just log and bail. we're in the server, so don't
@@ -583,6 +593,11 @@
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
+ } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount++;
+ if (mProximityCount == 1) {
+ enableProximityLockLocked();
+ }
}
if (newlock) {
acquireUid = wl.uid;
@@ -639,6 +654,11 @@
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
+ } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount--;
+ if (mProximityCount == 0) {
+ disableProximityLockLocked();
+ }
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
@@ -745,15 +765,17 @@
switch (type)
{
case PowerManager.FULL_WAKE_LOCK:
- return "FULL_WAKE_LOCK ";
+ return "FULL_WAKE_LOCK ";
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- return "SCREEN_BRIGHT_WAKE_LOCK";
+ return "SCREEN_BRIGHT_WAKE_LOCK ";
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- return "SCREEN_DIM_WAKE_LOCK ";
+ return "SCREEN_DIM_WAKE_LOCK ";
case PowerManager.PARTIAL_WAKE_LOCK:
- return "PARTIAL_WAKE_LOCK ";
+ return "PARTIAL_WAKE_LOCK ";
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
default:
- return "??? ";
+ return "??? ";
}
}
@@ -1996,4 +2018,55 @@
public void monitor() {
synchronized (mLocks) { }
}
+
+ public int getSupportedWakeLockFlags() {
+ int result = PowerManager.PARTIAL_WAKE_LOCK
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.SCREEN_DIM_WAKE_LOCK;
+
+ // call getSensorManager() to make sure mProximitySensor is initialized
+ getSensorManager();
+ if (mProximitySensor != null) {
+ result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+ }
+
+ return result;
+ }
+
+ private SensorManager getSensorManager() {
+ if (mSensorManager == null) {
+ mSensorManager = new SensorManager(mHandlerThread.getLooper());
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
+ return mSensorManager;
+ }
+
+ private void enableProximityLockLocked() {
+ mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ private void disableProximityLockLocked() {
+ mSensorManager.unregisterListener(this);
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ long milliseconds = event.timestamp / 1000000;
+ if (event.values[0] == 0.0) {
+ goToSleep(milliseconds);
+ } else {
+ // 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;
+ }
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // ignore
+ }
}
diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/java/com/android/server/ShutdownActivity.java
new file mode 100644
index 0000000..7f0e90d
--- /dev/null
+++ b/services/java/com/android/server/ShutdownActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.server;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import com.android.internal.app.ShutdownThread;
+
+public class ShutdownActivity extends Activity {
+
+ private static final String TAG = "ShutdownActivity";
+ private boolean mConfirm;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mConfirm = getIntent().getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ Log.i(TAG, "onCreate(): confirm=" + mConfirm);
+
+ Handler h = new Handler();
+ h.post(new Runnable() {
+ public void run() {
+ ShutdownThread.shutdown(ShutdownActivity.this, mConfirm);
+ }
+ });
+ }
+}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
new file mode 100644
index 0000000..17d0f1d
--- /dev/null
+++ b/services/java/com/android/server/SystemBackupAgent.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 com.android.server;
+
+import android.backup.AbsoluteFileBackupHelper;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataInputStream;
+import android.backup.BackupDataOutput;
+import android.backup.BackupHelper;
+import android.backup.BackupHelperAgent;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.ServiceManager;
+import android.os.SystemService;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Backup agent for various system-managed data
+ */
+public class SystemBackupAgent extends BackupHelperAgent {
+ private static final String TAG = "SystemBackupAgent";
+
+ private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+ private static final String WALLPAPER_INFO = "/data/system/wallpaper_info.xml";
+
+ @Override
+ public void onCreate() {
+ addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
+ new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ boolean success = false;
+ try {
+ super.onRestore(data, appVersionCode, newState);
+
+ WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+ Context.WALLPAPER_SERVICE);
+ wallpaper.settingsRestored();
+ } catch (IOException ex) {
+ // If there was a failure, delete everything for the wallpaper, this is too aggresive,
+ // but this is hopefully a rare failure.
+ Log.d(TAG, "restore failed", ex);
+ (new File(WALLPAPER_IMAGE)).delete();
+ (new File(WALLPAPER_INFO)).delete();
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aa1a5cf..98f35f4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,19 +32,15 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
+import android.os.*;
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;
+import android.accounts.AccountManagerService;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -52,7 +48,6 @@
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private final static boolean INCLUDE_DEMO = false;
- private final static boolean INCLUDE_BACKUP = false;
private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010;
@@ -89,12 +84,15 @@
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 {
@@ -121,6 +119,14 @@
mContentResolver = context.getContentResolver();
+ try {
+ Log.i(TAG, "Starting Account Manager.");
+ ServiceManager.addService(Context.ACCOUNT_SERVICE,
+ new AccountManagerService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Account Manager", e);
+ }
+
Log.i(TAG, "Starting Content Manager.");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
@@ -129,7 +135,7 @@
ActivityManagerService.installSystemProviders();
Log.i(TAG, "Starting Battery Service.");
- BatteryService battery = new BatteryService(context);
+ battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
Log.i(TAG, "Starting Hardware Service.");
@@ -170,10 +176,10 @@
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);
- bluetoothA2dp = new BluetoothA2dpService(context);
+ bluetooth.initAfterRegistration();
+ bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
@@ -192,6 +198,7 @@
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
NotificationManagerService notification = null;
+ WallpaperManagerService wallpaper = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -226,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);
}
@@ -298,7 +305,8 @@
try {
Log.i(TAG, "Starting Wallpaper Service");
- ServiceManager.addService(Context.WALLPAPER_SERVICE, new WallpaperService(context));
+ wallpaper = new WallpaperManagerService(context);
+ ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Wallpaper Service", e);
}
@@ -319,10 +327,16 @@
}
try {
- if (INCLUDE_BACKUP) {
- Log.i(TAG, "Starting Backup Service");
- ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
- }
+ 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) {
Log.e(TAG, "Failure starting Backup Service", e);
}
@@ -379,6 +393,9 @@
} catch (RemoteException e) {
}
+ if (wallpaper != null) wallpaper.systemReady();
+ if (battery != null) battery.systemReady();
+ if (connectivity != null) connectivity.systemReady();
Watchdog.getInstance().start();
Looper.loop();
@@ -422,19 +439,19 @@
public static final int FACTORY_TEST_OFF = 0;
public static final int FACTORY_TEST_LOW_LEVEL = 1;
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
-
- /**
- * This method is called from Zygote to initialize the system. This will cause the native
+
+ /**
+ * This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
- */
+ */
native public static void init1(String[] args);
public static void main(String[] args) {
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
-
+
System.loadLibrary("android_servers");
init1(args);
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 9f2856c..7379b5d 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -88,6 +88,8 @@
private String mDataConnectionApn = "";
+ private String[] mDataConnectionApnTypes = null;
+
private String mDataConnectionInterfaceName = "";
private Bundle mCellLocation = new Bundle();
@@ -337,7 +339,7 @@
}
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ String reason, String apn, String[] apnTypes, String interfaceName) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
@@ -346,6 +348,7 @@
mDataConnectionPossible = isDataConnectivityPossible;
mDataConnectionReason = reason;
mDataConnectionApn = apn;
+ mDataConnectionApnTypes = apnTypes;
mDataConnectionInterfaceName = interfaceName;
for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
@@ -359,7 +362,7 @@
}
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- interfaceName);
+ apnTypes, interfaceName);
}
public void notifyDataConnectionFailed(String reason) {
@@ -517,8 +520,9 @@
mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
}
- private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ private void broadcastDataConnectionStateChanged(int state,
+ boolean isDataConnectivityPossible,
+ String reason, String apn, String[] apnTypes, String interfaceName) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -531,6 +535,11 @@
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];
+ }
+ intent.putExtra(Phone.DATA_APN_TYPES_KEY, types);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
mContext.sendStickyBroadcast(intent);
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
new file mode 100644
index 0000000..6047742
--- /dev/null
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -0,0 +1,613 @@
+/*
+ * 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 static android.os.FileObserver.*;
+import static android.os.ParcelFileDescriptor.*;
+
+import android.app.IWallpaperManager;
+import android.app.IWallpaperManagerCallback;
+import android.backup.BackupManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.FileObserver;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.service.wallpaper.IWallpaperConnection;
+import android.service.wallpaper.IWallpaperEngine;
+import android.service.wallpaper.IWallpaperService;
+import android.service.wallpaper.WallpaperService;
+import android.util.Log;
+import android.util.Xml;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import com.android.internal.service.wallpaper.ImageWallpaper;
+import com.android.internal.util.FastXmlSerializer;
+
+class WallpaperManagerService extends IWallpaperManager.Stub {
+ static final String TAG = "WallpaperService";
+ static final boolean DEBUG = true;
+
+ Object mLock = new Object();
+
+ /**
+ * Minimum time between crashes of a wallpaper service for us to consider
+ * restarting it vs. just reverting to the static wallpaper.
+ */
+ static final long MIN_WALLPAPER_CRASH_TIME = 10000;
+
+ static final File WALLPAPER_DIR = new File(
+ "/data/data/com.android.settings/files");
+ static final String WALLPAPER = "wallpaper";
+ static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
+
+ /**
+ * List of callbacks registered they should each be notified
+ * when the wallpaper is changed.
+ */
+ private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ /**
+ * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
+ * that the wallpaper has changed. The CREATE is triggered when there is no
+ * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
+ * everytime the wallpaper is changed.
+ */
+ private final FileObserver mWallpaperObserver = new FileObserver(
+ WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) {
+ @Override
+ public void onEvent(int event, String path) {
+ if (path == null) {
+ return;
+ }
+ synchronized (mLock) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ File changedFile = new File(WALLPAPER_DIR, path);
+ if (WALLPAPER_FILE.equals(changedFile)) {
+ notifyCallbacksLocked();
+ }
+ }
+ }
+ };
+
+ final Context mContext;
+ final IWindowManager mIWindowManager;
+
+ int mWidth = -1;
+ int mHeight = -1;
+ String mName = "";
+ ComponentName mWallpaperComponent;
+ WallpaperConnection mWallpaperConnection;
+ long mLastDiedTime;
+
+ class WallpaperConnection extends IWallpaperConnection.Stub
+ implements ServiceConnection {
+ final Binder mToken = new Binder();
+ IWallpaperService mService;
+ IWallpaperEngine mEngine;
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ if (mWallpaperConnection == this) {
+ mService = IWallpaperService.Stub.asInterface(service);
+ attachServiceLocked(this);
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ mService = null;
+ mEngine = null;
+ if (mWallpaperConnection == this) {
+ Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
+ if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
+ < SystemClock.uptimeMillis()) {
+ Log.w(TAG, "Reverting to built-in wallpaper!");
+ bindWallpaperComponentLocked(null);
+ }
+ }
+ }
+ }
+
+ public void attachEngine(IWallpaperEngine engine) {
+ mEngine = engine;
+ }
+
+ public ParcelFileDescriptor setWallpaper(String name) {
+ synchronized (mLock) {
+ if (mWallpaperConnection == this) {
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ if (pfd != null) {
+ saveSettingsLocked();
+ }
+ return pfd;
+ }
+ return null;
+ }
+ }
+ }
+
+ public WallpaperManagerService(Context context) {
+ if (DEBUG) Log.d(TAG, "WallpaperService startup");
+ mContext = context;
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ WALLPAPER_DIR.mkdirs();
+ loadSettingsLocked();
+ mWallpaperObserver.startWatching();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ mWallpaperObserver.stopWatching();
+ }
+
+ public void systemReady() {
+ synchronized (mLock) {
+ try {
+ bindWallpaperComponentLocked(mWallpaperComponent);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failure starting previous wallpaper", e);
+ try {
+ bindWallpaperComponentLocked(null);
+ } catch (RuntimeException e2) {
+ Log.w(TAG, "Failure starting default wallpaper", e2);
+ clearWallpaperComponentLocked();
+ }
+ }
+ }
+ }
+
+ public void clearWallpaper() {
+ synchronized (mLock) {
+ File f = WALLPAPER_FILE;
+ if (f.exists()) {
+ f.delete();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void setDimensionHints(int width, int height) throws RemoteException {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("width and height must be > 0");
+ }
+
+ synchronized (mLock) {
+ if (width != mWidth || height != mHeight) {
+ mWidth = width;
+ mHeight = height;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getWidthHint() throws RemoteException {
+ synchronized (mLock) {
+ return mWidth;
+ }
+ }
+
+ public int getHeightHint() throws RemoteException {
+ synchronized (mLock) {
+ return mHeight;
+ }
+ }
+
+ public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb) {
+ synchronized (mLock) {
+ try {
+ mCallbacks.register(cb);
+ File f = WALLPAPER_FILE;
+ if (!f.exists()) {
+ return null;
+ }
+ return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ /* Shouldn't happen as we check to see if the file exists */
+ Log.w(TAG, "Error getting wallpaper", e);
+ }
+ return null;
+ }
+ }
+
+ public ParcelFileDescriptor setWallpaper(String name) {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER);
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ if (pfd != null) {
+ bindWallpaperComponentLocked(null);
+ saveSettingsLocked();
+ }
+ return pfd;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+ if (name == null) name = "";
+ try {
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ MODE_CREATE|MODE_READ_WRITE);
+ mName = name;
+ return fd;
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Error setting wallpaper", e);
+ }
+ return null;
+ }
+
+ public void setWallpaperComponent(ComponentName name) {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ void bindWallpaperComponentLocked(ComponentName name) {
+ // Has the component changed?
+ if (mWallpaperConnection != null) {
+ if (mWallpaperComponent == null) {
+ if (name == null) {
+ // Still using default wallpaper.
+ return;
+ }
+ } else if (mWallpaperComponent.equals(name)) {
+ // Changing to same wallpaper.
+ return;
+ }
+ }
+
+ try {
+ ComponentName realName = name;
+ if (realName == null) {
+ // 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);
+ if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
+ throw new SecurityException("Selected service does not require "
+ + android.Manifest.permission.BIND_WALLPAPER
+ + ": " + realName);
+ }
+
+ Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ if (name != null) {
+ // Make sure the selected service is actually a wallpaper service.
+ List<ResolveInfo> ris = mContext.getPackageManager()
+ .queryIntentServices(intent, 0);
+ for (int i=0; i<ris.size(); i++) {
+ ServiceInfo rsi = ris.get(i).serviceInfo;
+ if (rsi.name.equals(si.name) &&
+ rsi.packageName.equals(si.packageName)) {
+ ris = null;
+ break;
+ }
+ }
+ if (ris != null) {
+ throw new SecurityException("Selected service is not a wallpaper: "
+ + realName);
+ }
+ }
+
+ // Bind the service!
+ WallpaperConnection newConn = new WallpaperConnection();
+ intent.setComponent(realName);
+ if (!mContext.bindService(intent, newConn,
+ Context.BIND_AUTO_CREATE)) {
+ throw new IllegalArgumentException("Unable to bind service: "
+ + name);
+ }
+
+ clearWallpaperComponentLocked();
+ mWallpaperComponent = name;
+ mWallpaperConnection = newConn;
+ mLastDiedTime = SystemClock.uptimeMillis();
+ try {
+ if (DEBUG) Log.v(TAG, "Adding window token: " + newConn.mToken);
+ mIWindowManager.addWindowToken(newConn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER);
+ } catch (RemoteException e) {
+ }
+
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown component " + name);
+ }
+ }
+
+ void clearWallpaperComponentLocked() {
+ mWallpaperComponent = null;
+ if (mWallpaperConnection != null) {
+ if (mWallpaperConnection.mEngine != null) {
+ try {
+ mWallpaperConnection.mEngine.destroy();
+ } catch (RemoteException e) {
+ }
+ }
+ mContext.unbindService(mWallpaperConnection);
+ mWallpaperConnection = null;
+ }
+ }
+
+ void attachServiceLocked(WallpaperConnection conn) {
+ try {
+ conn.mService.attach(conn, conn.mToken, mWidth, mHeight);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed attaching wallpaper; clearing", e);
+ bindWallpaperComponentLocked(null);
+ }
+ }
+
+ private void notifyCallbacksLocked() {
+ final int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+ } catch (RemoteException e) {
+
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
+ }
+ }
+ mCallbacks.finishBroadcast();
+ final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ mContext.sendBroadcast(intent);
+ }
+
+ private void checkPermission(String permission) {
+ if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ private static JournaledFile makeJournaledFile() {
+ final String base = "/data/system/wallpaper_info.xml";
+ return new JournaledFile(new File(base), new File(base + ".tmp"));
+ }
+
+ private void saveSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(journal.chooseForWrite(), false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+ out.startTag(null, "wp");
+ out.attribute(null, "width", Integer.toString(mWidth));
+ out.attribute(null, "height", Integer.toString(mHeight));
+ out.attribute(null, "name", mName);
+ if (mWallpaperComponent != null) {
+ out.attribute(null, "component",
+ mWallpaperComponent.flattenToShortString());
+ }
+ out.endTag(null, "wp");
+
+ out.endDocument();
+ stream.close();
+ journal.commit();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ journal.rollback();
+ }
+ }
+
+ private void loadSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileInputStream stream = null;
+ File file = journal.chooseForRead();
+ boolean success = false;
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if ("wp".equals(tag)) {
+ mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
+ mName = parser.getAttributeValue(null, "name");
+ String comp = parser.getAttributeValue(null, "component");
+ mWallpaperComponent = comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null;
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ success = true;
+ } catch (NullPointerException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IOException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ if (!success) {
+ mWidth = -1;
+ mHeight = -1;
+ mName = "";
+ }
+ }
+
+ void settingsRestored() {
+ boolean success = false;
+ synchronized (mLock) {
+ loadSettingsLocked();
+ // If there's a wallpaper name, we use that. If that can't be loaded, then we
+ // use the default.
+ if ("".equals(mName)) {
+ success = true;
+ } else {
+ success = restoreNamedResourceLocked();
+ }
+ }
+
+ if (!success) {
+ Log.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
+ mName = "";
+ WALLPAPER_FILE.delete();
+ }
+ saveSettingsLocked();
+ }
+
+ boolean restoreNamedResourceLocked() {
+ if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
+ String resName = mName.substring(4);
+
+ String pkg = null;
+ int colon = resName.indexOf(':');
+ if (colon > 0) {
+ pkg = resName.substring(0, colon);
+ }
+
+ String ident = null;
+ int slash = resName.lastIndexOf('/');
+ if (slash > 0) {
+ ident = resName.substring(slash+1);
+ }
+
+ String type = null;
+ if (colon > 0 && slash > 0 && (slash-colon) > 1) {
+ type = resName.substring(colon+1, slash);
+ }
+
+ if (pkg != null && ident != null && type != null) {
+ int resId = -1;
+ InputStream res = null;
+ FileOutputStream fos = null;
+ try {
+ Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
+ Resources r = c.getResources();
+ resId = r.getIdentifier(resName, null, null);
+ if (resId == 0) {
+ Log.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
+ + " ident=" + ident);
+ return false;
+ }
+
+ res = r.openRawResource(resId);
+ fos = new FileOutputStream(WALLPAPER_FILE);
+
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=res.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ // mWallpaperObserver will notice the close and send the change broadcast
+
+ Log.d(TAG, "Restored wallpaper: " + resName);
+ return true;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Package name " + pkg + " not found");
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Resource not found: " + resId);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException while restoring wallpaper ", e);
+ } finally {
+ if (res != null) {
+ try {
+ res.close();
+ } catch (IOException ex) {}
+ }
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException ex) {}
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java
deleted file mode 100644
index d921baf..0000000
--- a/services/java/com/android/server/WallpaperService.java
+++ /dev/null
@@ -1,203 +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 com.android.server;
-
-import static android.os.FileObserver.*;
-import static android.os.ParcelFileDescriptor.*;
-
-import android.app.IWallpaperService;
-import android.app.IWallpaperServiceCallback;
-import android.backup.BackupManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.FileObserver;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteCallbackList;
-import android.util.Config;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-class WallpaperService extends IWallpaperService.Stub {
- private static final String TAG = WallpaperService.class.getSimpleName();
-
- private static final File WALLPAPER_DIR = new File(
- "/data/data/com.android.settings/files");
- private static final String WALLPAPER = "wallpaper";
- private static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
- private static final String PREFERENCES = "wallpaper-hints";
-
- private static final String HINT_WIDTH = "hintWidth";
- private static final String HINT_HEIGHT = "hintHeight";
-
- /**
- * List of callbacks registered they should each be notified
- * when the wallpaper is changed.
- */
- private final RemoteCallbackList<IWallpaperServiceCallback> mCallbacks
- = new RemoteCallbackList<IWallpaperServiceCallback>();
-
- /**
- * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
- * that the wallpaper has changed. The CREATE is triggered when there is no
- * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
- * everytime the wallpaper is changed.
- */
- private final FileObserver mWallpaperObserver = new FileObserver(
- WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE) {
- @Override
- public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
-
- File changedFile = new File(WALLPAPER_DIR, path);
- if (WALLPAPER_FILE.equals(changedFile)) {
- notifyCallbacks();
- }
- }
- };
-
- private final Context mContext;
-
- private int mWidth = -1;
- private int mHeight = -1;
-
- public WallpaperService(Context context) {
- if (Config.LOGD) Log.d(TAG, "WallpaperService startup");
- mContext = context;
- createFilesDir();
- mWallpaperObserver.startWatching();
-
- SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES,
- Context.MODE_PRIVATE);
- mWidth = preferences.getInt(HINT_WIDTH, -1);
- mHeight = preferences.getInt(HINT_HEIGHT, -1);
- }
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- mWallpaperObserver.stopWatching();
- }
-
- public void clearWallpaper() {
- File f = WALLPAPER_FILE;
- if (f.exists()) {
- f.delete();
- }
- }
-
- public void setDimensionHints(int width, int height) throws RemoteException {
- checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
-
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException("width and height must be > 0");
- }
-
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
-
- SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES,
- Context.MODE_PRIVATE);
-
- final SharedPreferences.Editor editor = preferences.edit();
- editor.putInt(HINT_WIDTH, width);
- editor.putInt(HINT_HEIGHT, height);
- editor.commit();
- }
- }
-
- public int getWidthHint() throws RemoteException {
- return mWidth;
- }
-
- public int getHeightHint() throws RemoteException {
- return mHeight;
- }
-
- public ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb) {
- try {
- mCallbacks.register(cb);
- File f = WALLPAPER_FILE;
- if (!f.exists()) {
- return null;
- }
- return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
- } catch (FileNotFoundException e) {
-
- /* Shouldn't happen as we check to see if the file exists */
- if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e);
- }
- return null;
- }
-
- public ParcelFileDescriptor setWallpaper() {
- checkPermission(android.Manifest.permission.SET_WALLPAPER);
- try {
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
- MODE_CREATE|MODE_READ_WRITE);
-
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
-
- return fd;
- } catch (FileNotFoundException e) {
- if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
- }
- return null;
- }
-
- private void createFilesDir() {
- if (!WALLPAPER_DIR.exists()) {
- WALLPAPER_DIR.mkdirs();
- }
- }
-
- private void notifyCallbacks() {
- final int n = mCallbacks.beginBroadcast();
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onWallpaperChanged();
- } catch (RemoteException e) {
-
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
- }
- }
- mCallbacks.finishBroadcast();
- final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
- mContext.sendBroadcast(intent);
- }
-
- private void checkPermission(String permission) {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
- throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
- + ", must have permission " + permission);
- }
- }
-}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 394ed3a..2dc747e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -41,6 +41,7 @@
import android.net.wifi.SupplicantState;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
+import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -92,6 +93,9 @@
private boolean mDeviceIdle;
private int mPluggedType;
+ // true if the user enabled Wifi while in airplane mode
+ private boolean mAirplaneModeOverwridden;
+
private final LockList mLocks = new LockList();
// some wifi lock statistics
private int mFullLocksAcquired;
@@ -142,28 +146,6 @@
private final WifiHandler mWifiHandler;
/*
- * Map used to keep track of hidden networks presence, which
- * is needed to switch between active and passive scan modes.
- * If there is at least one hidden network that is currently
- * present (enabled), we want to do active scans instead of
- * passive.
- */
- private final Map<Integer, Boolean> mIsHiddenNetworkPresent;
- /*
- * The number of currently present hidden networks. When this
- * counter goes from 0 to 1 or from 1 to 0, we change the
- * scan mode to active or passive respectively. Initially, we
- * set the counter to 0 and we increment it every time we add
- * a new present (enabled) hidden network.
- */
- private int mNumHiddenNetworkPresent;
- /*
- * Whether we change the scan mode is due to a hidden network
- * (in this class, this is always the case)
- */
- private final static boolean SET_DUE_TO_A_HIDDEN_NETWORK = true;
-
- /*
* Cache of scan results objects (size is somewhat arbitrary)
*/
private static final int SCAN_RESULT_CACHE_SIZE = 80;
@@ -195,12 +177,6 @@
mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
- /*
- * Initialize the hidden-networks state
- */
- mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>();
- mNumHiddenNetworkPresent = 0;
-
mScanResultCache = new LinkedHashMap<String, ScanResult>(
SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
/*
@@ -246,6 +222,8 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // clear our flag indicating the user has overwridden airplane mode
+ mAirplaneModeOverwridden = false;
updateWifiState();
}
},
@@ -254,155 +232,6 @@
setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
}
- /**
- * Initializes the hidden networks state. Must be called when we
- * enable Wi-Fi.
- */
- private synchronized void initializeHiddenNetworksState() {
- // First, reset the state
- resetHiddenNetworksState();
-
- // ... then add networks that are marked as hidden
- List<WifiConfiguration> networks = getConfiguredNetworks();
- if (!networks.isEmpty()) {
- for (WifiConfiguration config : networks) {
- if (config != null && config.hiddenSSID) {
- addOrUpdateHiddenNetwork(
- config.networkId,
- config.status != WifiConfiguration.Status.DISABLED);
- }
- }
-
- }
- }
-
- /**
- * Resets the hidden networks state.
- */
- private synchronized void resetHiddenNetworksState() {
- mNumHiddenNetworkPresent = 0;
- mIsHiddenNetworkPresent.clear();
- }
-
- /**
- * Marks all but netId network as not present.
- */
- private synchronized void markAllHiddenNetworksButOneAsNotPresent(int netId) {
- for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) {
- if (entry != null) {
- Integer networkId = entry.getKey();
- if (networkId != netId) {
- updateNetworkIfHidden(
- networkId, false);
- }
- }
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network.
- */
- private synchronized void updateNetworkIfHidden(int netId, boolean present) {
- if (isHiddenNetwork(netId)) {
- addOrUpdateHiddenNetwork(netId, present);
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network. If the network does not exist, adds the network.
- */
- private synchronized void addOrUpdateHiddenNetwork(int netId, boolean present) {
- if (0 <= netId) {
-
- // If we are adding a new entry or modifying an existing one
- Boolean isPresent = mIsHiddenNetworkPresent.get(netId);
- if (isPresent == null || isPresent != present) {
- if (present) {
- incrementHiddentNetworkPresentCounter();
- } else {
- // If we add a new hidden network, no need to change
- // the counter (it must be 0)
- if (isPresent != null) {
- decrementHiddentNetworkPresentCounter();
- }
- }
- mIsHiddenNetworkPresent.put(netId, present);
- }
- } else {
- Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Removes the netId network if it is hidden (being kept track of).
- */
- private synchronized void removeNetworkIfHidden(int netId) {
- if (isHiddenNetwork(netId)) {
- removeHiddenNetwork(netId);
- }
- }
-
- /**
- * Removes the netId network. For the call to be successful, the network
- * must be hidden.
- */
- private synchronized void removeHiddenNetwork(int netId) {
- if (0 <= netId) {
- Boolean isPresent =
- mIsHiddenNetworkPresent.remove(netId);
- if (isPresent != null) {
- // If we remove an existing hidden network that is not
- // present, no need to change the counter
- if (isPresent) {
- decrementHiddentNetworkPresentCounter();
- }
- } else {
- if (DBG) {
- Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!");
- }
- }
- } else {
- Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Returns true if netId is an existing hidden network.
- */
- private synchronized boolean isHiddenNetwork(int netId) {
- return mIsHiddenNetworkPresent.containsKey(netId);
- }
-
- /**
- * Increments the present (enabled) hidden networks counter. If the
- * counter value goes from 0 to 1, changes the scan mode to active.
- */
- private void incrementHiddentNetworkPresentCounter() {
- ++mNumHiddenNetworkPresent;
- if (1 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "active"
- mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- }
-
- /**
- * Decrements the present (enabled) hidden networks counter. If the
- * counter goes from 1 to 0, changes the scan mode back to passive.
- */
- private void decrementHiddentNetworkPresentCounter() {
- if (0 < mNumHiddenNetworkPresent) {
- --mNumHiddenNetworkPresent;
- if (0 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "passive"
- mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- } else {
- Log.e(TAG, "Hidden-network counter invariant violation!");
- }
- }
-
private boolean getPersistedWifiEnabled() {
final ContentResolver cr = mContext.getContentResolver();
try {
@@ -468,6 +297,8 @@
synchronized (mWifiHandler) {
sWakeLock.acquire();
mLastEnableUid = Binder.getCallingUid();
+ // set a flag if the user is enabling Wifi while in airplane mode
+ mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
sendEnableMessage(enable, true, Binder.getCallingUid());
}
@@ -488,7 +319,7 @@
if (mWifiState == eventualWifiState) {
return true;
}
- if (enable && isAirplaneModeOn()) {
+ if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
return false;
}
@@ -522,7 +353,7 @@
}
// We must reset the interface before we unload the driver
- mWifiStateTracker.resetInterface();
+ mWifiStateTracker.resetInterface(false);
if (!WifiNative.unloadDriver()) {
Log.e(TAG, "Failed to unload Wi-Fi driver.");
@@ -544,12 +375,10 @@
setWifiEnabledState(eventualWifiState, uid);
/*
- * Initialize the hidden networks state and the number of allowed
- * radio channels if Wi-Fi is being turned on.
+ * Initialize the number of allowed radio channels if Wi-Fi is being turned on.
*/
if (enable) {
mWifiStateTracker.setNumAllowedChannels();
- initializeHiddenNetworksState();
}
return true;
@@ -884,15 +713,6 @@
}
mNeedReconfig = mNeedReconfig || doReconfig;
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- if (config.hiddenSSID) {
- // Mark the network as present unless it is disabled
- addOrUpdateHiddenNetwork(
- netId, config.status != WifiConfiguration.Status.DISABLED);
- }
-
setVariables: {
/*
* Note that if a networkId for a non-existent network
@@ -1231,11 +1051,6 @@
public boolean removeNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- removeNetworkIfHidden(netId);
-
return mWifiStateTracker.removeNetwork(netId);
}
@@ -1249,18 +1064,14 @@
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- synchronized(this) {
- if (disableOthers) {
- markAllHiddenNetworksButOneAsNotPresent(netId);
- }
- updateNetworkIfHidden(netId, true);
- }
-
synchronized (mWifiStateTracker) {
- return WifiNative.enableNetworkCommand(netId, disableOthers);
+ String ifname = mWifiStateTracker.getInterfaceName();
+ NetworkUtils.enableInterface(ifname);
+ boolean result = WifiNative.enableNetworkCommand(netId, disableOthers);
+ if (!result) {
+ NetworkUtils.disableInterface(ifname);
+ }
+ return result;
}
}
@@ -1273,11 +1084,6 @@
public boolean disableNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- updateNetworkIfHidden(netId, false);
-
synchronized (mWifiStateTracker) {
return WifiNative.disableNetworkCommand(netId);
}
@@ -1375,45 +1181,49 @@
level = 0;
}
- // bssid is the hash key
- scanResult = mScanResultCache.get(bssid);
+ /*
+ * The formatting of the results returned by
+ * wpa_supplicant is intended to make the fields
+ * line up nicely when printed,
+ * not to make them easy to parse. So we have to
+ * apply some heuristics to figure out which field
+ * is the SSID and which field is the flags.
+ */
+ String ssid;
+ String flags;
+ if (result.length == 4) {
+ if (result[3].charAt(0) == '[') {
+ flags = result[3];
+ ssid = "";
+ } else {
+ flags = "";
+ ssid = result[3];
+ }
+ } else if (result.length == 5) {
+ flags = result[3];
+ ssid = result[4];
+ } else {
+ // Here, we must have 3 fields: no flags and ssid
+ // set
+ flags = "";
+ ssid = "";
+ }
+
+ // bssid + ssid is the hash key
+ String key = bssid + ssid;
+ scanResult = mScanResultCache.get(key);
if (scanResult != null) {
scanResult.level = level;
+ scanResult.SSID = ssid;
+ scanResult.capabilities = flags;
+ scanResult.frequency = frequency;
} else {
- /*
- * The formatting of the results returned by
- * wpa_supplicant is intended to make the fields
- * line up nicely when printed,
- * not to make them easy to parse. So we have to
- * apply some heuristics to figure out which field
- * is the SSID and which field is the flags.
- */
- String ssid;
- String flags;
- if (result.length == 4) {
- if (result[3].charAt(0) == '[') {
- flags = result[3];
- ssid = "";
- } else {
- flags = "";
- ssid = result[3];
- }
- } else if (result.length == 5) {
- flags = result[3];
- ssid = result[4];
- } else {
- // Here, we must have 3 fields: no flags and ssid
- // set
- flags = "";
- ssid = "";
- }
-
// Do not add scan results that have no SSID set
if (0 < ssid.trim().length()) {
scanResult =
new ScanResult(
ssid, bssid, flags, level, frequency);
- mScanResultCache.put(bssid, scanResult);
+ mScanResultCache.put(key, scanResult);
}
}
} else {
@@ -1479,14 +1289,17 @@
* Set the number of radio frequency channels that are allowed to be used
* in the current regulatory domain. This method should be used only
* if the correct number of channels cannot be determined automatically
- * for some reason. If the operation is successful, the new value is
+ * for some reason. If the operation is successful, the new value may be
* persisted as a Secure setting.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
+ * @param persist {@code true} if the setting should be remembered.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is outside the valid range.
*/
- public boolean setNumAllowedChannels(int numChannels) {
+ public boolean setNumAllowedChannels(int numChannels, boolean persist) {
+ Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
+ " with persist set to "+persist);
enforceChangePermission();
/*
* Validate the argument. We'd like to let the Wi-Fi driver do this,
@@ -1505,9 +1318,11 @@
return false;
}
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
- numChannels);
+ if (persist) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ numChannels);
+ }
mWifiStateTracker.setNumAllowedChannels(numChannels);
return true;
}
@@ -1688,7 +1503,7 @@
private void updateWifiState() {
boolean wifiEnabled = getPersistedWifiEnabled();
- boolean airplaneMode = isAirplaneModeOn();
+ boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
boolean lockHeld = mLocks.hasLocks();
int strongestLockMode;
boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
@@ -1752,6 +1567,13 @@
|| airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
}
+ private boolean isAirplaneToggleable() {
+ String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+ return toggleableRadios != null
+ && toggleableRadios.contains(Settings.System.RADIO_WIFI);
+ }
+
/**
* Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
* currently on.
@@ -2068,7 +1890,9 @@
// our new size == 1 (first call), but this function won't
// be called often and by making the stopPacket call each
// time we're less fragile and self-healing.
- WifiNative.stopPacketFiltering();
+ synchronized (mWifiStateTracker) {
+ WifiNative.stopPacketFiltering();
+ }
}
int uid = Binder.getCallingUid();
@@ -2104,7 +1928,9 @@
removed.unlinkDeathRecipient();
}
if (mMulticasters.size() == 0) {
- WifiNative.startPacketFiltering();
+ synchronized (mWifiStateTracker) {
+ WifiNative.startPacketFiltering();
+ }
}
Long ident = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d4c27b7..988c3d5 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -31,15 +31,15 @@
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
-import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
@@ -66,6 +66,7 @@
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.LatencyTimer;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
@@ -124,7 +125,8 @@
import java.util.List;
/** {@hide} */
-public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
+public class WindowManagerService extends IWindowManager.Stub
+ implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
@@ -137,7 +139,10 @@
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;
static final boolean PROFILE_ORIENTATION = false;
static final boolean BLUR = true;
@@ -395,6 +400,13 @@
WindowState mInputMethodWindow = null;
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
+ final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+
+ // If non-null, this is the currently visible window that is associated
+ // with the wallpaper.
+ WindowState mWallpaperTarget = null;
+ int mWallpaperAnimLayerAdjustment;
+
AppWindowToken mFocusedApp = null;
PowerManagerService mPowerManager;
@@ -512,6 +524,10 @@
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
mContext = context;
mHaveInputMethods = haveInputMethods;
mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -1159,6 +1175,247 @@
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
}
+ boolean adjustWallpaperWindowsLocked() {
+ boolean changed = false;
+
+ // 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;
+ 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()
+ && !w.mDrawPending && !w.mCommitDrawPending) {
+ visible = true;
+ break;
+ }
+ }
+
+ if (!visible) w = null;
+ if (DEBUG_WALLPAPER && mWallpaperTarget != w) {
+ Log.v(TAG, "New wallpaper target: " + w);
+ }
+ mWallpaperTarget = w;
+
+ if (visible) {
+ // The window is visible to the compositor... but is it visible
+ // to the user? That is what the wallpaper cares about.
+ visible = !w.mObscured;
+
+ // If the wallpaper target is animating, we may need to copy
+ // its layer adjustment.
+ mWallpaperAnimLayerAdjustment = w.mAppToken != null
+ ? w.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 &&
+ (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
+ wb.mToken != w.mToken)) {
+ // This window is not related to the previous one in any
+ // interesting way, so stop here.
+ break;
+ }
+ w = wb;
+ i--;
+ }
+ }
+
+ // 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();
+
+ // Start stepping backwards from here, ensuring that our wallpaper windows
+ // are correctly placed.
+ 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);
+ }
+
+ // First, make sure the client has the current visibility
+ // state.
+ 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) {
+ }
+ }
+
+ wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+ 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;
+ continue;
+ }
+
+ // The window didn't match... the current wallpaper window,
+ // wherever it is, is in the wrong place, so make sure it is
+ // not in the list.
+ int oldIndex = localmWindows.indexOf(wallpaper);
+ if (oldIndex >= 0) {
+ localmWindows.remove(oldIndex);
+ if (oldIndex < i) {
+ i--;
+ }
+ }
+
+ // Now stick it in.
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+ + " from " + oldIndex + " to " + i);
+
+ localmWindows.add(i, wallpaper);
+ changed = true;
+ }
+ }
+
+ return changed;
+ }
+
+ void setWallpaperAnimLayerAdjustmentLocked(int adj) {
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting wallpaper layer adj to " + adj);
+ mWallpaperAnimLayerAdjustment = adj;
+ 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);
+ wallpaper.mAnimLayer = wallpaper.mLayer + adj;
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
+ }
+ }
+ }
+
+ 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 (rawChanged) {
+ try {
+ wallpaperWin.mClient.dispatchWallpaperOffsets(
+ wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
+ } catch (RemoteException e) {
+ }
+ }
+
+ return changed;
+ }
+
+ boolean updateWallpaperOffsetLocked() {
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
+ boolean changed = false;
+
+ WindowState target = mWallpaperTarget;
+ if (target != null) {
+ 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 (updateWallpaperOffsetLocked(target, wallpaper, dw, dh)) {
+ wallpaper.computeShownFrameLocked();
+ changed = true;
+ }
+ }
+ }
+ }
+
+ return changed;
+ }
+
+ 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) {
@@ -1216,6 +1473,11 @@
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ if (attrs.type == TYPE_WALLPAPER) {
+ Log.w(TAG, "Attempted to add wallpaper window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
token = new WindowToken(attrs.token, -1, false);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
@@ -1242,6 +1504,12 @@
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ } else if (attrs.type == TYPE_WALLPAPER) {
+ if (token.windowType != TYPE_WALLPAPER) {
+ Log.w(TAG, "Attempted to add wallpaper window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
}
win = new WindowState(session, client, token,
@@ -1292,6 +1560,10 @@
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
+ if (attrs.type == TYPE_WALLPAPER ||
+ (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
}
win.mEnterAnimationPending = true;
@@ -1432,6 +1704,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);
@@ -1453,6 +1727,11 @@
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);
@@ -1552,6 +1831,19 @@
}
}
+ public void setWindowWallpaperPositionLocked(WindowState window, float x, float y) {
+ if (window.mWallpaperX != x || window.mWallpaperY != y) {
+ window.mWallpaperX = x;
+ window.mWallpaperY = y;
+
+ if (mWallpaperTarget == window) {
+ if (updateWallpaperOffsetLocked()) {
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ }
+ }
+
public int relayoutWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, boolean insetsPending,
@@ -1610,6 +1902,9 @@
|| ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
+ boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
+ && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
+
win.mRelayoutCalled = true;
final int oldVisibility = win.mViewVisibility;
win.mViewVisibility = viewVisibility;
@@ -1707,6 +2002,11 @@
assignLayers = true;
}
}
+ if (wallpaperMayMove) {
+ if (adjustWallpaperWindowsLocked()) {
+ assignLayers = true;
+ }
+ }
mLayoutNeeded = true;
win.mGivenInsetsPending = insetsPending;
@@ -1750,6 +2050,9 @@
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client);
if (win != null && win.finishDrawingLocked()) {
+ if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -2002,6 +2305,9 @@
wtoken = new WindowToken(token, type, true);
mTokenMap.put(token, wtoken);
mTokenList.add(wtoken);
+ if (type == TYPE_WALLPAPER) {
+ mWallpaperTokens.add(wtoken);
+ }
}
}
@@ -2047,6 +2353,8 @@
if (delayed) {
mExitingTokens.add(wtoken);
+ } else if (wtoken.windowType == TYPE_WALLPAPER) {
+ mWallpaperTokens.remove(wtoken);
}
}
@@ -3833,7 +4141,7 @@
private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
long curTime = SystemClock.uptimeMillis();
- if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
+ if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
if (mLastTouchEventType == eventType &&
(curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
return;
@@ -3893,8 +4201,16 @@
if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
"dispatchPointer " + ev);
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
+ }
+
Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
ev, true, false, pid, uid);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
+ }
int action = ev.getAction();
@@ -3932,7 +4248,8 @@
WindowState target = (WindowState)targetObj;
final long eventTime = ev.getEventTime();
-
+ final long eventTimeNano = ev.getEventTimeNano();
+
//Log.i(TAG, "Sending " + ev + " to " + target);
if (uid != 0 && uid != target.mSession.mUid) {
@@ -3949,6 +4266,10 @@
return INJECT_NO_PERMISSION;
}
}
+
+ if (MEASURE_LATENCY) {
+ lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
if ((target.mAttrs.flags &
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
@@ -4032,6 +4353,10 @@
}
}
+ if (MEASURE_LATENCY) {
+ lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
+
synchronized(mWindowMap) {
if (qev != null && action == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(target,
@@ -4047,7 +4372,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);
}
@@ -4060,6 +4385,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);
+ }
}
}
@@ -4069,7 +4400,16 @@
if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
Log.v(TAG, "Delivering pointer " + qev + " to " + target);
}
- target.mClient.dispatchPointer(ev, eventTime);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
+
+ target.mClient.dispatchPointer(ev, eventTime, true);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
@@ -4141,7 +4481,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);
@@ -4664,7 +5004,8 @@
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
mPolicy.interceptKeyTi(null, keycode,
- nextKey.getMetaState(), down, repeatCount);
+ nextKey.getMetaState(), down, repeatCount,
+ nextKey.getFlags());
}
Log.w(TAG, "Event timeout during app switch: dropping "
+ nextKey);
@@ -4687,7 +5028,8 @@
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
if (mPolicy.interceptKeyTi(focus,
- keycode, nextKey.getMetaState(), down, repeatCount)) {
+ keycode, nextKey.getMetaState(), down, repeatCount,
+ nextKey.getFlags())) {
return CONSUMED_EVENT_TOKEN;
}
}
@@ -4914,14 +5256,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;
@@ -4951,17 +5295,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() {
@@ -5107,7 +5459,7 @@
PowerManager.WakeLock mHoldingScreen;
KeyQ() {
- super(mContext);
+ super(mContext, WindowManagerService.this);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"KEEP_SCREEN_ON_FLAG");
@@ -5238,7 +5590,7 @@
}
}
}
- };
+ }
public boolean detectSafeMode() {
mSafeMode = mPolicy.detectSafeMode();
@@ -5303,9 +5655,13 @@
if (DEBUG_INPUT && ev != null) Log.v(
TAG, "Event: type=" + ev.classType + " data=" + ev.event);
+ if (MEASURE_LATENCY) {
+ lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
+ }
+
try {
if (ev != null) {
- curTime = ev.when;
+ curTime = SystemClock.uptimeMillis();
int eventType;
if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
eventType = eventType((MotionEvent)ev.event);
@@ -5316,17 +5672,29 @@
eventType = LocalPowerManager.OTHER_EVENT;
}
try {
- long now = SystemClock.uptimeMillis();
-
- if ((now - mLastBatteryStatsCallTime)
+ if ((curTime - mLastBatteryStatsCallTime)
>= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastBatteryStatsCallTime = now;
+ mLastBatteryStatsCallTime = curTime;
mBatteryStats.noteInputEvent();
}
} catch (RemoteException e) {
// Ignore
}
- mPowerManager.userActivity(curTime, false, eventType, false);
+
+ if (eventType != TOUCH_EVENT
+ && eventType != LONG_TOUCH_EVENT
+ && eventType != CHEEK_EVENT) {
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ } else if (mLastTouchEventType != eventType
+ || (curTime - mLastUserActivityCallTime)
+ >= MIN_TIME_BETWEEN_USERACTIVITIES) {
+ mLastUserActivityCallTime = curTime;
+ mLastTouchEventType = eventType;
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ }
+
switch (ev.classType) {
case RawInputEvent.CLASS_KEYBOARD:
KeyEvent ke = (KeyEvent)ev.event;
@@ -5592,6 +5960,18 @@
}
}
+ public void setWallpaperPosition(IBinder window, float x, float y) {
+ synchronized(mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+ x, y);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -5667,6 +6047,8 @@
final int mSubLayer;
final boolean mLayoutAttached;
final boolean mIsImWindow;
+ final boolean mIsWallpaper;
+ final boolean mIsFloatingLayer;
int mViewVisibility;
boolean mPolicyVisibility = true;
boolean mPolicyVisibilityAfterAnim = true;
@@ -5674,16 +6056,16 @@
Surface mSurface;
boolean mAttachedHidden; // is our parent window hidden?
boolean mLastHidden; // was this window last hidden?
+ boolean mWallpaperVisible; // for wallpaper, what was last vis report?
int mRequestedWidth;
int mRequestedHeight;
int mLastRequestedWidth;
int mLastRequestedHeight;
- int mReqXPos;
- int mReqYPos;
int mLayer;
int mAnimLayer;
int mLastLayer;
boolean mHaveFrame;
+ boolean mObscured;
WindowState mNextOutsideTouch;
@@ -5764,6 +6146,15 @@
boolean mHasLocalTransformation;
final Transformation mTransformation = new Transformation();
+ // If a window showing a wallpaper: the requested offset for the
+ // wallpaper; if a wallpaper window: the currently applied offset.
+ float mWallpaperX = -1;
+ float mWallpaperY = -1;
+
+ // Wallpaper windows: pixels offset based on above variables.
+ int mXOffset;
+ int mYOffset;
+
// This is set after IWindowSession.relayout() has been called at
// least once for the window. It allows us to detect the situation
// where we don't yet have a surface, but should have one soon, so
@@ -5824,6 +6215,8 @@
mAttachedWindow = null;
mLayoutAttached = false;
mIsImWindow = false;
+ mIsWallpaper = false;
+ mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
return;
@@ -5844,6 +6237,8 @@
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
|| attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+ mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
+ mIsFloatingLayer = mIsImWindow || mIsWallpaper;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
@@ -5855,6 +6250,8 @@
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+ mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
+ mIsFloatingLayer = mIsImWindow || mIsWallpaper;
}
WindowState appWin = this;
@@ -5877,8 +6274,8 @@
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
- mReqXPos = 0;
- mReqYPos = 0;
+ mXOffset = 0;
+ mYOffset = 0;
mLayer = 0;
mAnimLayer = 0;
mLastLayer = 0;
@@ -6059,11 +6456,7 @@
}
int flags = 0;
- if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
- flags |= Surface.HARDWARE;
- } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
- flags |= Surface.GPU;
- } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
+ if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
flags |= Surface.PUSH_BUFFERS;
}
@@ -6344,6 +6737,8 @@
mAnimLayer = mLayer;
if (mIsImWindow) {
mAnimLayer += mInputMethodAnimLayerAdjustment;
+ } else if (mIsWallpaper) {
+ mAnimLayer += mWallpaperAnimLayerAdjustment;
}
if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
+ " anim layer: " + mAnimLayer);
@@ -6430,6 +6825,25 @@
Transformation appTransformation =
(mAppToken != null && mAppToken.hasTransformation)
? mAppToken.transformation : null;
+
+ // Wallpapers are animated based on the "real" window they
+ // are currently targeting.
+ if (mAttrs.type == TYPE_WALLPAPER && mWallpaperTarget != null) {
+ if (mWallpaperTarget.mHasLocalTransformation) {
+ attachedTransformation = mWallpaperTarget.mTransformation;
+ }
+ if (mWallpaperTarget.mAppToken != null &&
+ 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
|| appTransformation != null) {
// cache often used attributes locally
@@ -6460,8 +6874,8 @@
mDtDx = tmpFloats[Matrix.MSKEW_X];
mDsDy = tmpFloats[Matrix.MSKEW_Y];
mDtDy = tmpFloats[Matrix.MSCALE_Y];
- int x = (int)tmpFloats[Matrix.MTRANS_X];
- int y = (int)tmpFloats[Matrix.MTRANS_Y];
+ int x = (int)tmpFloats[Matrix.MTRANS_X] + mXOffset;
+ int y = (int)tmpFloats[Matrix.MTRANS_Y] + mYOffset;
int w = frame.width();
int h = frame.height();
mShownFrame.set(x, y, x+w, y+h);
@@ -6498,6 +6912,9 @@
}
mShownFrame.set(mFrame);
+ if (mXOffset != 0 || mYOffset != 0) {
+ mShownFrame.offset(mXOffset, mYOffset);
+ }
mShownAlpha = mAlpha;
mDsDx = 1;
mDtDx = 0;
@@ -6561,10 +6978,10 @@
if (atoken != null) {
return mSurface != null && mPolicyVisibility && !mDestroying
&& ((!mAttachedHidden && !atoken.hiddenRequested)
- || mAnimating || atoken.animating);
+ || mAnimation != null || atoken.animation != null);
} else {
return mSurface != null && mPolicyVisibility && !mDestroying
- && (!mAttachedHidden || mAnimating);
+ && (!mAttachedHidden || mAnimation != null);
}
}
@@ -6574,10 +6991,12 @@
*/
boolean isReadyForDisplay() {
final AppWindowToken atoken = mAppToken;
- final boolean animating = atoken != null ? atoken.animating : false;
+ final boolean animating = atoken != null
+ ? (atoken.animation != null) : false;
return mSurface != null && mPolicyVisibility && !mDestroying
- && ((!mAttachedHidden && !mRootToken.hidden)
- || mAnimating || animating);
+ && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
+ && !mRootToken.hidden)
+ || mAnimation != null || animating);
}
/** Is the window or its container currently animating? */
@@ -6659,7 +7078,7 @@
boolean isFullscreen(int screenWidth, int screenHeight) {
return mFrame.left <= 0 && mFrame.top <= 0 &&
- mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
+ mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
}
void removeLocked() {
@@ -6749,8 +7168,11 @@
pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
}
- if (mIsImWindow) {
- pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
+ if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
+ pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow);
+ pw.print(" mIsWallpaper="); pw.print(mIsWallpaper);
+ pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer);
+ pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible);
}
pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
pw.print(" mSubLayer="); pw.print(mSubLayer);
@@ -6773,7 +7195,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);
@@ -6782,9 +7205,11 @@
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
- pw.print(" h="); pw.print(mRequestedHeight);
- pw.print(" x="); pw.print(mReqXPos);
- pw.print(" y="); pw.println(mReqYPos);
+ pw.print(" h="); pw.println(mRequestedHeight);
+ if (mXOffset != 0 || mYOffset != 0) {
+ pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
+ pw.print(" y="); pw.println(mYOffset);
+ }
pw.print(prefix); pw.print("mGivenContentInsets=");
mGivenContentInsets.printShortString(pw);
pw.print(" mGivenVisibleInsets=");
@@ -6852,6 +7277,10 @@
pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
pw.print(" mVScale="); pw.println(mVScale);
}
+ if (mWallpaperX != -1 || mWallpaperY != -1) {
+ pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX);
+ pw.print(" mWallpaperY="); pw.println(mWallpaperY);
+ }
}
@Override
@@ -7036,6 +7465,9 @@
if (w == mInputMethodTarget) {
setInputMethodAnimLayerAdjustment(adj);
}
+ if (w == mWallpaperTarget) {
+ setWallpaperAnimLayerAdjustmentLocked(adj);
+ }
}
}
@@ -7786,7 +8218,8 @@
for (i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
+ if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
+ || (i > 0 && w.mIsWallpaper)) {
curLayer += WINDOW_LAYER_MULTIPLIER;
w.mLayer = curLayer;
} else {
@@ -7802,6 +8235,8 @@
}
if (w.mIsImWindow) {
w.mAnimLayer += mInputMethodAnimLayerAdjustment;
+ } else if (w.mIsWallpaper) {
+ w.mAnimLayer += mWallpaperAnimLayerAdjustment;
}
if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
+ w.mAnimLayer);
@@ -8190,6 +8625,7 @@
// 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();
}
@@ -8465,7 +8901,7 @@
}
// Update effect.
- if (!obscured) {
+ if (!(w.mObscured=obscured)) {
if (w.mSurface != null) {
if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
holdScreen = w.mSession;
@@ -8482,7 +8918,8 @@
}
boolean opaqueDrawn = w.isOpaqueDrawn();
- if (opaqueDrawn && w.isFullscreen(dw, dh)) {
+ if ((opaqueDrawn && w.isFullscreen(dw, dh))
+ || attrs.type == TYPE_WALLPAPER) {
// This window completely covers everything behind it,
// so we want to leave all of them as unblurred (for
// performance reasons).
@@ -8630,6 +9067,7 @@
}
// Destroy the surface of any windows that are no longer visible.
+ boolean wallpaperDestroyed = false;
i = mDestroySurface.size();
if (i > 0) {
do {
@@ -8639,6 +9077,9 @@
if (mInputMethodWindow == win) {
mInputMethodWindow = null;
}
+ if (win == mWallpaperTarget) {
+ wallpaperDestroyed = true;
+ }
win.destroySurfaceLocked();
} while (i > 0);
mDestroySurface.clear();
@@ -8649,6 +9090,9 @@
WindowToken token = mExitingTokens.get(i);
if (!token.hasVisible) {
mExitingTokens.remove(i);
+ if (token.windowType == TYPE_WALLPAPER) {
+ mWallpaperTokens.remove(token);
+ }
}
}
@@ -8664,7 +9108,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);
@@ -9071,6 +9520,16 @@
pw.println(mTokenList.get(i));
}
}
+ if (mWallpaperTokens.size() > 0) {
+ pw.println(" ");
+ pw.println(" Wallpaper tokens:");
+ for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
+ WindowToken token = mWallpaperTokens.get(i);
+ pw.print(" Wallpaper #"); pw.print(i);
+ pw.print(' '); pw.print(token); pw.println(':');
+ token.dump(pw, " ");
+ }
+ }
if (mAppTokens.size() > 0) {
pw.println(" ");
pw.println(" Application tokens in Z order:");
@@ -9115,6 +9574,7 @@
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
+ pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -9126,7 +9586,9 @@
pw.print( " no DimAnimator ");
}
pw.print(" mInputMethodAnimLayerAdjustment=");
- pw.println(mInputMethodAnimLayerAdjustment);
+ pw.print(mInputMethodAnimLayerAdjustment);
+ pw.print(" mWallpaperAnimLayerAdjustment=");
+ pw.println(mWallpaperAnimLayerAdjustment);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
@@ -9166,6 +9628,10 @@
synchronized (mKeyWaiter) { }
}
+ public void virtualKeyFeedback(KeyEvent event) {
+ mPolicy.keyFeedbackFromInput(event);
+ }
+
/**
* DimAnimator class that controls the dim animation. This holds the surface and
* all state used for dim animation.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 04bfae6..c59c9cc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -318,6 +318,12 @@
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
+ // System property defining error report receiver for system apps
+ static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
+
+ // System property defining default error report receiver
+ static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
+
// Corresponding memory levels for above adjustments.
final int EMPTY_APP_MEM;
final int HIDDEN_APP_MEM;
@@ -8198,27 +8204,62 @@
private ComponentName getErrorReportReceiver(ProcessRecord app) {
IPackageManager pm = ActivityThread.getPackageManager();
+
try {
- // was an installer package name specified when this app was
- // installed?
- String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
- if (installerPackageName == null) {
- return null;
+ // look for receiver in the installer package
+ String candidate = pm.getInstallerPackageName(app.info.packageName);
+ ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
}
- // is there an Activity in this package that handles ACTION_APP_ERROR?
- Intent intent = new Intent(Intent.ACTION_APP_ERROR);
- intent.setPackage(installerPackageName);
- ResolveInfo info = pm.resolveIntent(intent, null, 0);
- if (info == null || info.activityInfo == null) {
- return null;
+ // if the error app is on the system image, look for system apps
+ // error receiver
+ if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
+ result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
+ }
}
- return new ComponentName(installerPackageName, info.activityInfo.name);
+ // if there is a default receiver, try that
+ candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
+ return getErrorReportReceiver(pm, app.info.packageName, candidate);
} catch (RemoteException e) {
- // will return null and no error report will be delivered
+ // should not happen
+ Log.e(TAG, "error talking to PackageManager", e);
+ return null;
}
- return null;
+ }
+
+ /**
+ * Return activity in receiverPackage that handles ACTION_APP_ERROR.
+ *
+ * @param pm PackageManager isntance
+ * @param errorPackage package which caused the error
+ * @param receiverPackage candidate package to receive the error
+ * @return activity component within receiverPackage which handles
+ * ACTION_APP_ERROR, or null if not found
+ */
+ private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
+ String receiverPackage) throws RemoteException {
+ if (receiverPackage == null || receiverPackage.length() == 0) {
+ return null;
+ }
+
+ // break the loop if it's the error report receiver package that crashed
+ if (receiverPackage.equals(errorPackage)) {
+ return null;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ intent.setPackage(receiverPackage);
+ ResolveInfo info = pm.resolveIntent(intent, null, 0);
+ if (info == null || info.activityInfo == null) {
+ return null;
+ }
+ return new ComponentName(receiverPackage, info.activityInfo.name);
}
void makeAppNotRespondingLocked(ProcessRecord app,
@@ -8540,6 +8581,7 @@
report.crashInfo.throwFileName = trace.getFileName();
report.crashInfo.throwClassName = trace.getClassName();
report.crashInfo.throwMethodName = trace.getMethodName();
+ report.crashInfo.throwLineNumber = trace.getLineNumber();
} else if (r.notResponding) {
report.type = ApplicationErrorReport.TYPE_ANR;
report.anrInfo = new ApplicationErrorReport.AnrInfo();
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
old mode 100755
new mode 100644
index d458911..66868a3
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -695,7 +695,14 @@
if (NC > 0) {
for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
sb.append("A:");
- sb.append(ent.getKey());
+ String activity = ent.getKey();
+ if (activity.startsWith(pkgName)) {
+ sb.append('*');
+ sb.append(activity.substring(
+ pkgName.length(), activity.length()));
+ } else {
+ sb.append(activity);
+ }
TimeStats times = ent.getValue();
sb.append(',');
sb.append(times.count);
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index a4b47b5..33d899a 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -18,10 +18,11 @@
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;
+import android.bluetooth.BluetoothPbap;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -76,15 +77,8 @@
private static StatusBarPolicy sInstance;
// message codes for the handler
- private static final int EVENT_DATA_CONN_STATE_CHANGED = 2;
- private static final int EVENT_DATA_ACTIVITY = 3;
private static final int EVENT_BATTERY_CLOSE = 4;
- // indices into mBatteryThresholds
- private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
- private static final int BATTERY_THRESHOLD_WARNING = 1;
- private static final int BATTERY_THRESHOLD_EMPTY = 2;
-
private final Context mContext;
private final StatusBarService mService;
private final Handler mHandler = new StatusBarHandler();
@@ -99,16 +93,13 @@
private IBinder mBatteryIcon;
private IconData mBatteryData;
private boolean mBatteryFirst = true;
- private int mBatteryPlugged;
+ private boolean mBatteryPlugged;
private int mBatteryLevel;
- private int mBatteryThreshold = 0; // index into mBatteryThresholds
- private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
private AlertDialog mLowBatteryDialog;
private TextView mBatteryLevelTextView;
private View mBatteryView;
private int mBatteryViewSequence;
private boolean mBatteryShowLowOnEndCall = false;
- private boolean mSentLowBatteryBroadcast = false;
private static final boolean SHOW_LOW_BATTERY_WARNING = true;
// phone
@@ -311,6 +302,7 @@
private IconData mBluetoothData;
private int mBluetoothHeadsetState;
private int mBluetoothA2dpState;
+ private int mBluetoothPbapState;
private boolean mBluetoothEnabled;
// wifi
@@ -363,6 +355,9 @@
else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
updateClock();
}
+ else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ updateBattery(intent);
+ }
else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
updateClock();
}
@@ -377,12 +372,17 @@
else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
updateSyncState(intent);
}
- else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- updateBattery(intent);
+ else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+ onBatteryLow(intent);
+ }
+ else if (action.equals(Intent.ACTION_BATTERY_OKAY)
+ || action.equals(Intent.ACTION_POWER_CONNECTED)) {
+ onBatteryOkay(intent);
}
else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
- action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
+ action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
updateBluetooth(intent);
}
else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
@@ -473,15 +473,16 @@
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;
}
mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
+ mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
// Gps status
@@ -521,6 +522,9 @@
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_BATTERY_LOW);
+ filter.addAction(Intent.ACTION_BATTERY_OKAY);
+ filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
@@ -529,6 +533,7 @@
filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
@@ -564,38 +569,22 @@
//mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
}
- private void pickNextBatteryLevel(int level) {
- final int N = mBatteryThresholds.length;
- for (int i=0; i<N; i++) {
- if (level >= mBatteryThresholds[i]) {
- mBatteryThreshold = i;
- break;
- }
- }
- if (mBatteryThreshold >= N) {
- mBatteryThreshold = N-1;
- }
- }
-
private final void updateBattery(Intent intent) {
mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
mService.updateIcon(mBatteryIcon, mBatteryData, null);
- int plugged = intent.getIntExtra("plugged", 0);
+ boolean plugged = intent.getIntExtra("plugged", 0) != 0;
int level = intent.getIntExtra("level", -1);
if (false) {
Log.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
- + " mBatteryThreshold=" + mBatteryThreshold
+ " mBatteryFirst=" + mBatteryFirst);
}
- int oldPlugged = mBatteryPlugged;
- int oldThreshold = mBatteryThreshold;
- pickNextBatteryLevel(level);
+ boolean oldPlugged = mBatteryPlugged;
mBatteryPlugged = plugged;
mBatteryLevel = level;
@@ -617,45 +606,31 @@
}
*/
if (false) {
- Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
- + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
+ Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
- if (plugged == 0
- && ((oldPlugged != 0 && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
- || (mBatteryThreshold > oldThreshold
- && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
- // Broadcast the low battery warning
- mSentLowBatteryBroadcast = true;
- Intent batIntent = new Intent(Intent.ACTION_BATTERY_LOW);
- batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(batIntent);
+ }
- if (SHOW_LOW_BATTERY_WARNING) {
- if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
- + " mLowBatteryDialog=" + mLowBatteryDialog
- + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
- }
+ private void onBatteryLow(Intent intent) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (false) {
+ Log.d(TAG, "mPhoneState=" + mPhoneState
+ + " mLowBatteryDialog=" + mLowBatteryDialog
+ + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
+ }
- if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
- showLowBatteryWarning();
- } else {
- mBatteryShowLowOnEndCall = true;
- }
+ if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ showLowBatteryWarning();
+ } else {
+ mBatteryShowLowOnEndCall = true;
}
- } else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) {
- if (mSentLowBatteryBroadcast == true) {
- mSentLowBatteryBroadcast = false;
- Intent batIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
- batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(batIntent);
- }
- if (SHOW_LOW_BATTERY_WARNING) {
- if (mLowBatteryDialog != null) {
- mLowBatteryDialog.dismiss();
- mBatteryShowLowOnEndCall = false;
- }
- }
+ }
+ }
+
+ private void onBatteryOkay(Intent intent) {
+ if (mLowBatteryDialog != null
+ && SHOW_LOW_BATTERY_WARNING) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
}
}
@@ -720,9 +695,11 @@
private void showLowBatteryWarning() {
closeLastBatteryView();
- int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0];
+ /* Show exact battery level.
+ * Add 1 because the text says "less than X%".
+ */
CharSequence levelText = mContext.getString(
- com.android.internal.R.string.battery_low_percent_format, level);
+ com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
if (mBatteryLevelTextView != null) {
mBatteryLevelTextView.setText(levelText);
@@ -773,7 +750,7 @@
}
if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
if (mBatteryShowLowOnEndCall) {
- if (mBatteryPlugged == 0) {
+ if (!mBatteryPlugged) {
showLowBatteryWarning();
}
mBatteryShowLowOnEndCall = false;
@@ -951,17 +928,16 @@
// Use Evdo icon
evdoIconList = this.sSignalImages_evdo;
- int evdoEcio = mSignalStrength.getEvdoEcio();
+ int evdoDbm = mSignalStrength.getEvdoDbm();
int evdoSnr = mSignalStrength.getEvdoSnr();
- int levelEvdoEcio = 0;
+ int levelEvdoDbm = 0;
int levelEvdoSnr = 0;
- // Ec/Io are in dB*10
- if (evdoEcio >= -650) levelEvdoEcio = 4;
- else if (evdoEcio >= -750) levelEvdoEcio = 3;
- else if (evdoEcio >= -900) levelEvdoEcio = 2;
- else if (evdoEcio >= -1050) levelEvdoEcio = 1;
- else levelEvdoEcio = 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;
@@ -969,7 +945,7 @@
else if (evdoSnr > 1) levelEvdoSnr = 1;
else levelEvdoSnr = 0;
- evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
+ evdoIconLevel = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
@@ -1107,20 +1083,24 @@
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);
} else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
BluetoothA2dp.STATE_DISCONNECTED);
+ } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+ mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
+ BluetoothPbap.STATE_DISCONNECTED);
} else {
return;
}
if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
- mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) {
+ mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
+ mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
}
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 1d66fb1..85d63c9 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -19,8 +19,8 @@
#include "JNIHelp.h"
#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
+#include <utils/Log.h>
+#include <utils/misc.h>
#include <fcntl.h>
#include <stdio.h>
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 2524966..8e7cadc 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -18,8 +18,8 @@
#include "JNIHelp.h"
#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
+#include <utils/Log.h>
+#include <utils/misc.h>
#include <fcntl.h>
#include <stdio.h>
@@ -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/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp
index b0aab59..22d4bd8 100644
--- a/services/jni/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_HardwareService.cpp
@@ -133,7 +133,7 @@
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },
- { "finalize_native", "(I)V", (void*)init_native },
+ { "finalize_native", "(I)V", (void*)finalize_native },
{ "setLight_native", "(IIIIII)V", (void*)setLight_native },
{ "vibratorOn", "(J)V", (void*)vibratorOn },
{ "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
index 63830d5..f27596c 100644
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ b/services/jni/com_android_server_KeyInputQueue.cpp
@@ -110,6 +110,23 @@
return NULL;
}
+static void
+android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz,
+ jstring deviceName)
+{
+ gLock.lock();
+ sp<EventHub> hub = gHub;
+ if (hub == NULL) {
+ hub = new EventHub;
+ gHub = hub;
+ }
+ gLock.unlock();
+
+ const char* nameStr = env->GetStringUTFChars(deviceName, NULL);
+ gHub->addExcludedDevice(nameStr);
+ env->ReleaseStringUTFChars(deviceName, nameStr);
+}
+
static jboolean
android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
jint deviceId, jint axis,
@@ -205,6 +222,23 @@
return st;
}
+static jint
+android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
+ jint deviceId, jint scancode)
+{
+ jint res = 0;
+ gLock.lock();
+ if (gHub != NULL) {
+ int32_t keycode;
+ uint32_t flags;
+ gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
+ res = keycode;
+ }
+ gLock.unlock();
+
+ return res;
+}
+
static jboolean
android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
jintArray keyCodes, jbooleanArray outFlags)
@@ -238,6 +272,8 @@
(void*) android_server_KeyInputQueue_getDeviceClasses },
{ "getDeviceName", "(I)Ljava/lang/String;",
(void*) android_server_KeyInputQueue_getDeviceName },
+ { "addExcludedDevice", "(Ljava/lang/String;)V",
+ (void*) android_server_KeyInputQueue_addExcludedDevice },
{ "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
(void*) android_server_KeyInputQueue_getAbsoluteInfo },
{ "getSwitchState", "(I)I",
@@ -254,6 +290,8 @@
(void*) android_server_KeyInputQueue_getKeycodeStateDevice },
{ "hasKeys", "([I[Z)Z",
(void*) android_server_KeyInputQueue_hasKeys },
+ { "scancodeToKeycode", "(II)I",
+ (void*) android_server_KeyInputQueue_scancodeToKeycode },
};
int register_android_server_KeyInputQueue(JNIEnv* env)
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index dbe8431..13713e5 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -22,11 +22,15 @@
import android.net.Uri;
import android.os.SystemProperties;
import android.provider.Contacts;
+import android.provider.ContactsContract;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseIntArray;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
+
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -56,6 +60,9 @@
public static final int TOA_International = 0x91;
public static final int TOA_Unknown = 0x81;
+ static final String LOG_TAG = "PhoneNumberUtils";
+ private static final boolean DBG = false;
+
/*
* global-phone-number = ["+"] 1*( DIGIT / written-sep )
* written-sep = ("-"/".")
@@ -129,15 +136,23 @@
}
String type = intent.resolveType(context);
+ String phoneColumn = null;
- Cursor c = context.getContentResolver().query(
- uri, new String[]{ Contacts.People.Phones.NUMBER },
- null, null, null);
+ // Correctly read out the phone entry based on requested provider
+ final String authority = uri.getAuthority();
+ if (Contacts.AUTHORITY.equals(authority)) {
+ phoneColumn = Contacts.People.Phones.NUMBER;
+ } else if (ContactsContract.AUTHORITY.equals(authority)) {
+ phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
+ }
+
+ final Cursor c = context.getContentResolver().query(uri, new String[] {
+ phoneColumn
+ }, null, null, null);
if (c != null) {
try {
if (c.moveToFirst()) {
- number = c.getString(
- c.getColumnIndex(Contacts.People.Phones.NUMBER));
+ number = c.getString(c.getColumnIndex(phoneColumn));
}
} finally {
c.close();
@@ -218,6 +233,9 @@
}
}
+ private static void log(String msg) {
+ Log.d(LOG_TAG, msg);
+ }
/** index of the last character of the network portion
* (eg anything after is a post-dial string)
*/
@@ -732,6 +750,14 @@
return true;
}
+ private static boolean isNonSeparator(String address) {
+ for (int i = 0, count = address.length(); i < count; i++) {
+ if (!isNonSeparator(address.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Note: calls extractNetworkPortion(), so do not use for
* SIM EF[ADN] style records
@@ -990,6 +1016,7 @@
* as:
*
* <p><code>
+ * xxxxx
* xxx-xxxx
* xxx-xxx-xxxx
* 1-xxx-xxx-xxxx
@@ -1003,7 +1030,11 @@
if (length > "+1-nnn-nnn-nnnn".length()) {
// The string is too long to be formatted
return;
+ } else if (length <= 5) {
+ // The string is either a shortcode or too short to be formatted
+ return;
}
+
CharSequence saved = text.subSequence(0, length);
// Strip the dashes first, as we're going to add them back
@@ -1215,4 +1246,261 @@
KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9');
KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9');
}
+
+ //================ Plus Code formatting =========================
+ private static final char PLUS_SIGN_CHAR = '+';
+ private static final String PLUS_SIGN_STRING = "+";
+ private static final String NANP_IDP_STRING = "011";
+ private static final int NANP_LENGTH = 10;
+
+ /**
+ * This function checks if there is a plus sign (+) in the passed-in dialing number.
+ * If there is, it processes the plus sign based on the default telephone
+ * numbering plan of the system when the phone is activated and the current
+ * telephone numbering plan of the system that the phone is camped on.
+ * Currently, we only support the case that the default and current telephone
+ * numbering plans are North American Numbering Plan(NANP).
+ *
+ * The passed-in dialStr should only contain the valid format as described below,
+ * 1) the 1st character in the dialStr should be one of the really dialable
+ * characters listed below
+ * ISO-LATIN characters 0-9, *, # , +
+ * 2) the dialStr should already strip out the separator characters,
+ * every character in the dialStr should be one of the non separator characters
+ * listed below
+ * ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE
+ *
+ * Otherwise, this function returns the dial string passed in
+ *
+ * This API is for CDMA only
+ *
+ * @hide TODO: pending API Council approval
+ */
+ public static String cdmaCheckAndProcessPlusCode(String dialStr) {
+ if (!TextUtils.isEmpty(dialStr)) {
+ if (isReallyDialable(dialStr.charAt(0)) &&
+ isNonSeparator(dialStr)) {
+ return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
+ getFormatTypeForLocale(Locale.getDefault()));
+ }
+ }
+ return dialStr;
+ }
+
+ /**
+ * This function should be called from checkAndProcessPlusCode only
+ * And it is used for test purpose also.
+ *
+ * It checks the dial string by looping through the network portion,
+ * post dial portion 1, post dial porting 2, etc. If there is any
+ * 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,
+ * +18475797000 is converted to 18475797000,
+ * 2)+non-NANP Numbers,replace + with the current NANP IDP, e.g,
+ * +11875767800 is converted to 01111875767800
+ * 3)+NANP in post dial string(s), e.g.
+ * 8475797000;+8475231753 is converted to 8475797000;8475231753
+ *
+ * This function returns the original dial string if locale/numbering plan
+ * aren't supported.
+ *
+ * @hide
+ */
+ public static String cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int numFormat) {
+ 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) {
+
+ 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
+ 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 = "";
+ }
+ Log.e("wrong postDialStr=", postDialStr);
+ }
+ }
+ if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
+ } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
+ }
+ return retStr;
+ }
+
+ // This function gets the default international dialing prefix
+ private static String getDefaultIdp( ) {
+ String ps = null;
+ SystemProperties.get(PROPERTY_IDP_STRING, ps);
+ if (TextUtils.isEmpty(ps)) {
+ ps = NANP_IDP_STRING;
+ }
+ return ps;
+ }
+
+ private static boolean isTwoToNine (char c) {
+ if (c >= '2' && c <= '9') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 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
+ */
+ private static boolean isNanp (String dialStr) {
+ boolean retVal = false;
+ if (dialStr != null) {
+ if (dialStr.length() == NANP_LENGTH) {
+ if (isTwoToNine(dialStr.charAt(0)) &&
+ isTwoToNine(dialStr.charAt(3))) {
+ retVal = true;
+ for (int i=1; i<NANP_LENGTH; i++ ) {
+ char c=dialStr.charAt(i);
+ if (!PhoneNumberUtils.isISODigit(c)) {
+ retVal = false;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ Log.e("isNanp: null dialStr passed in", dialStr);
+ }
+ return retVal;
+ }
+
+ /**
+ * This function checks if the passed in string conforms to 1-NANP format
+ */
+ private static boolean isOneNanp(String dialStr) {
+ boolean retVal = false;
+ if (dialStr != null) {
+ String newDialStr = dialStr.substring(1);
+ if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
+ retVal = true;
+ }
+ } else {
+ Log.e("isOneNanp: null dialStr passed in", dialStr);
+ }
+ return retVal;
+ }
+
+ /**
+ * 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
+ */
+ private static String processPlusCodeWithinNanp(String networkDialStr) {
+ String retStr = networkDialStr;
+
+ if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
+ // If there is a plus sign at the beginning of the dial string,
+ // Convert the plus sign to the default IDP since it's an international number
+ if (networkDialStr != null &
+ networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
+ networkDialStr.length() > 1) {
+ String newStr = networkDialStr.substring(1);
+ if (isNanp(newStr) || isOneNanp(newStr)) {
+ // Remove the leading plus sign
+ retStr = newStr;
+ } else {
+ String idpStr = getDefaultIdp();
+ // Replaces the plus sign with the default IDP
+ retStr = networkDialStr.replaceFirst("[+]", idpStr);
+ }
+ }
+ if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
+ return retStr;
+ }
+
+ // This function finds the index of the dialable character(s)
+ // in the post dial string
+ private static int findDialableIndexFromPostDialStr(String postDialStr) {
+ for (int index = 0;index < postDialStr.length();index++) {
+ char c = postDialStr.charAt(index);
+ if (isReallyDialable(c)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ // This function appends the non-diablable P/W character to the original
+ // dial string based on the dialable index passed in
+ private static String
+ appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
+ String retStr;
+
+ // There is only 1 P/W character before the dialable characters
+ if (dialableIndex == 1) {
+ StringBuilder ret = new StringBuilder(origStr);
+ ret = ret.append(dialStr.charAt(0));
+ retStr = ret.toString();
+ } else {
+ // It means more than 1 P/W characters in the post dial string,
+ // appends to retStr
+ String nonDigitStr = dialStr.substring(0,dialableIndex);
+ retStr = origStr.concat(nonDigitStr);
+ }
+ return retStr;
+ }
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 82539fb..598f945 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -54,10 +54,13 @@
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is sucessfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
@@ -109,10 +112,13 @@
* <code>PendingIntent</code>s (one for each message part) that is
* broadcast when the corresponding message part has been sent.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applicaitons,
* which cause smaller number of SMS to be sent in checking period.
@@ -169,10 +175,13 @@
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is sucessfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applicaitons,
* which cause smaller number of SMS to be sent in checking period.
@@ -210,10 +219,13 @@
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java
index 7eb9d85..b95dd11 100644
--- a/telephony/java/com/android/internal/telephony/Call.java
+++ b/telephony/java/com/android/internal/telephony/Call.java
@@ -25,10 +25,10 @@
/* Enums */
public enum State {
- IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED;
+ IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
public boolean isAlive() {
- return !(this == IDLE || this == DISCONNECTED);
+ return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
}
public boolean isRinging() {
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index e583110..6ebd8d6 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -82,15 +82,6 @@
}
}
- enum IccStatus {
- ICC_ABSENT,
- ICC_NOT_READY,
- ICC_READY,
- ICC_PIN,
- ICC_PUK,
- ICC_NETWORK_PERSONALIZATION
- }
-
//***** Constants
// Used as parameter to dial() and setCLIR() below
@@ -534,15 +525,6 @@
void unregisterForCdmaOtaProvision(Handler h);
/**
- * Returns current ICC status.
- *
- * AsyncResult.result is IccStatus
- *
- */
-
- void getIccStatus(Message result);
-
- /**
* Supply the ICC PIN to the ICC card
*
* returned message
@@ -1243,8 +1225,10 @@
* Request the device MDN / H_SID / H_NID / MIN.
* "response" is const char **
* [0] is MDN if CDMA subscription is available
- * [1] is H_SID (Home SID) if CDMA subscription is available
- * [2] is H_NID (Home NID) if CDMA subscription is available
+ * [1] is a comma separated list of H_SID (Home SID) in decimal format
+ * if CDMA subscription is available
+ * [2] is a comma separated list of H_NID (Home NID) in decimal format
+ * if CDMA subscription is available
* [3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available
*/
public void getCDMASubscription(Message response);
@@ -1316,11 +1300,13 @@
* the username for APN, or NULL
* @param password
* the password for APN, or NULL
+ * @param authType
+ * the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
* @param result
* Callback message
*/
public void setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, Message result);
+ String user, String password, String authType, Message result);
/**
* Deactivate packet data connection
@@ -1366,4 +1352,12 @@
* @param response callback message
*/
public void exitEmergencyCallbackMode(Message response);
+
+ /**
+ * Request the status of the ICC and UICC cards.
+ *
+ * @param response
+ * Callback message containing {@link IccCardStatus} structure for the card.
+ */
+ public void getIccCardStatus(Message result);
}
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 92f6cb8..e6fd0a0 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -56,7 +56,8 @@
CDMA_RETRY_ORDER, /* requeseted service is rejected, retry delay is set */
CDMA_ACCESS_FAILURE,
CDMA_PREEMPTED,
- CDMA_NOT_EMERGENCY /* not an emergency call */
+ CDMA_NOT_EMERGENCY, /* not an emergency call */
+ ERROR_UNSPECIFIED
}
Object userData;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index c074cb8..29e89b5 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,12 +98,28 @@
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;
//***** Constants
- protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
- /** Cap out with 30 min retry interval. */
- protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000;
+ 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,"
+ + "320000:5000,640000:5000,1280000:5000,1800000:5000";
/** Slow poll when attempting connection recovery. */
protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
@@ -145,6 +165,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;
@@ -162,6 +185,8 @@
this.phone = phone;
}
+ public abstract void dispose();
+
public Activity getActivity() {
return activity;
}
@@ -201,10 +226,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.
@@ -242,6 +270,9 @@
break;
case EVENT_ROAMING_OFF:
+ if (getDataOnRoamingEnabled() == false) {
+ mRetryMgr.resetRetryCount();
+ }
onRoamingOff();
break;
@@ -290,24 +321,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();
@@ -316,4 +341,162 @@
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 + ')');
+ 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);
+ }
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index d6151c6..00d7c72 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -94,8 +94,11 @@
public void notifyDataConnection(Phone sender, String reason) {
try {
- mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
- sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
+ mRegistry.notifyDataConnection(
+ convertDataState(sender.getDataConnectionState()),
+ sender.isDataConnectivityPossible(), reason,
+ sender.getActiveApn(),
+ sender.getActiveApnTypes(),
sender.getInterfaceName(null));
} catch (RemoteException ex) {
// system process is dead
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index e8095e1..461b694 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -183,15 +183,9 @@
}
int headerBits = (header.length + 1) * 8;
- int headerSeptets = headerBits / 7;
- headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
+ int headerSeptets = (headerBits + 6) / 7;
- int sz = data.length();
- int septetCount;
- septetCount = countGsmSeptets(data, true) + headerSeptets;
-
- byte[] ret = stringToGsm7BitPacked(data, 0, septetCount,
- (headerSeptets*7), true);
+ byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true);
// Paste in the header
ret[1] = (byte)header.length;
@@ -215,7 +209,7 @@
*/
public static byte[] stringToGsm7BitPacked(String data)
throws EncodeException {
- return stringToGsm7BitPacked(data, 0, -1, 0, true);
+ return stringToGsm7BitPacked(data, 0, true);
}
/**
@@ -228,58 +222,37 @@
* septets.
*
* @param data the text to convert to septets
- * @param dataOffset the character offset in data to start the encoding from
- * @param maxSeptets the maximum number of septets to convert, or -1 for no
- * enforced maximum.
- * @param startingBitOffset the number of padding bits to put before
- * the start of the first septet at the begining of the array
+ * @param startingSeptetOffset the number of padding septets to put before
+ * the character data at the begining of the array
* @param throwException If true, throws EncodeException on invalid char.
* If false, replaces unencodable char with GSM alphabet space char.
*
* @throws EncodeException if String is too large to encode
*/
- public static byte[] stringToGsm7BitPacked(String data, int dataOffset,
- int maxSeptets, int startingBitOffset, boolean throwException)
- throws EncodeException {
-
- int sz = data.length();
- int septetCount;
- if (maxSeptets == -1) {
- septetCount = countGsmSeptets(data, true);
- } else {
- septetCount = maxSeptets;
+ public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset,
+ boolean throwException) throws EncodeException {
+ int dataLen = data.length();
+ int septetCount = countGsmSeptets(data, throwException) + startingSeptetOffset;
+ if (septetCount > 255) {
+ throw new EncodeException("Payload cannot exceed 255 septets");
}
-
- if(septetCount > 0xff) {
- throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE
- + " septets");
- }
-
- // Enough for all the septets and the length 2 byte prefix
- byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)];
-
- int bitOffset = startingBitOffset;
- int septets = startingBitOffset/7;
- for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) {
+ int byteCount = ((septetCount * 7) + 7) / 8;
+ byte[] ret = new byte[byteCount + 1]; // Include space for one byte length prefix.
+ for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7;
+ i < dataLen && septets < septetCount;
+ i++, bitOffset += 7) {
char c = data.charAt(i);
-
int v = GsmAlphabet.charToGsm(c, throwException);
if (v == GSM_EXTENDED_ESCAPE) {
- // Lookup the extended char
- v = GsmAlphabet.charToGsmExtended(c);
-
+ v = GsmAlphabet.charToGsmExtended(c); // Lookup the extended char.
packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE);
bitOffset += 7;
septets++;
}
-
packSmsChar(ret, bitOffset, v);
septets++;
}
-
- // See check for > 0xff above
- ret[0] = (byte)septets;
-
+ ret[0] = (byte) (septetCount); // Validated by check above.
return ret;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 865c6ca..6b42e6b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,7 @@
void notifyCallForwardingChanged(boolean cfi);
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName);
+ String reason, String apn, in String[] apnTypes, String interfaceName);
void notifyDataConnectionFailed(String reason);
void notifyCellLocation(in Bundle cellLocation);
}
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d7ad492..c2bed88 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -16,13 +16,40 @@
package com.android.internal.telephony;
-import android.os.Message;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.os.AsyncResult;
import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.util.Log;
+
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.CommandsInterface.RadioState;
/**
* {@hide}
*/
-public interface IccCard {
+public abstract class IccCard {
+ protected String mLogTag;
+ protected boolean mDbg;
+
+ private IccCardStatus mIccCardStatus = null;
+ protected State mState = null;
+ protected PhoneBase mPhone;
+ private RegistrantList mAbsentRegistrants = new RegistrantList();
+ private RegistrantList mPinLockedRegistrants = new RegistrantList();
+ private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
+
+ private boolean mDesiredPinLocked;
+ private boolean mDesiredFdnEnabled;
+ private boolean mIccPinLocked = true; // Default to locked
+ private boolean mIccFdnEnabled = false; // Default to disabled.
+ // Will be updated when SIM_READY.
+
+
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
static public final String INTENT_KEY_ICC_STATE = "ss";
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
@@ -46,6 +73,17 @@
/* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
+ protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1;
+ private static final int EVENT_GET_ICC_STATUS_DONE = 2;
+ protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
+ private static final int EVENT_PINPUK_DONE = 4;
+ private static final int EVENT_REPOLL_STATUS_DONE = 5;
+ protected static final int EVENT_ICC_READY = 6;
+ private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
+ private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
+ private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9;
+ private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
+ private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
/*
UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
@@ -58,33 +96,108 @@
PIN_REQUIRED,
PUK_REQUIRED,
NETWORK_LOCKED,
- READY;
+ READY,
+ NOT_READY;
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
}
}
- State getState();
+ public State getState() {
+ if (mState == null) {
+ switch(mPhone.mCM.getRadioState()) {
+ /* This switch block must not return anything in
+ * State.isLocked() or State.ABSENT.
+ * If it does, handleSimStatus() may break
+ */
+ case RADIO_OFF:
+ case RADIO_UNAVAILABLE:
+ case SIM_NOT_READY:
+ case RUIM_NOT_READY:
+ return State.UNKNOWN;
+ case SIM_LOCKED_OR_ABSENT:
+ case RUIM_LOCKED_OR_ABSENT:
+ //this should be transient-only
+ return State.UNKNOWN;
+ case SIM_READY:
+ case RUIM_READY:
+ case NV_READY:
+ return State.READY;
+ case NV_NOT_READY:
+ return State.ABSENT;
+ }
+ } else {
+ return mState;
+ }
+ Log.e(mLogTag, "IccCard.getState(): case should never be reached");
+ return State.UNKNOWN;
+ }
+
+ public IccCard(PhoneBase phone, String logTag, Boolean dbg) {
+ mPhone = phone;
+ mLogTag = logTag;
+ mDbg = dbg;
+ }
+
+ abstract public void dispose();
+
+ protected void finalize() {
+ if(mDbg) Log.d(mLogTag, "IccCard finalized");
+ }
/**
* Notifies handler of any transition into State.ABSENT
*/
- void registerForAbsent(Handler h, int what, Object obj);
- void unregisterForAbsent(Handler h);
+ public void registerForAbsent(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
- /**
- * Notifies handler of any transition into State.isPinLocked()
- */
- void registerForLocked(Handler h, int what, Object obj);
- void unregisterForLocked(Handler h);
+ mAbsentRegistrants.add(r);
+
+ if (getState() == State.ABSENT) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForAbsent(Handler h) {
+ mAbsentRegistrants.remove(h);
+ }
/**
* Notifies handler of any transition into State.NETWORK_LOCKED
*/
- void registerForNetworkLocked(Handler h, int what, Object obj);
- void unregisterForNetworkLocked(Handler h);
+ public void registerForNetworkLocked(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+
+ mNetworkLockedRegistrants.add(r);
+
+ if (getState() == State.NETWORK_LOCKED) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForNetworkLocked(Handler h) {
+ mNetworkLockedRegistrants.remove(h);
+ }
+
+ /**
+ * Notifies handler of any transition into State.isPinLocked()
+ */
+ public void registerForLocked(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+
+ mPinLockedRegistrants.add(r);
+
+ if (getState().isPinLocked()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForLocked(Handler h) {
+ mPinLockedRegistrants.remove(h);
+ }
+
/**
* Supply the ICC PIN to the ICC
@@ -107,10 +220,30 @@
*
*/
- void supplyPin (String pin, Message onComplete);
- void supplyPuk (String puk, String newPin, Message onComplete);
- void supplyPin2 (String pin2, Message onComplete);
- void supplyPuk2 (String puk2, String newPin2, Message onComplete);
+ public void supplyPin (String pin, Message onComplete) {
+ mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPuk (String puk, String newPin, Message onComplete) {
+ mPhone.mCM.supplyIccPuk(puk, newPin,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPin2 (String pin2, Message onComplete) {
+ mPhone.mCM.supplyIccPin2(pin2,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
+ mPhone.mCM.supplyIccPuk2(puk2, newPin2,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyNetworkDepersonalization (String pin, Message onComplete) {
+ if(mDbg) log("Network Despersonalization: " + pin);
+ mPhone.mCM.supplyNetworkDepersonalization(pin,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
/**
* Check whether ICC pin lock is enabled
@@ -119,35 +252,9 @@
* @return true for ICC locked enabled
* false for ICC locked disabled
*/
- boolean getIccLockEnabled ();
-
- /**
- * Set the ICC pin lock enabled or disabled
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param enabled "true" for locked "false" for unlocked.
- * @param password needed to change the ICC pin state, aka. Pin1
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void setIccLockEnabled(boolean enabled, String password, Message onComplete);
-
-
- /**
- * Change the ICC password used in ICC pin lock
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete);
+ public boolean getIccLockEnabled() {
+ return mIccPinLocked;
+ }
/**
* Check whether ICC fdn (fixed dialing number) is enabled
@@ -156,36 +263,99 @@
* @return true for ICC fdn enabled
* false for ICC fdn disabled
*/
- boolean getIccFdnEnabled ();
+ public boolean getIccFdnEnabled() {
+ return mIccFdnEnabled;
+ }
- /**
- * Set the ICC fdn enabled or disabled
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param enabled "true" for locked "false" for unlocked.
- * @param password needed to change the ICC fdn enable, aka Pin2
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void setIccFdnEnabled(boolean enabled, String password, Message onComplete);
+ /**
+ * Set the ICC pin lock enabled or disabled
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param enabled "true" for locked "false" for unlocked.
+ * @param password needed to change the ICC pin state, aka. Pin1
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void setIccLockEnabled (boolean enabled,
+ String password, Message onComplete) {
+ int serviceClassX;
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX;
- /**
- * Change the ICC password used in ICC fdn enable
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete);
+ mDesiredPinLocked = enabled;
- void supplyNetworkDepersonalization (String pin, Message onComplete);
+ mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
+ enabled, password, serviceClassX,
+ mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
+ }
+
+ /**
+ * Set the ICC fdn enabled or disabled
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param enabled "true" for locked "false" for unlocked.
+ * @param password needed to change the ICC fdn enable, aka Pin2
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void setIccFdnEnabled (boolean enabled,
+ String password, Message onComplete) {
+ int serviceClassX;
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX +
+ CommandsInterface.SERVICE_CLASS_SMS;
+
+ mDesiredFdnEnabled = enabled;
+
+ mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
+ enabled, password, serviceClassX,
+ mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
+ }
+
+ /**
+ * Change the ICC password used in ICC pin lock
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param oldPassword is the old password
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void changeIccLockPassword(String oldPassword, String newPassword,
+ Message onComplete) {
+ if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
+ mPhone.mCM.changeIccPin(oldPassword, newPassword,
+ mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+ }
+
+ /**
+ * Change the ICC password used in ICC fdn enable
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param oldPassword is the old password
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void changeIccFdnPassword(String oldPassword, String newPassword,
+ Message onComplete) {
+ if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
+ mPhone.mCM.changeIccPin2(oldPassword, newPassword,
+ mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+ }
+
/**
* Returns service provider name stored in ICC card.
@@ -203,5 +373,301 @@
* yet available
*
*/
- String getServiceProviderName();
+ public abstract String getServiceProviderName();
+
+ protected void updateStateProperty() {
+ mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
+ }
+
+ private void getIccCardStatusDone(AsyncResult ar) {
+ if (ar.exception != null) {
+ Log.e(mLogTag,"Error getting ICC status. "
+ + "RIL_REQUEST_GET_ICC_STATUS should "
+ + "never return an error", ar.exception);
+ return;
+ }
+ handleIccCardStatus((IccCardStatus) ar.result);
+ }
+
+ private void handleIccCardStatus(IccCardStatus newCardStatus) {
+ boolean transitionedIntoPinLocked;
+ boolean transitionedIntoAbsent;
+ boolean transitionedIntoNetworkLocked;
+
+ State oldState, newState;
+
+ oldState = mState;
+ mIccCardStatus = newCardStatus;
+ newState = getIccCardState();
+ mState = newState;
+
+ updateStateProperty();
+
+ transitionedIntoPinLocked = (
+ (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
+ || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
+ transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
+ transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
+ && newState == State.NETWORK_LOCKED);
+
+ if (transitionedIntoPinLocked) {
+ if(mDbg) log("Notify SIM pin or puk locked.");
+ mPinLockedRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+ (newState == State.PIN_REQUIRED) ?
+ INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
+ } else if (transitionedIntoAbsent) {
+ if(mDbg) log("Notify SIM missing.");
+ mAbsentRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null);
+ } else if (transitionedIntoNetworkLocked) {
+ if(mDbg) log("Notify SIM network locked.");
+ mNetworkLockedRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+ INTENT_VALUE_LOCKED_NETWORK);
+ }
+ }
+
+ /**
+ * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+ * @param ar is asyncResult of Query_Facility_Locked
+ */
+ private void onQueryFdnEnabled(AsyncResult ar) {
+ if(ar.exception != null) {
+ if(mDbg) log("Error in querying facility lock:" + ar.exception);
+ return;
+ }
+
+ int[] ints = (int[])ar.result;
+ if(ints.length != 0) {
+ mIccFdnEnabled = (0!=ints[0]);
+ if(mDbg) log("Query facility lock : " + mIccFdnEnabled);
+ } else {
+ Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+ }
+ }
+
+ /**
+ * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+ * @param ar is asyncResult of Query_Facility_Locked
+ */
+ private void onQueryFacilityLock(AsyncResult ar) {
+ if(ar.exception != null) {
+ if (mDbg) log("Error in querying facility lock:" + ar.exception);
+ return;
+ }
+
+ int[] ints = (int[])ar.result;
+ if(ints.length != 0) {
+ mIccPinLocked = (0!=ints[0]);
+ if(mDbg) log("Query facility lock : " + mIccPinLocked);
+ } else {
+ Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+ }
+ }
+
+ public void broadcastIccStateChangedIntent(String value, String reason) {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName());
+ intent.putExtra(INTENT_KEY_ICC_STATE, value);
+ intent.putExtra(INTENT_KEY_LOCKED_REASON, reason);
+ if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value
+ + " reason " + reason);
+ ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+ }
+
+ protected Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg){
+ AsyncResult ar;
+ int serviceClassX;
+
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX;
+
+ switch (msg.what) {
+ case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+ mState = null;
+ updateStateProperty();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null);
+ break;
+ case EVENT_ICC_READY:
+ //TODO: put facility read in SIM_READY now, maybe in REG_NW
+ mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
+ break;
+ case EVENT_ICC_LOCKED_OR_ABSENT:
+ mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+ break;
+ case EVENT_GET_ICC_STATUS_DONE:
+ ar = (AsyncResult)msg.obj;
+
+ getIccCardStatusDone(ar);
+ break;
+ case EVENT_PINPUK_DONE:
+ // a PIN/PUK/PIN2/PUK2/Network Personalization
+ // request has completed. ar.userObj is the response Message
+ // Repoll before returning
+ ar = (AsyncResult)msg.obj;
+ // TODO should abstract these exceptions
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ mPhone.mCM.getIccCardStatus(
+ obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
+ break;
+ case EVENT_REPOLL_STATUS_DONE:
+ // Finished repolling status after PIN operation
+ // ar.userObj is the response messaeg
+ // ar.userObj.obj is already an AsyncResult with an
+ // appropriate exception filled in if applicable
+
+ ar = (AsyncResult)msg.obj;
+ getIccCardStatusDone(ar);
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_QUERY_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFacilityLock(ar);
+ break;
+ case EVENT_QUERY_FACILITY_FDN_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFdnEnabled(ar);
+ break;
+ case EVENT_CHANGE_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ mIccPinLocked = mDesiredPinLocked;
+ if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
+ "mIccPinLocked= " + mIccPinLocked);
+ } else {
+ Log.e(mLogTag, "Error change facility lock with exception "
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_CHANGE_FACILITY_FDN_DONE:
+ ar = (AsyncResult)msg.obj;
+
+ if (ar.exception == null) {
+ mIccFdnEnabled = mDesiredFdnEnabled;
+ if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
+ "mIccFdnEnabled=" + mIccFdnEnabled);
+ } else {
+ Log.e(mLogTag, "Error change facility fdn with exception "
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_CHANGE_ICC_PASSWORD_DONE:
+ ar = (AsyncResult)msg.obj;
+ if(ar.exception != null) {
+ Log.e(mLogTag, "Error in change sim password with exception"
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ default:
+ Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what);
+ }
+ }
+ };
+
+ public State getIccCardState() {
+ if (mIccCardStatus == null) {
+ Log.e(mLogTag, "[IccCard] IccCardStatus is null");
+ return IccCard.State.ABSENT;
+ }
+
+ // this is common for all radio technologies
+ if (!mIccCardStatus.getCardState().isCardPresent()) {
+ return IccCard.State.NOT_READY;
+ }
+
+ RadioState currentRadioState = mPhone.mCM.getRadioState();
+ // check radio technology
+ if( currentRadioState == RadioState.RADIO_OFF ||
+ currentRadioState == RadioState.RADIO_UNAVAILABLE ||
+ currentRadioState == RadioState.SIM_NOT_READY ||
+ currentRadioState == RadioState.RUIM_NOT_READY ||
+ currentRadioState == RadioState.NV_NOT_READY ||
+ currentRadioState == RadioState.NV_READY) {
+ return IccCard.State.NOT_READY;
+ }
+
+ if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.SIM_READY ||
+ currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+
+ int index;
+
+ // check for CDMA radio technology
+ if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+ index = mIccCardStatus.getCdmaSubscriptionAppIndex();
+ }
+ else {
+ index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+ }
+
+ IccCardApplication app = mIccCardStatus.getApplication(index);
+
+ if (app == null) {
+ Log.e(mLogTag, "[IccCard] Subscription Application in not present");
+ return IccCard.State.ABSENT;
+ }
+
+ // check if PIN required
+ if (app.app_state.isPinRequired()) {
+ return IccCard.State.PIN_REQUIRED;
+ }
+ if (app.app_state.isPukRequired()) {
+ return IccCard.State.PUK_REQUIRED;
+ }
+ if (app.app_state.isSubscriptionPersoEnabled()) {
+ return IccCard.State.NETWORK_LOCKED;
+ }
+ if (app.app_state.isAppReady()) {
+ return IccCard.State.READY;
+ }
+ if (app.app_state.isAppNotReady()) {
+ return IccCard.State.NOT_READY;
+ }
+ return IccCard.State.NOT_READY;
+ }
+
+ return IccCard.State.ABSENT;
+ }
+
+
+ public boolean hasApplicationType(IccCardApplication.AppType type) {
+ if (mIccCardStatus == null) return false;
+
+ for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
+ IccCardApplication app = mIccCardStatus.getApplication(i);
+ if (app != null && app.app_type == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void log(String msg) {
+ Log.d(mLogTag, "[IccCard] " + msg);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index b602b1c..0e7bad7 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -45,42 +45,89 @@
PINSTATE_ENABLED_PERM_BLOCKED
};
- public CardState card_state;
- public PinState universal_pin_state;
- public int gsm_umts_subscription_app_index;
- public int cdma_subscription_app_index;
- public int num_applications;
+ private CardState mCardState;
+ private PinState mUniversalPinState;
+ private int mGsmUmtsSubscriptionAppIndex;
+ private int mCdmaSubscriptionAppIndex;
+ private int mNumApplications;
- ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS);
+ private ArrayList<IccCardApplication> mApplications =
+ new ArrayList<IccCardApplication>(CARD_MAX_APPS);
- CardState CardStateFromRILInt(int state) {
- CardState newState;
- /* RIL_CardState ril.h */
- switch(state) {
- case 0: newState = CardState.CARDSTATE_ABSENT; break;
- case 1: newState = CardState.CARDSTATE_PRESENT; break;
- case 2: newState = CardState.CARDSTATE_ERROR; break;
- default:
- throw new RuntimeException(
- "Unrecognized RIL_CardState: " +state);
- }
- return newState;
+ public CardState getCardState() {
+ return mCardState;
}
- PinState PinStateFromRILInt(int state) {
- PinState newState;
- /* RIL_PinState ril.h */
+ public void setCardState(int state) {
switch(state) {
- case 0: newState = PinState.PINSTATE_UNKNOWN; break;
- case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break;
- case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break;
- case 3: newState = PinState.PINSTATE_DISABLED; break;
- case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break;
- case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break;
- default:
- throw new RuntimeException(
- "Unrecognized RIL_PinState: " +state);
+ case 0:
+ mCardState = CardState.CARDSTATE_ABSENT;
+ break;
+ case 1:
+ mCardState = CardState.CARDSTATE_PRESENT;
+ break;
+ case 2:
+ mCardState = CardState.CARDSTATE_ERROR;
+ break;
+ default:
+ throw new RuntimeException("Unrecognized RIL_CardState: " + state);
}
- return newState;
+ }
+
+ public void setUniversalPinState(int state) {
+ switch(state) {
+ case 0:
+ mUniversalPinState = PinState.PINSTATE_UNKNOWN;
+ break;
+ case 1:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED;
+ break;
+ case 2:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED;
+ break;
+ case 3:
+ mUniversalPinState = PinState.PINSTATE_DISABLED;
+ break;
+ case 4:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED;
+ break;
+ case 5:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED;
+ break;
+ default:
+ throw new RuntimeException("Unrecognized RIL_PinState: " + state);
+ }
+ }
+
+ public int getGsmUmtsSubscriptionAppIndex() {
+ return mGsmUmtsSubscriptionAppIndex;
+ }
+
+ public void setGsmUmtsSubscriptionAppIndex(int gsmUmtsSubscriptionAppIndex) {
+ mGsmUmtsSubscriptionAppIndex = gsmUmtsSubscriptionAppIndex;
+ }
+
+ public int getCdmaSubscriptionAppIndex() {
+ return mCdmaSubscriptionAppIndex;
+ }
+
+ public void setCdmaSubscriptionAppIndex(int cdmaSubscriptionAppIndex) {
+ mCdmaSubscriptionAppIndex = cdmaSubscriptionAppIndex;
+ }
+
+ public int getNumApplications() {
+ return mNumApplications;
+ }
+
+ public void setNumApplications(int numApplications) {
+ mNumApplications = numApplications;
+ }
+
+ public void addApplication(IccCardApplication application) {
+ mApplications.add(application);
+ }
+
+ public IccCardApplication getApplication(int index) {
+ return mApplications.get(index);
}
}
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 881ed2d..3e7094e 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -74,7 +74,7 @@
* exactly as received"
*/
public static int
- bcdByteToInt(byte b) {
+ gsmBcdByteToInt(byte b) {
int ret = 0;
// treat out-of-range BCD values as 0
@@ -89,11 +89,14 @@
return ret;
}
- /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD
- * digit is expected in the most significant nibble.
+ /**
+ * Decodes a CDMA style BCD byte like {@link gsmBcdByteToInt}, but
+ * opposite nibble format. The least significant BCD digit
+ * is in the least significant nibble and the most significant
+ * is in the most significant nibble.
*/
public static int
- beBcdByteToInt(byte b) {
+ cdmaBcdByteToInt(byte b) {
int ret = 0;
// treat out-of-range BCD values as 0
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 7f2b849..622b47d 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -22,6 +22,7 @@
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -98,8 +99,9 @@
static final String PHONE_NAME_KEY = "phoneName";
static final String FAILURE_REASON_KEY = "reason";
static final String STATE_CHANGE_REASON_KEY = "reason";
- static final String DATA_APN_TYPE_KEY = "apnType";
+ static final String DATA_APN_TYPES_KEY = "apnType";
static final String DATA_APN_KEY = "apn";
+
static final String DATA_IFACE_NAME_KEY = "iface";
static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
static final String PHONE_IN_ECM_STATE = "phoneinECMState";
@@ -119,10 +121,16 @@
static final String APN_TYPE_MMS = "mms";
/** APN type for SUPL assisted GPS */
static final String APN_TYPE_SUPL = "supl";
+ /** APN type for DUN traffic */
+ static final String APN_TYPE_DUN = "dun";
+ /** APN type for HiPri traffic */
+ static final String APN_TYPE_HIPRI = "hipri";
// "Features" accessible through the connectivity manager
static final String FEATURE_ENABLE_MMS = "enableMMS";
static final String FEATURE_ENABLE_SUPL = "enableSUPL";
+ static final String FEATURE_ENABLE_DUN = "enableDUN";
+ static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
/**
* Return codes for <code>enableApnType()</code>
@@ -260,8 +268,8 @@
/**
* Get current coarse-grained voice call state.
- * Use {@link #registerForPhoneStateChanged(Handler, int, Object)
- * registerForPhoneStateChanged()} for change notification. <p>
+ * Use {@link #registerForPreciseCallStateChanged(Handler, int, Object)
+ * registerForPreciseCallStateChanged()} for change notification. <p>
* If the phone has an active call and call waiting occurs,
* then the phone state is RINGING not OFFHOOK
* <strong>Note:</strong>
@@ -315,18 +323,21 @@
void unregisterForUnknownConnection(Handler h);
/**
- * Notifies when any aspect of the voice call state changes.
+ * Register for getting notifications for change in the Call State {@link Call.State}
+ * This is called PreciseCallState because the call state is more precise than the
+ * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
+ *
* Resulting events will have an AsyncResult in <code>Message.obj</code>.
* AsyncResult.userData will be set to the obj argument here.
* The <em>h</em> parameter is held only by a weak reference.
*/
- void registerForPhoneStateChanged(Handler h, int what, Object obj);
+ void registerForPreciseCallStateChanged(Handler h, int what, Object obj);
/**
* Unregisters for voice call state change notifications.
* Extraneous calls are tolerated silently.
*/
- void unregisterForPhoneStateChanged(Handler h);
+ void unregisterForPreciseCallStateChanged(Handler h);
/**
@@ -538,6 +549,20 @@
void unregisterForCdmaOtaStatusChange(Handler h);
/**
+ * Registration point for subscription info ready
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj);
+
+ /**
+ * Unregister for notifications for subscription info
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSubscriptionInfoReady(Handler h);
+
+ /**
* Returns SIM record load state. Use
* <code>getSimCard().registerForReady()</code> for change notification.
*
@@ -556,8 +581,8 @@
/**
* Answers a ringing or waiting call. Active calls, if any, go on hold.
* Answering occurs asynchronously, and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
@@ -567,8 +592,8 @@
* Reject (ignore) a ringing call. In GSM, this means UDUB
* (User Determined User Busy). Reject occurs asynchronously,
* and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
@@ -578,8 +603,8 @@
* Places any active calls on hold, and makes any held calls
* active. Switch occurs asynchronously and may fail.
* Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if a call is ringing, waiting, or
* dialing/alerting. In these cases, this operation may not be performed.
@@ -596,8 +621,8 @@
/**
* Conferences holding and active. Conference occurs asynchronously
* and may fail. Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if canConference() would return false.
* In these cases, this operation may not be performed.
@@ -631,8 +656,8 @@
* Connects the two calls and disconnects the subscriber from both calls
* Explicit Call Transfer occurs asynchronously
* and may fail. Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if canTransfer() would return false.
* In these cases, this operation may not be performed.
@@ -659,8 +684,8 @@
* IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getForegroundCall();
@@ -676,8 +701,8 @@
* IDLE, HOLDING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getBackgroundCall();
@@ -693,8 +718,8 @@
* IDLE, INCOMING, WAITING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getRingingCall();
@@ -1067,8 +1092,8 @@
/**
* Gets current mute status. Use
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}
* as a change notifcation, although presently phone state changed is not
* fired when setMute() is called.
*
@@ -1262,6 +1287,13 @@
boolean disableDataConnectivity();
/**
+ * Report the current state of data connectivity (enabled or disabled)
+ * @return {@code false} if data connectivity has been explicitly disabled,
+ * {@code true} otherwise.
+ */
+ boolean isDataConnectivityEnabled();
+
+ /**
* Enables the specified APN type. Only works for "special" APN types,
* i.e., not the default APN.
* @param type The desired APN type. Cannot be {@link #APN_TYPE_DEFAULT}.
@@ -1355,6 +1387,13 @@
String getCdmaMin();
/**
+ * Check if subscription data has been assigned to mMin
+ *
+ * return true if MIN info is ready; false otherwise.
+ */
+ boolean isMinInfoReady();
+
+ /**
* Retrieves PRL Version for CDMA phones
*/
String getCdmaPrlVersion();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index bcb1ccc..6f4aef9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.SharedPreferences;
+import android.net.wifi.WifiManager;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
@@ -28,6 +29,7 @@
import android.os.RegistrantList;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.text.TextUtils;
@@ -57,10 +59,13 @@
private static final String LOG_TAG = "PHONE";
private static final boolean LOCAL_DEBUG = true;
- // Key used to read and write the saved network selection value
+ // Key used to read and write the saved network selection numeric value
public static final String NETWORK_SELECTION_KEY = "network_selection_key";
+ // Key used to read and write the saved network selection operator name
+ public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key";
- // Key used to read/write "disable data connection on boot" pref (used for testing)
+
+ // Key used to read/write "disable data connection on boot" pref (used for testing)
public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
//***** Event Constants
@@ -104,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
@@ -117,7 +123,7 @@
}
- protected final RegistrantList mPhoneStateRegistrants
+ protected final RegistrantList mPreciseCallStateRegistrants
= new RegistrantList();
protected final RegistrantList mNewRingingConnectionRegistrants
@@ -185,7 +191,7 @@
this.mContext = context;
mLooper = Looper.myLooper();
- setLocaleByCarrier();
+ setPropertiesByCarrier();
setUnitTestMode(unitTestMode);
@@ -219,25 +225,24 @@
}
// Inherited documentation suffices.
- public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
+ public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
checkCorrectThread(h);
- mPhoneStateRegistrants.addUnique(h, what, obj);
+ mPreciseCallStateRegistrants.addUnique(h, what, obj);
}
// Inherited documentation suffices.
- public void unregisterForPhoneStateChanged(Handler h) {
- mPhoneStateRegistrants.remove(h);
+ public void unregisterForPreciseCallStateChanged(Handler h) {
+ mPreciseCallStateRegistrants.remove(h);
}
/**
- * Notify registrants of a PhoneStateChanged.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
*/
- protected void notifyCallStateChangedP() {
+ protected void notifyPreciseCallStateChangedP() {
AsyncResult ar = new AsyncResult(null, this, null);
- mPhoneStateRegistrants.notifyRegistrants(ar);
+ mPreciseCallStateRegistrants.notifyRegistrants(ar);
}
// Inherited documentation suffices.
@@ -450,10 +455,10 @@
}
/**
- * Set the locale by matching the carrier string in
+ * Set the properties by matching the carrier string in
* a string-array resource
*/
- private void setLocaleByCarrier() {
+ private void setPropertiesByCarrier() {
String carrier = SystemProperties.get("ro.carrier");
if (null == carrier || 0 == carrier.length()) {
@@ -461,18 +466,36 @@
}
CharSequence[] carrierLocales = mContext.
- getResources().getTextArray(R.array.carrier_locales);
+ getResources().getTextArray(R.array.carrier_properties);
- for (int i = 0; i < carrierLocales.length-1; i+=2) {
+ for (int i = 0; i < carrierLocales.length; i+=3) {
String c = carrierLocales[i].toString();
- String l = carrierLocales[i+1].toString();
if (carrier.equals(c)) {
+ String l = carrierLocales[i+1].toString();
+ int wifiChannels = 0;
+ try {
+ wifiChannels = Integer.parseInt(
+ carrierLocales[i+2].toString());
+ } catch (NumberFormatException e) { }
+
String language = l.substring(0, 2);
String country = "";
if (l.length() >=5) {
country = l.substring(3, 5);
}
setSystemLocale(language, country);
+
+ if (wifiChannels != 0) {
+ try {
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+ } catch (Settings.SettingNotFoundException e) {
+ // note this is not persisting
+ WifiManager wM = (WifiManager)
+ mContext.getSystemService(Context.WIFI_SERVICE);
+ wM.setNumAllowedChannels(wifiChannels, false);
+ }
+ }
return;
}
}
@@ -679,6 +702,12 @@
return null;
}
+ public boolean isMinInfoReady() {
+ // 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.");
+ return false;
+ }
+
public String getCdmaPrlVersion(){
// 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.");
@@ -705,6 +734,16 @@
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
+ public void registerForSubscriptionInfoReady(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 unregisterForSubscriptionInfoReady(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 boolean isOtaSpNumber(String dialStr) {
// 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.");
@@ -786,4 +825,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 da00268..f2568c1 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -25,6 +25,7 @@
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.util.Log;
@@ -210,12 +211,12 @@
mActivePhone.unregisterForUnknownConnection(h);
}
- public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
- mActivePhone.registerForPhoneStateChanged(h, what, obj);
+ public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
+ mActivePhone.registerForPreciseCallStateChanged(h, what, obj);
}
- public void unregisterForPhoneStateChanged(Handler h) {
- mActivePhone.unregisterForPhoneStateChanged(h);
+ public void unregisterForPreciseCallStateChanged(Handler h) {
+ mActivePhone.unregisterForPreciseCallStateChanged(h);
}
public void registerForNewRingingConnection(Handler h, int what, Object obj) {
@@ -314,6 +315,14 @@
mActivePhone.unregisterForCdmaOtaStatusChange(h);
}
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ mActivePhone.registerForSubscriptionInfoReady(h, what, obj);
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ mActivePhone.unregisterForSubscriptionInfoReady(h);
+ }
+
public boolean getIccRecordsLoaded() {
return mActivePhone.getIccRecordsLoaded();
}
@@ -418,6 +427,10 @@
return mActivePhone.getCdmaMin();
}
+ public boolean isMinInfoReady() {
+ return mActivePhone.isMinInfoReady();
+ }
+
public String getCdmaPrlVersion() {
return mActivePhone.getCdmaPrlVersion();
}
@@ -613,6 +626,10 @@
return mActivePhone.disableApnType(type);
}
+ public boolean isDataConnectivityEnabled() {
+ return mActivePhone.isDataConnectivityEnabled();
+ }
+
public boolean isDataConnectivityPossible() {
return mActivePhone.isDataConnectivityPossible();
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 690b38a..50bf218 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -630,7 +630,7 @@
}
public void
- getIccStatus(Message result) {
+ getIccCardStatus(Message result) {
//Note: This RIL request has not been renamed to ICC,
// but this request is also valid for SIM and RUIM
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
@@ -1237,10 +1237,17 @@
*/
public void
setupDefaultPDP(String apn, String user, String password, Message result) {
- String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS
+ int radioTechnology;
+ int authType;
String profile = ""; //profile number, NULL for GSM/UMTS
- setupDataCall(radioTechnology, profile, apn, user,
- password, result);
+
+ radioTechnology = RILConstants.SETUP_DATA_TECH_GSM;
+ //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
+ authType = (user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP
+ : RILConstants.SETUP_DATA_AUTH_NONE;
+
+ setupDataCall(Integer.toString(radioTechnology), profile, apn, user,
+ password, Integer.toString(authType), result);
}
@@ -1259,7 +1266,7 @@
*/
public void
setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, Message result) {
+ String user, String password, String authType, Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
@@ -1270,15 +1277,12 @@
rr.mp.writeString(apn);
rr.mp.writeString(user);
rr.mp.writeString(password);
- //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
- // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed.
- if (user != null)
- rr.mp.writeString("3");
- else
- rr.mp.writeString("0");
+ rr.mp.writeString(authType);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
- + apn);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest) + " " + radioTechnology + " "
+ + profile + " " + apn + " " + user + " "
+ + password + " " + authType);
send(rr);
}
@@ -2553,7 +2557,7 @@
break;
case RIL_UNSOL_CDMA_CALL_WAITING:
- if (RILJ_LOGD) unsljLog(response);
+ if (RILJ_LOGD) unsljLogRet(response, ret);
if (mCallWaitingInfoRegistrants != null) {
mCallWaitingInfoRegistrants.notifyRegistrants(
@@ -2735,24 +2739,22 @@
private Object
responseIccCardStatus(Parcel p) {
- RadioState currentRadioState;
IccCardApplication ca;
- currentRadioState = getRadioState();
-
IccCardStatus status = new IccCardStatus();
- status.card_state = status.CardStateFromRILInt(p.readInt());
- status.universal_pin_state = status.PinStateFromRILInt(p.readInt());
- status.gsm_umts_subscription_app_index = p.readInt();
- status.cdma_subscription_app_index = p.readInt();
- status.num_applications = p.readInt();
+ status.setCardState(p.readInt());
+ status.setUniversalPinState(p.readInt());
+ status.setGsmUmtsSubscriptionAppIndex(p.readInt());
+ status.setCdmaSubscriptionAppIndex(p.readInt());
+ int numApplications = p.readInt();
// limit to maximum allowed applications
- if (status.num_applications > IccCardStatus.CARD_MAX_APPS) {
- status.num_applications = IccCardStatus.CARD_MAX_APPS;
+ if (numApplications > IccCardStatus.CARD_MAX_APPS) {
+ numApplications = IccCardStatus.CARD_MAX_APPS;
}
+ status.setNumApplications(numApplications);
- for (int i = 0 ; i < status.num_applications ; i++) {
+ for (int i = 0 ; i < numApplications ; i++) {
ca = new IccCardApplication();
ca.app_type = ca.AppTypeFromRILInt(p.readInt());
ca.app_state = ca.AppStateFromRILInt(p.readInt());
@@ -2762,62 +2764,9 @@
ca.pin1_replaced = p.readInt();
ca.pin1 = p.readInt();
ca.pin2 = p.readInt();
- status.application.add(ca);
+ status.addApplication(ca);
}
-
- // this is common for all radio technologies
- if (!status.card_state.isCardPresent()) {
- return IccStatus.ICC_ABSENT;
- }
-
- // check radio technology
- if( currentRadioState == RadioState.RADIO_OFF ||
- currentRadioState == RadioState.RADIO_UNAVAILABLE ||
- currentRadioState == RadioState.SIM_NOT_READY ||
- currentRadioState == RadioState.RUIM_NOT_READY ||
- currentRadioState == RadioState.NV_NOT_READY ||
- currentRadioState == RadioState.NV_READY ) {
- return IccStatus.ICC_NOT_READY;
- }
-
- if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.SIM_READY ||
- currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.RUIM_READY) {
-
- int index;
-
- // check for CDMA radio technology
- if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.RUIM_READY) {
- index = status.cdma_subscription_app_index;
- }
- else {
- index = status.gsm_umts_subscription_app_index;
- }
-
- // check if PIN required
- if (status.application.get(index).app_state.isPinRequired()) {
- return IccStatus.ICC_PIN;
- }
- if (status.application.get(index).app_state.isPukRequired()) {
- return IccStatus.ICC_PUK;
- }
- if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) {
- return IccStatus.ICC_NETWORK_PERSONALIZATION;
- }
- if (status.application.get(index).app_state.isAppReady()) {
- return IccStatus.ICC_READY;
- }
- if (status.application.get(index).app_state.isAppNotReady()) {
- return IccStatus.ICC_NOT_READY;
- }
- return IccStatus.ICC_NOT_READY;
- }
-
- // Unrecognized ICC status. Treat it like a missing ICC.
- Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status);
- return IccStatus.ICC_ABSENT;
+ return status;
}
private Object
@@ -3035,7 +2984,7 @@
CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification();
notification.number = p.readString();
- notification.numberPresentation = p.readInt();
+ notification.numberPresentation = notification.presentationFromCLIP(p.readInt());
notification.name = p.readString();
notification.namePresentation = notification.numberPresentation;
notification.isPresent = p.readInt();
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 0763e63..90a82f9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -79,6 +79,14 @@
int CDM_TTY_HCO_MODE = 2;
int CDM_TTY_VCO_MODE = 3;
+ /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */
+ int SETUP_DATA_TECH_CDMA = 0;
+ int SETUP_DATA_TECH_GSM = 1;
+ int SETUP_DATA_AUTH_NONE = 0;
+ int SETUP_DATA_AUTH_PAP = 1;
+ int SETUP_DATA_AUTH_CHAP = 2;
+ int SETUP_DATA_AUTH_PAP_CHAP = 3;
+
/*
cat include/telephony/ril.h | \
egrep '^#define' | \
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
new file mode 100644
index 0000000..385b191
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -0,0 +1,392 @@
+/**
+ * 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 com.android.internal.telephony;
+
+import android.util.Log;
+import android.util.Pair;
+import android.text.TextUtils;
+
+import java.util.Random;
+import java.util.ArrayList;
+
+/**
+ * Retry manager allows a simple way to declare a series of
+ * retires timeouts. After creating a RetryManager the configure
+ * method is used to define the sequence. A simple linear series
+ * may be initialized using configure with three integer parameters
+ * The other configure method allows a series to be declared using
+ * a string.
+ *<p>
+ * The format of the configuration string is a series of parameters
+ * separated by a comma. There are two name value pair parameters plus a series
+ * of delay times. The units of of these delay times is unspecified.
+ * The name value pairs which may be specified are:
+ *<ul>
+ *<li>max_retries=<value>
+ *<li>default_randomizationTime=<value>
+ *</ul>
+ *<p>
+ * max_retries is the number of times that incrementRetryCount
+ * maybe called before isRetryNeeded will return false. if value
+ * is infinite then isRetryNeeded will always return true.
+ *
+ * default_randomizationTime will be used as the randomizationTime
+ * for delay times which have no supplied randomizationTime. If
+ * default_randomizationTime is not defined it defaults to 0.
+ *<p>
+ * The other parameters define The series of delay times and each
+ * may have an optional randomization value separated from the
+ * delay time by a colon.
+ *<p>
+ * Examples:
+ * <ul>
+ * <li>3 retires with no randomization value which means its 0:
+ * <ul><li><code>"1000, 2000, 3000"</code></ul>
+ *
+ * <li>10 retires with a 500 default randomization value for each and
+ * the 4..10 retries all using 3000 as the delay:
+ * <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul>
+ *
+ * <li>4 retires with a 100 as the default randomization value for the first 2 values and
+ * the other two having specified values of 500:
+ * <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul>
+ *
+ * <li>Infinite number of retires with the first one at 1000, the second at 2000 all
+ * others will be at 3000.
+ * <ul><li><code>"max_retries=infinite,1000,2000,3000</code></ul>
+ * </ul>
+ *
+ * {@hide}
+ */
+public class RetryManager {
+ static public final String LOG_TAG = "RetryManager";
+ static public final boolean DBG = false;
+ static public final int RETRYIES_NOT_STARTED = 0;
+ static public final int RETRYIES_ON_GOING = 1;
+ static public final int RETRYIES_COMPLETED = 2;
+
+ /**
+ * Retry record with times in milli-seconds
+ */
+ private static class RetryRec {
+ RetryRec(int delayTime, int randomizationTime) {
+ mDelayTime = delayTime;
+ mRandomizationTime = randomizationTime;
+ }
+
+ int mDelayTime;
+ int mRandomizationTime;
+ }
+
+ /** The array of retry records */
+ private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>();
+
+ /** When true isRetryNeeded() will always return true */
+ private boolean mRetryForever;
+
+ /**
+ * The maximum number of retries to attempt before
+ * isRetryNeeded returns false
+ */
+ private int mMaxRetryCount;
+
+ /** The current number of retires */
+ private int mRetryCount;
+
+ /** Random number generator */
+ private Random rng = new Random();
+
+ /** Constructor */
+ public RetryManager() {
+ if (DBG) log("constructor");
+ }
+
+ /**
+ * Configure for a simple linear sequence of times plus
+ * a random value.
+ *
+ * @param maxRetryCount is the maximum number of retries
+ * before isRetryNeeded returns false.
+ * @param retryTime is a time that will be returned by getRetryTime.
+ * @param randomizationTime a random value between 0 and
+ * randomizationTime will be added to retryTime. this
+ * parameter may be 0.
+ * @return true if successfull
+ */
+ public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
+ Pair<Boolean, Integer> value;
+
+ if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
+
+ if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) {
+ return false;
+ }
+
+ if (!validateNonNegativeInt("retryTime", retryTime)) {
+ return false;
+ }
+
+ if (!validateNonNegativeInt("randomizationTime", randomizationTime)) {
+ return false;
+ }
+
+ mMaxRetryCount = maxRetryCount;
+ resetRetryCount();
+ mRetryArray.clear();
+ mRetryArray.add(new RetryRec(retryTime, randomizationTime));
+
+ return true;
+ }
+
+ /**
+ * Configure for using string which allow arbitary
+ * sequences of times. See class comments for the
+ * string format.
+ *
+ * @return true if successfull
+ */
+ public boolean configure(String configStr) {
+ if (DBG) log("configure: '" + configStr + "'");
+
+ if (!TextUtils.isEmpty(configStr)) {
+ int defaultRandomization = 0;
+
+ if (DBG) log("configure: not empty");
+
+ mMaxRetryCount = 0;
+ resetRetryCount();
+ mRetryArray.clear();
+
+ String strArray[] = configStr.split(",");
+ for (int i = 0; i < strArray.length; i++) {
+ if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
+ Pair<Boolean, Integer> value;
+ String splitStr[] = strArray[i].split("=", 2);
+ splitStr[0] = splitStr[0].trim();
+ if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
+ if (splitStr.length > 1) {
+ splitStr[1] = splitStr[1].trim();
+ if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ if (TextUtils.equals(splitStr[0], "default_randomization")) {
+ value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+ if (!value.first) return false;
+ defaultRandomization = value.second;
+ } else if (TextUtils.equals(splitStr[0], "max_retries")) {
+ if (TextUtils.equals("infinite",splitStr[1])) {
+ mRetryForever = true;
+ } else {
+ value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+ if (!value.first) return false;
+ mMaxRetryCount = value.second;
+ }
+ } else {
+ Log.e(LOG_TAG, "Unrecognized configuration name value pair: "
+ + strArray[i]);
+ return false;
+ }
+ } else {
+ /**
+ * Assume a retry time with an optional randomization value
+ * following a ":"
+ */
+ splitStr = strArray[i].split(":", 2);
+ splitStr[0] = splitStr[0].trim();
+ RetryRec rr = new RetryRec(0, 0);
+ value = parseNonNegativeInt("delayTime", splitStr[0]);
+ if (!value.first) return false;
+ rr.mDelayTime = value.second;
+
+ // Check if optional randomization value present
+ if (splitStr.length > 1) {
+ splitStr[1] = splitStr[1].trim();
+ if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ value = parseNonNegativeInt("randomizationTime", splitStr[1]);
+ if (!value.first) return false;
+ rr.mRandomizationTime = value.second;
+ } else {
+ rr.mRandomizationTime = defaultRandomization;
+ }
+ mRetryArray.add(rr);
+ }
+ }
+ if (mRetryArray.size() > mMaxRetryCount) {
+ mMaxRetryCount = mRetryArray.size();
+ if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
+ }
+ if (DBG) log("configure: true");
+ return true;
+ } else {
+ if (DBG) log("configure: false it's empty");
+ return false;
+ }
+ }
+
+ /**
+ * Report whether data reconnection should be retried
+ *
+ * @return {@code true} if the max retires has not been reached. {@code
+ * false} otherwise.
+ */
+ public boolean isRetryNeeded() {
+ boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount);
+ if (DBG) log("isRetryNeeded: " + retVal);
+ return retVal;
+ }
+
+ /**
+ * Return the timer that should be used to trigger the data reconnection
+ */
+ public int getRetryTimer() {
+ int index;
+ if (mRetryCount < mRetryArray.size()) {
+ index = mRetryCount;
+ } else {
+ index = mRetryArray.size() - 1;
+ }
+
+ int retVal;
+ if ((index >= 0) && (index < mRetryArray.size())) {
+ retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index);
+ } else {
+ retVal = 0;
+ }
+
+ if (DBG) log("getRetryTimer: " + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return retry count
+ */
+ public int getRetryCount() {
+ if (DBG) log("getRetryCount: " + mRetryCount);
+ return mRetryCount;
+ }
+
+ /**
+ * Increase the retry counter, does not change retry forever.
+ */
+ public void increaseRetryCount() {
+ mRetryCount++;
+ if (mRetryCount > mMaxRetryCount) {
+ mRetryCount = mMaxRetryCount;
+ }
+ if (DBG) log("increseRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Set retry count to the specified value
+ * and turns off retrying forever.
+ */
+ public void setRetryCount(int count) {
+ mRetryCount = count;
+ if (mRetryCount > mMaxRetryCount) {
+ mRetryCount = mMaxRetryCount;
+ }
+
+ if (mRetryCount < 0) {
+ mRetryCount = 0;
+ }
+
+ mRetryForever = false;
+ if (DBG) log("setRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Reset network re-registration indicator and clear the data-retry counter
+ * and turns off retrying forever.
+ */
+ public void resetRetryCount() {
+ mRetryCount = 0;
+ mRetryForever = false;
+ if (DBG) log("resetRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Retry forever using last timeout time.
+ */
+ public void retryForeverUsingLastTimeout() {
+ mRetryCount = mMaxRetryCount;
+ mRetryForever = true;
+ if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount);
+ }
+
+ /**
+ * @return true if retrying forever
+ */
+ public boolean isRetryForever() {
+ if (DBG) log("isRetryForever: " + mRetryForever);
+ return mRetryForever;
+ }
+
+ /**
+ * Parse an integer validating the value is not negative.
+ *
+ * @param name
+ * @param stringValue
+ * @return Pair.first == true if stringValue an integer >= 0
+ */
+ private Pair<Boolean, Integer> parseNonNegativeInt(String name, String stringValue) {
+ int value;
+ Pair<Boolean, Integer> retVal;
+ try {
+ value = Integer.parseInt(stringValue);
+ retVal = new Pair<Boolean, Integer>(validateNonNegativeInt(name, value), value);
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, name + " bad value: " + stringValue, e);
+ retVal = new Pair<Boolean, Integer>(false, 0);
+ }
+ if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+ + retVal.first + ", " + retVal.second);
+ return retVal;
+ }
+
+ /**
+ * Validate an integer is >= 0 and logs an error if not
+ *
+ * @param name
+ * @param value
+ * @return Pair.first
+ */
+ private boolean validateNonNegativeInt(String name, int value) {
+ boolean retVal;
+ if (value < 0) {
+ Log.e(LOG_TAG, name + " bad value: is < 0");
+ retVal = false;
+ } else {
+ retVal = true;
+ }
+ if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
+ return retVal;
+ }
+
+ /**
+ * Return next random number for the index
+ */
+ private int nextRandomizationTime(int index) {
+ int randomTime = mRetryArray.get(index).mRandomizationTime;
+ if (randomTime == 0) {
+ return 0;
+ } else {
+ return rng.nextInt(randomTime);
+ }
+ }
+
+ private void log(String s) {
+ Log.d(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index 890ea63..d66c20b 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -445,7 +445,11 @@
} else if (tracker.mSentIntent != null) {
// Done retrying; return an error to the app.
try {
- tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
+ Intent fillIn = new Intent();
+ if (ar.result != null) {
+ fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode);
+ }
+ tracker.mSentIntent.send(mContext, RESULT_ERROR_GENERIC_FAILURE, fillIn);
} catch (CanceledException ex) {}
}
}
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index bdcf3f7..39806e9 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -77,7 +77,6 @@
// waiting period before recheck gprs and voice registration
public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
- public static final int MAX_NUM_DATA_STATE_READS = 15;
public static final int DATA_STATE_POLL_SLEEP_MS = 100;
//*****GSM events
@@ -116,6 +115,8 @@
protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34;
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/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 8b9ccb4..6177c8a 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -353,60 +353,30 @@
}
/**
- * Try to parse this message as an email gateway message -> Neither
- * of the standard ways are currently supported: There are two ways
- * specified in TS 23.040 Section 3.8 (not supported via this mechanism) -
- * SMS message "may have its TP-PID set for internet electronic mail - MT
+ * Try to parse this message as an email gateway message
+ * There are two ways specified in TS 23.040 Section 3.8 :
+ * - SMS message "may have its TP-PID set for internet electronic mail - MT
* SMS format: [<from-address><space>]<message> - "Depending on the
* nature of the gateway, the destination/origination address is either
* derived from the content of the SMS TP-OA or TP-DA field, or the
* TP-OA/TP-DA field contains a generic gateway address and the to/from
- * address is added at the beginning as shown above." - multiple addreses
- * separated by commas, no spaces - subject field delimited by '()' or '##'
- * and '#' Section 9.2.3.24.11
+ * address is added at the beginning as shown above." (which is supported here)
+ * - Multiple addreses separated by commas, no spaces, Subject field delimited
+ * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
*/
protected void extractEmailAddressFromMessageBody() {
- /*
- * a little guesswork here. I haven't found doc for this.
- * the format could be either
+ /* Some carriers may use " /" delimiter as below
*
* 1. [x@y][ ]/[subject][ ]/[body]
* -or-
* 2. [x@y][ ]/[body]
*/
- int slash = 0, slash2 = 0, atSymbol = 0;
-
- try {
- slash = messageBody.indexOf(" /");
- if (slash == -1) {
- return;
- }
-
- atSymbol = messageBody.indexOf('@');
- if (atSymbol == -1 || atSymbol > slash) {
- return;
- }
-
- emailFrom = messageBody.substring(0, slash);
-
- slash2 = messageBody.indexOf(" /", slash + 2);
-
- if (slash2 == -1) {
- pseudoSubject = null;
- emailBody = messageBody.substring(slash + 2);
- } else {
- pseudoSubject = messageBody.substring(slash + 2, slash2);
- emailBody = messageBody.substring(slash2 + 2);
- }
-
- isEmail = true;
- } catch (Exception ex) {
- Log.w(LOG_TAG,
- "extractEmailAddressFromMessageBody: exception slash="
- + slash + ", atSymbol=" + atSymbol + ", slash2="
- + slash2, ex);
- }
+ String[] parts = messageBody.split("( /)|( )", 2);
+ if (parts.length < 1 || parts[0].indexOf('@') == -1) return;
+ emailFrom = parts[0];
+ emailBody = parts[1];
+ isEmail = true;
}
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 02e9800..2216ec4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -220,28 +220,4 @@
*/
public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
= "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
-
- /**
- * Broadcast Action: The MDN changed during the CDMA OTA Process
- * The intent will have the following extra values:</p>
- * <ul>
- * <li><em>mdn</em> - An Integer of the updated MDN number.</li>
- * </ul>
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
- *
- * <p class="note">
- */
- // TODO(Moto): Generally broadcast intents are for use to allow entities which
- // may not know about each other to "communicate". This seems quite specific
- // and maybe using the registrant style would be better.
-
- // Moto: Since this is used for apps not in the same process of phone, can the
- // registrant style be used? (Ling Li says: Maybe the "app" can request rather
- // than save the MDN each time and this intent would not be necessary?)
- // Moto response: Moto internal discussion is on-going.
- public static final String ACTION_CDMA_OTA_MDN_CHANGED
- = "android.intent.action.ACTION_MDN_STATE_CHANGED";
-
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 5ec4020..60e0a44 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -109,4 +109,15 @@
/** The international dialing prefix conversion string */
static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring";
+
+ /**
+ * Defines the schema for the carrier specified OTASP number
+ */
+ static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema";
+
+ /**
+ * Disable all calls including Emergency call when it set to true.
+ */
+ static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call";
+
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 23eedfe..f0c0ea2 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -42,6 +42,7 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
@@ -73,15 +74,19 @@
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* {@hide}
*/
public class CDMAPhone extends PhoneBase {
static final String LOG_TAG = "CDMA";
- private static final boolean LOCAL_DEBUG = true;
+ private static final boolean DBG = true;
// Default Emergency Callback Mode exit timer
- private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000;
+ 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;
@@ -90,7 +95,6 @@
CdmaCallTracker mCT;
CdmaSMSDispatcher mSMS;
CdmaServiceStateTracker mSST;
- CdmaDataConnectionTracker mDataConnection;
RuimFileHandler mRuimFileHandler;
RuimRecords mRuimRecords;
RuimCard mRuimCard;
@@ -113,6 +117,8 @@
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.
private Runnable mExitEcmRunnable = new Runnable() {
@@ -168,6 +174,10 @@
String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
mIsPhoneInECMState = inEcm.equals("true");
+ // get the string that specifies the carrier OTA Sp number
+ mCarrierOtaSpNumSchema = SystemProperties.get(
+ TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
+
// Sets operator alpha property by retrieving from build-time system property
String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
@@ -233,7 +243,7 @@
}
protected void finalize() {
- if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized");
+ if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
}
@@ -358,42 +368,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!");
@@ -423,13 +402,17 @@
}
public String getCdmaPrlVersion(){
- return mRuimRecords.getPrlVersion();
+ return mSST.getPrlVersion();
}
- public String getCdmaMIN() {
+ public String getCdmaMin() {
return mSST.getCdmaMin();
}
+ public boolean isMinInfoReady() {
+ return mSST.isMinInfoReady();
+ }
+
public void getCallWaiting(Message onComplete) {
mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
}
@@ -466,10 +449,6 @@
return false;
}
- public String getInterfaceName(String apnType) {
- return mDataConnection.getInterfaceName();
- }
-
public CellLocation getCellLocation() {
return mSST.cellLoc;
}
@@ -509,10 +488,6 @@
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
}
- public String[] getDnsServers(String apnType) {
- return mDataConnection.getDnsServers();
- }
-
public IccCard getIccCard() {
return mRuimCard;
}
@@ -541,6 +516,14 @@
mCM.unregisterForCdmaOtaProvision(h);
}
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ mSST.registerForSubscriptionInfoReady(h, what, obj);
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ mSST.unregisterForSubscriptionInfoReady(h);
+ }
+
public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
mECMExitRespRegistrant = new Registrant (h, what, obj);
}
@@ -557,10 +540,6 @@
mCT.unregisterForCallWaiting(h);
}
- public String getIpAddress(String apnType) {
- return mDataConnection.getIpAddress();
- }
-
public void
getNeighboringCids(Message response) {
/*
@@ -674,14 +653,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");
}
@@ -808,19 +779,19 @@
}
/**
- * Notify any interested party of a Phone state change.
+ * Notify any interested party of a Phone state change {@link Phone.State}
*/
/*package*/ void notifyPhoneStateChanged() {
mNotifier.notifyPhoneState(this);
}
/**
- * Notifies registrants (ie, activities in the Phone app) about
- * changes to call state (including Phone and Connection changes).
+ * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
+ * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
*/
- /*package*/ void notifyCallStateChanged() {
+ /*package*/ void notifyPreciseCallStateChanged() {
/* we'd love it if this was package-scoped*/
- super.notifyCallStateChangedP();
+ super.notifyPreciseCallStateChangedP();
}
void notifyServiceStateChanged(ServiceState ss) {
@@ -927,6 +898,8 @@
}
// send an Intent
sendEmergencyCallbackModeChange();
+ // Re-initiate data connection
+ mDataConnection.setDataEnabled(true);
}
}
@@ -959,7 +932,7 @@
break;
}
- if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
+ if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
}
break;
@@ -1042,6 +1015,7 @@
onComplete.sendToTarget();
}
}
+ break;
default:{
throw new RuntimeException("unexpected event not handled");
@@ -1153,10 +1127,10 @@
mSMS.setCellBroadcastConfig(configValuesArray, response);
}
- public static final String IS683A_FEATURE_CODE = "*228" ;
- public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ;
- public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ;
- public static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
+ private static final String IS683A_FEATURE_CODE = "*228";
+ private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
+ private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
+ private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
private static final int IS683_CONST_800MHZ_A_BAND = 0;
private static final int IS683_CONST_800MHZ_B_BAND = 1;
@@ -1166,6 +1140,7 @@
private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
+ private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
private boolean isIs683OtaSpDialStr(String dialStr) {
int sysSelCodeInt;
@@ -1176,58 +1151,168 @@
if (dialStr.equals(IS683A_FEATURE_CODE)) {
isOtaspDialString = true;
}
- } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0,
- IS683A_FEATURE_CODE_NUM_DIGITS) == true)
- && (dialStrLen >=
- (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
- StringBuilder sb = new StringBuilder(dialStr);
- // Separate the System Selection Code into its own string
- char[] sysSel = new char[2];
- sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET);
- sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0);
-
- if ((PhoneNumberUtils.isISODigit(sysSel[0]))
- && (PhoneNumberUtils.isISODigit(sysSel[1]))) {
- String sysSelCode = new String(sysSel);
- sysSelCodeInt = Integer.parseInt((String)sysSelCode);
- switch (sysSelCodeInt) {
- case IS683_CONST_800MHZ_A_BAND:
- case IS683_CONST_800MHZ_B_BAND:
- case IS683_CONST_1900MHZ_A_BLOCK:
- case IS683_CONST_1900MHZ_B_BLOCK:
- case IS683_CONST_1900MHZ_C_BLOCK:
- case IS683_CONST_1900MHZ_D_BLOCK:
- case IS683_CONST_1900MHZ_E_BLOCK:
- case IS683_CONST_1900MHZ_F_BLOCK:
- isOtaspDialString = true;
- break;
-
- default:
- break;
- }
+ } else {
+ sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+ switch (sysSelCodeInt) {
+ case IS683_CONST_800MHZ_A_BAND:
+ case IS683_CONST_800MHZ_B_BAND:
+ case IS683_CONST_1900MHZ_A_BLOCK:
+ case IS683_CONST_1900MHZ_B_BLOCK:
+ case IS683_CONST_1900MHZ_C_BLOCK:
+ case IS683_CONST_1900MHZ_D_BLOCK:
+ case IS683_CONST_1900MHZ_E_BLOCK:
+ case IS683_CONST_1900MHZ_F_BLOCK:
+ isOtaspDialString = true;
+ break;
+ default:
+ break;
}
}
return isOtaspDialString;
}
+ /**
+ * This function extracts the system selection code from the dial string.
+ */
+ private int extractSelCodeFromOtaSpNum(String dialStr) {
+ int dialStrLen = dialStr.length();
+ int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
- /**
- * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
- * OTASP dial string.
- *
- * @param dialStr the number to look up.
- * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
- */
+ if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
+ 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
+ (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
+ IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
+ // Since we checked the condition above, the system selection code
+ // extracted from dialStr will not cause any exception
+ sysSelCodeInt = Integer.parseInt (
+ dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
+ IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
+ }
+ if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
+ return sysSelCodeInt;
+ }
+
+ /**
+ * This function checks if the system selection code extracted from
+ * the dial string "sysSelCodeInt' is the system selection code specified
+ * in the carrier ota sp number schema "sch".
+ */
+ private boolean
+ checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
+ boolean isOtaSpNum = false;
+ try {
+ // Get how many number of system selection code ranges
+ int selRc = Integer.parseInt((String)sch[1]);
+ for (int i = 0; i < selRc; i++) {
+ if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
+ int selMin = Integer.parseInt((String)sch[i+2]);
+ int selMax = Integer.parseInt((String)sch[i+3]);
+ // Check if the selection code extracted from the dial string falls
+ // within any of the range pairs specified in the schema.
+ if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
+ isOtaSpNum = true;
+ break;
+ }
+ }
+ }
+ } catch (NumberFormatException ex) {
+ // If the carrier ota sp number schema is not correct, we still allow dial
+ // and only log the error:
+ Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
+ }
+ return isOtaSpNum;
+ }
+
+ // Define the pattern/format for carrier specified OTASP number schema.
+ // It separates by comma and/or whitespace.
+ private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
+
+ /**
+ * The following function checks if a dial string is a carrier specified
+ * OTASP number or not by checking against the OTASP number schema stored
+ * in PROPERTY_OTASP_NUM_SCHEMA.
+ *
+ * Currently, there are 2 schemas for carriers to specify the OTASP number:
+ * 1) Use system selection code:
+ * The schema is:
+ * SELC,the # of code pairs,min1,max1,min2,max2,...
+ * e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
+ * selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
+ *
+ * 2) Use feature code:
+ * The schema is:
+ * "FC,length of feature code,feature code".
+ * e.g "FC,2,*2" indicates that the length of the feature code is 2,
+ * and the code itself is "*2".
+ */
+ private boolean isCarrierOtaSpNum(String dialStr) {
+ boolean isOtaSpNum = false;
+ int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+ if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
+ return isOtaSpNum;
+ }
+ // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
+ if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
+ Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
+ }
+
+ if (m.find()) {
+ String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
+ // If carrier uses system selection code mechanism
+ if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
+ if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
+ isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
+ }
+ }
+ } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
+ int fcLen = Integer.parseInt((String)sch[1]);
+ String fc = (String)sch[2];
+ if (dialStr.regionMatches(0,fc,0,fcLen)) {
+ isOtaSpNum = true;
+ } else {
+ if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
+ }
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
+ }
+ }
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
+ mCarrierOtaSpNumSchema);
+ }
+ }
+ } else {
+ if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
+ }
+ return isOtaSpNum;
+ }
+
+ /**
+ * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
+ * OTASP dial string.
+ *
+ * @param dialStr the number to look up.
+ * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
+ */
@Override
- public boolean isOtaSpNumber(String dialStr){
- boolean isOtaSpNum = false;
- if(dialStr != null){
- isOtaSpNum=isIs683OtaSpDialStr(dialStr);
- if(isOtaSpNum == false){
- //TO DO:Add carrier specific OTASP number detection here.
- }
- }
- return isOtaSpNum;
- }
+ public boolean isOtaSpNumber(String dialStr){
+ boolean isOtaSpNum = false;
+ String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr);
+ if (dialableStr != null) {
+ isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
+ if (isOtaSpNum == false) {
+ isOtaSpNum = isCarrierOtaSpNum(dialableStr);
+ }
+ }
+ if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
+ return isOtaSpNum;
+ }
@Override
public int getCdmaEriIconIndex() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
index e8724c2..c3bb01f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
@@ -24,6 +24,7 @@
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.DriverCall;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.Call.State;
/**
* {@hide}
@@ -186,6 +187,7 @@
cn.onHangupLocal();
}
+ state = State.DISCONNECTING;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index ed2ea90..be4763c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -222,7 +222,7 @@
}
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
return pendingMO;
}
@@ -262,6 +262,7 @@
// triggered by updateParent.
cwConn.updateParent(ringingCall, foregroundCall);
cwConn.onConnectedInOrOut();
+ updatePhoneState();
switchWaitingOrHoldingAndActive();
} else {
throw new CallStateException("phone not ringing");
@@ -305,7 +306,7 @@
internalClearDisconnected();
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
boolean
@@ -320,13 +321,16 @@
canDial() {
boolean ret;
int serviceState = phone.getServiceState().getState();
+ String disableCall = SystemProperties.get(
+ TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
- ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
- pendingMO == null
+ ret = (serviceState != ServiceState.STATE_POWER_OFF)
+ && pendingMO == null
&& !ringingCall.isRinging()
+ && !disableCall.equals("true")
&& (!foregroundCall.getState().isAlive()
- || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
- || !backgroundCall.getState().isAlive());
+ || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
+ || !backgroundCall.getState().isAlive());
return ret;
}
@@ -531,17 +535,6 @@
// Dropped connections are removed from the CallTracker
// list but kept in the Call list
connections[i] = null;
- } else if (conn != null && dc != null && !conn.compareTo(dc)) {
- // Connection in CLCC response does not match what
- // we were tracking. Assume dropped call and new call
-
- droppedDuringPoll.add(conn);
- connections[i] = new CdmaConnection (phone.getContext(), dc, this, i);
-
- if (connections[i].getCall() == ringingCall) {
- newRinging = connections[i];
- } // else something strange happened
- hasNonHangupStateChanged = true;
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
boolean changed;
changed = conn.update(dc);
@@ -644,7 +637,7 @@
}
if (hasNonHangupStateChanged || newRinging != null) {
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
//dumpState();
@@ -678,7 +671,8 @@
// the hangup reason is user ignoring or timing out. So conn.onDisconnect()
// is not called here. Instead, conn.onLocalDisconnect() is called.
conn.onLocalDisconnect();
- phone.notifyCallStateChanged();
+ updatePhoneState();
+ phone.notifyPreciseCallStateChanged();
return;
} else {
try {
@@ -760,6 +754,7 @@
}
call.onHangupLocal();
+ phone.notifyPreciseCallStateChanged();
}
/* package */
@@ -821,7 +816,7 @@
// the status of the call is after a call waiting is answered,
// 3 way call merged or a switch between calls.
foregroundCall.setGeneric(true);
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
private Phone.SuppService getFailedService(int what) {
@@ -865,6 +860,7 @@
// Create a new CdmaConnection which attaches itself to ringingCall.
ringingCall.setGeneric(false);
new CdmaConnection(phone.getContext(), cw, this, ringingCall);
+ updatePhoneState();
// Finally notify application
notifyCallWaitingInfo(cw);
@@ -926,7 +922,7 @@
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
droppedDuringPoll.clear();
break;
@@ -965,6 +961,7 @@
if (ar.exception == null) {
// Assume 3 way call is connected
pendingMO.onConnectedInOrOut();
+ pendingMO = null;
}
break;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
index 54dec48..f4119ad 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
@@ -16,12 +16,16 @@
package com.android.internal.telephony.cdma;
+import android.util.Log;
+import com.android.internal.telephony.Connection;
+
/**
* Represents a Supplementary Service Notification received from the network.
*
* {@hide}
*/
public class CdmaCallWaitingNotification {
+ static final String LOG_TAG = "CDMA";
public String number =null;
public int numberPresentation = 0;
public String name = null;
@@ -31,7 +35,6 @@
public int alertPitch = 0;
public int signal = 0;
-
public String toString()
{
return super.toString() + "Call Waiting Notification "
@@ -45,4 +48,17 @@
+ " signal: " + signal ;
}
+ public static int
+ presentationFromCLIP(int cli)
+ {
+ switch(cli) {
+ case 0: return Connection.PRESENTATION_ALLOWED;
+ case 1: return Connection.PRESENTATION_RESTRICTED;
+ case 2: return Connection.PRESENTATION_UNKNOWN;
+ default:
+ // This shouldn't happen, just log an error and treat as Unknown
+ Log.d(LOG_TAG, "Unexpected presentation " + cli);
+ return Connection.PRESENTATION_UNKNOWN;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
old mode 100644
new mode 100755
index 025382d..0c94e6a
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -161,8 +161,8 @@
isIncoming = false;
cnapName = null;
- cnapNamePresentation = 0;
- numberPresentation = 0;
+ cnapNamePresentation = Connection.PRESENTATION_ALLOWED;
+ numberPresentation = Connection.PRESENTATION_ALLOWED;
createTime = System.currentTimeMillis();
if (parent != null) {
@@ -435,8 +435,10 @@
} else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY
&& phone.getIccCard().getState() != RuimCard.State.READY) {
return DisconnectCause.ICC_ERROR;
- } else {
+ } else if (causeCode==CallFailCause.NORMAL_CLEARING) {
return DisconnectCause.NORMAL;
+ } else {
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
}
}
@@ -816,15 +818,12 @@
return c == PhoneNumberUtils.WAIT;
}
-
-
-
// This function is to find the next PAUSE character index if
// multiple pauses in a row. Otherwise it finds the next non PAUSE or
// non WAIT character index.
private static int
findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
- boolean wMatched = false;
+ boolean wMatched = isWait(phoneNumber.charAt(currIndex));
int index = currIndex + 1;
int length = phoneNumber.length();
while (index < length) {
@@ -861,17 +860,17 @@
// Append the PW char
ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT;
- // if there is a PAUSE in at the begining of PW character sequences, and this
- // PW character sequences has more than 2 PAUSE and WAIT Characters,skip P, append W
- if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 1))) {
+ // if there is a PAUSE in at the beginning of PW character sequences, and this
+ // PW character sequences has more than 2 PAUSE and WAIT Characters,skip PAUSE,
+ // append WAIT.
+ if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 2))) {
ret = PhoneNumberUtils.WAIT;
}
return ret;
}
-
/**
- * format orignal dial string
+ * format original dial string
* 1) convert international dialing prefix "+" to
* string specified per region
*
@@ -890,20 +889,10 @@
StringBuilder ret = new StringBuilder();
char c;
int currIndex = 0;
+
while (currIndex < length) {
c = phoneNumber.charAt(currIndex);
- if (PhoneNumberUtils.isDialable(c)) {
- if (c == '+') {
- String ps = null;
- SystemProperties.get(TelephonyProperties.PROPERTY_IDP_STRING, ps);
- if (TextUtils.isEmpty(ps)) {
- ps = "011";
- }
- ret.append(ps);
- } else {
- ret.append(c);
- }
- } else if (isPause(c) || isWait(c)) {
+ if (isPause(c) || isWait(c)) {
if (currIndex < length - 1) {
// if PW not at the end
int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex);
@@ -911,8 +900,10 @@
if (nextIndex < length) {
char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex);
ret.append(pC);
- // If PW char is immediately followed by non-PW char
- if (nextIndex > (currIndex + 1)) {
+ // If PW char sequence has more than 2 PW characters,
+ // skip to the last character since the sequence already be
+ // converted to WAIT character
+ if (nextIndex > (currIndex + 2)) {
currIndex = nextIndex - 1;
}
} else if (nextIndex == length) {
@@ -925,7 +916,7 @@
}
currIndex++;
}
- return ret.toString();
+ return PhoneNumberUtils.cdmaCheckAndProcessPlusCode(ret.toString());
}
private void log(String msg) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index fef6d3c..4588f36 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -143,9 +143,10 @@
lastFailTime = -1;
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
- phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE),
+ phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
- null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+ null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
+ obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index c3818f5..d02d33e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Checkin;
import android.telephony.ServiceState;
@@ -45,7 +46,9 @@
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnection.FailCause;
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;
@@ -54,15 +57,12 @@
* {@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;
// Indicates baseband will not auto-attach
private boolean noAutoAttach = false;
- long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- private boolean mReregisterOnReconnectFailure = false;
private boolean mIsScreenOn = true;
//useful for debugging
@@ -76,12 +76,6 @@
/** Currently active CdmaDataConnection */
private CdmaDataConnection mActiveDataConnection;
- /** 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];
-
/**
* Pool size of CdmaDataConnection objects.
*/
@@ -100,6 +94,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.
@@ -160,6 +159,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"));
@@ -180,13 +180,25 @@
// 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)) {
+ // Should never happen, log an error and default to a simple linear sequence.
+ Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+ + DEFAULT_DATA_RETRY_CONFIG);
+ mRetryMgr.configure(20, 2000, 1000);
+ }
+ }
}
public void dispose() {
- //Unregister from all events
+ // Unregister from all events
phone.mCM.unregisterForAvailable(this);
phone.mCM.unregisterForOffOrNotAvailable(this);
mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this);
@@ -198,6 +210,7 @@
mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this);
mCdmaPhone.mSST.unregisterForRoamingOn(this);
mCdmaPhone.mSST.unregisterForRoamingOff(this);
+ phone.mCM.unregisterForCdmaOtaProvision(this);
phone.getContext().unregisterReceiver(this.mIntentReceiver);
destroyAllDataConnectionList();
@@ -207,7 +220,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
@@ -224,39 +237,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;
}
/**
@@ -282,54 +289,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());
@@ -459,9 +418,7 @@
setState(State.CONNECTED);
phone.notifyDataConnection(reason);
startNetStatPoll();
- // reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
}
private void resetPollStats() {
@@ -489,7 +446,7 @@
protected void restartRadio() {
Log.d(LOG_TAG, "************TURN OFF RADIO**************");
- cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
+ cleanUpConnection(true, Phone.REASON_CDMA_DATA_DETACHED);
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),
@@ -617,21 +574,13 @@
private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
if (state == State.FAILED) {
- if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
- if (mReregisterOnReconnectFailure) {
- // We have already tried to re-register to the network.
- // This might be a problem with the data network.
- nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
- } else {
- // Try to Re-register to the network.
- Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
- mReregisterOnReconnectFailure = true;
- mCdmaPhone.mSST.reRegisterNetwork(null);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- return;
- }
- }
-
+ /**
+ * For now With CDMA we never try to reconnect on
+ * error and instead just continue to retry
+ * at the last time until the state is changed.
+ * TODO: Make this configurable?
+ */
+ int nextReconnectDelay = mRetryMgr.getRetryTimer();
Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
@@ -645,8 +594,7 @@
SystemClock.elapsedRealtime() + nextReconnectDelay,
mReconnectIntent);
- // double it for next time
- nextReconnectDelay *= 2;
+ mRetryMgr.increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
@@ -723,10 +671,7 @@
* @override com.android.internal.telephony.DataConnectionTracker
*/
protected void onRadioOffOrNotAvailable() {
- // Make sure our reconnect delay starts at the initial value
- // next time the radio comes on
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
if (phone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -773,6 +718,10 @@
reason = (String) ar.userObj;
}
setState(State.IDLE);
+
+ CdmaServiceStateTracker ssTracker = mCdmaPhone.mSST;
+ ssTracker.processPendingRadioPowerOffAfterDataOff();
+
phone.notifyDataConnection(reason);
if (retryAfterDisconnected(reason)) {
trySetupData(reason);
@@ -802,9 +751,7 @@
resetPollStats();
}
} else {
- // reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
}
@@ -840,7 +787,7 @@
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
int bsid = (loc != null) ? loc.getBaseStationId() : -1;
@@ -853,6 +800,22 @@
}
}
+ 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 writeEventLogCdmaDataDrop() {
CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
int bsid = (loc != null) ? loc.getBaseStationId() : -1;
@@ -905,28 +868,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();
}
@@ -961,6 +924,10 @@
onDataStateChanged((AsyncResult) msg.obj);
break;
+ case EVENT_CDMA_OTA_PROVISION:
+ onCdmaOtaProvision((AsyncResult) msg.obj);
+ break;
+
default:
// handle the message in the super class DataConnectionTracker
super.handleMessage(msg);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index ecdc8f6..88cccd3 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -19,18 +19,22 @@
import android.app.Activity;
import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.os.AsyncResult;
import android.os.Message;
+import android.os.SystemProperties;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.preference.PreferenceManager;
import android.util.Config;
import android.util.Log;
+import android.telephony.SmsManager;
+import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
@@ -43,6 +47,7 @@
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
+import java.lang.Boolean;
final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -75,13 +80,19 @@
return Intents.RESULT_SMS_GENERIC_ERROR;
}
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ if (inEcm.equals("true")) {
+ return Intents.RESULT_SMS_GENERIC_ERROR;
+ }
+
// Decode BD stream and set sms variables.
SmsMessage sms = (SmsMessage) smsb;
sms.parseSms();
int teleService = sms.getTeleService();
boolean handled = false;
- if (sms.getUserData() == null) {
+ if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService) &&
+ (SmsEnvelope.TELESERVICE_VMN != teleService)) {
if (Config.LOGD) {
Log.d(TAG, "Received SMS without user data");
}
@@ -92,10 +103,11 @@
return Intents.RESULT_SMS_HANDLED;
}
- if (SmsEnvelope.TELESERVICE_WAP == teleService){
+ if (SmsEnvelope.TELESERVICE_WAP == teleService) {
return processCdmaWapPdu(sms.getUserData(), sms.messageRef,
sms.getOriginatingAddress());
- } else if (SmsEnvelope.TELESERVICE_VMN == teleService) {
+ } else if ((SmsEnvelope.TELESERVICE_VMN == teleService) ||
+ (SmsEnvelope.TELESERVICE_MWI == teleService)) {
// handling Voicemail
int voicemailCount = sms.getNumOfVoicemails();
Log.d(TAG, "Voicemail count=" + voicemailCount);
@@ -323,6 +335,24 @@
sentIntent, deliveryIntent);
}
+ protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) {
+ String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
+ if (Boolean.parseBoolean(inEcm)) {
+ if (sentIntent != null) {
+ try {
+ sentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
+ } catch (CanceledException ex) {}
+ }
+ if (Config.LOGD) {
+ Log.d(TAG, "Block SMS in Emergency Callback mode");
+ }
+ return;
+ }
+
+ super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
+ }
+
/** {@inheritDoc} */
protected void sendSms(SmsTracker tracker) {
HashMap map = tracker.mData;
@@ -343,6 +373,12 @@
/** {@inheritDoc} */
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
// FIXME unit test leaves cm == null. this should change
+
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ if (inEcm.equals("true")) {
+ return;
+ }
+
if (mCm != null) {
mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 23a0520..b4de09b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -93,6 +93,7 @@
private int mRegistrationState = -1;
private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
+ private RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
// Sometimes we get the NITZ time before we know what country we are in.
// Keep the time zone information from the NITZ string so we can fix
@@ -121,13 +122,17 @@
private int curSpnRule = 0;
private String mMdn;
- private int mHomeSystemId;
- private int mHomeNetworkId;
+ private int mHomeSystemId[] = null;
+ private int mHomeNetworkId[] = null;
private String mMin;
+ private String mPrlVersion;
+ private boolean mIsMinInfoReady = false;
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;
@@ -175,6 +180,7 @@
cm.registerForNVReady(this, EVENT_NV_READY, null);
phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null);
+ cm.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
// system setting property AIRPLANE_MODE_ON is set in Settings.
int airplaneMode = Settings.System.getInt(
@@ -198,6 +204,7 @@
cm.unregisterForNetworkStateChanged(this);
cm.unregisterForRUIMReady(this);
cm.unregisterForNVReady(this);
+ cm.unregisterForCdmaOtaProvision(this);
phone.unregisterForEriFileLoaded(this);
phone.mRuimRecords.unregisterForRecordsLoaded(this);
cm.unSetOnSignalStrengthUpdate(this);
@@ -261,6 +268,25 @@
cdmaDataConnectionDetachedRegistrants.remove(h);
}
+ /**
+ * Registration point for subscription info ready
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ cdmaForSubscriptionInfoReadyRegistrants.add(r);
+
+ if (isMinInfoReady()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ cdmaForSubscriptionInfoReadyRegistrants.remove(h);
+ }
+
//***** Called from CDMAPhone
public void
getLacAndCid(Message onComplete) {
@@ -290,6 +316,10 @@
EVENT_RUIM_RECORDS_LOADED, null);
mNeedToRegForRuimLoaded = false;
}
+
+ cm.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
+ if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
+
// restore the previous network selection.
pollState();
@@ -299,6 +329,10 @@
case EVENT_NV_READY:
isSubscriptionFromRuim = false;
+ // For Non-RUIM phones, the subscription information is stored in
+ // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
+ // subscription info.
+ cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
@@ -376,11 +410,59 @@
case EVENT_POLL_STATE_REGISTRATION_CDMA:
case EVENT_POLL_STATE_OPERATOR_CDMA:
- case EVENT_POLL_STATE_CDMA_SUBSCRIPTION:
ar = (AsyncResult) msg.obj;
handlePollStateResult(msg.what, ar);
break;
+ case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ String cdmaSubscription[] = (String[])ar.result;
+ if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
+ mMdn = cdmaSubscription[0];
+ if (cdmaSubscription[1] != null) {
+ String[] sid = cdmaSubscription[1].split(",");
+ mHomeSystemId = new int[sid.length];
+ for (int i = 0; i < sid.length; i++) {
+ try {
+ mHomeSystemId[i] = Integer.parseInt(sid[i]);
+ } catch (NumberFormatException ex) {
+ Log.e(LOG_TAG, "error parsing system id: ", ex);
+ }
+ }
+ }
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION SID=" + cdmaSubscription[1] );
+
+ if (cdmaSubscription[2] != null) {
+ String[] nid = cdmaSubscription[2].split(",");
+ mHomeNetworkId = new int[nid.length];
+ for (int i = 0; i < nid.length; i++) {
+ try {
+ mHomeNetworkId[i] = Integer.parseInt(nid[i]);
+ } catch (NumberFormatException ex) {
+ Log.e(LOG_TAG, "error parsing network id: ", ex);
+ }
+ }
+ }
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION NID=" + cdmaSubscription[2] );
+ mMin = cdmaSubscription[3];
+ mPrlVersion = cdmaSubscription[4];
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn);
+ //Notify apps subscription info is ready
+ if (cdmaForSubscriptionInfoReadyRegistrants != null) {
+ cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
+ }
+ if (!mIsMinInfoReady) {
+ mIsMinInfoReady = true;
+ }
+ } else {
+ Log.w(LOG_TAG,"error parsing cdmaSubscription params num="
+ + cdmaSubscription.length);
+ }
+ }
+ break;
+
case EVENT_POLL_SIGNAL_STRENGTH:
// Just poll signal strength...not part of pollState()
@@ -427,6 +509,29 @@
pollState();
break;
+ case EVENT_OTA_PROVISION_STATUS_CHANGE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ ints = (int[]) ar.result;
+ int otaStatus = ints[0];
+ if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED
+ || otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
+ Log.d(LOG_TAG, "Received OTA_PROGRAMMING Complete,Reload MDN ");
+ cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
+ }
+ }
+ 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;
@@ -455,19 +560,23 @@
msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
dcTracker.sendMessage(msg);
- // Poll data state up to 15 times, with a 100ms delay
- // totaling 1.5 sec. Normal data disable action will finish in 100ms.
- for (int i = 0; i < MAX_NUM_DATA_STATE_READS; 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
}
@@ -589,7 +698,10 @@
}
mRegistrationState = registrationState;
- mCdmaRoaming = regCodeIsRoaming(registrationState);
+ // mCdmaRoaming is true when registration state is roaming and TSB58 roaming
+ // indicator is not in the carrier-specified list of ERIs for home system
+ mCdmaRoaming =
+ regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
newSS.setState (regCodeToServiceState(registrationState));
this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
@@ -636,27 +748,6 @@
}
break;
- case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
- String cdmaSubscription[] = (String[])ar.result;
-
- if (cdmaSubscription != null && cdmaSubscription.length >= 4) {
- mMdn = cdmaSubscription[0];
- // TODO: Only grabbing the first SID/NID for now.
- if (cdmaSubscription[1] != null) {
- String[] sid = cdmaSubscription[1].split(",");
- mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0;
- }
- if (cdmaSubscription[2] != null) {
- String[] nid = cdmaSubscription[2].split(",");
- mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0;
- }
- mMin = cdmaSubscription[3];
-
- } else {
- Log.w(LOG_TAG, "error parsing cdmaSubscription");
- }
- break;
-
default:
Log.e(LOG_TAG, "RIL response handle in wrong phone!"
+ " Expected CDMA RIL request and get GSM RIL request.");
@@ -672,7 +763,7 @@
if (pollingContext[0] == 0) {
boolean namMatch = false;
- if ((mHomeSystemId != 0) && (mHomeSystemId == newSS.getSystemId()) ) {
+ if (!isSidsAllZeros() && isHomeSid(newSS.getSystemId())) {
namMatch = true;
}
@@ -684,33 +775,43 @@
}
// Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
- // TODO(Teleca): Validate this is correct.
- if (mIsInPrl) {
- if (namMatch && (mRoamingIndicator <= 2)) {
- // System is acquired, prl match, nam match and mRoamingIndicator <= 2
- newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
- } else {
- // System is acquired, prl match, no nam match or mRoamingIndicator > 2
- newSS.setCdmaRoamingIndicator(mRoamingIndicator);
- }
- } else {
- if (mRegistrationState == 5) {
- // System is acquired but prl not loaded or no prl match
+ newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+ boolean isPrlLoaded = true;
+ if (TextUtils.isEmpty(mPrlVersion)) {
+ isPrlLoaded = false;
+ }
+ if (!isPrlLoaded) {
+ newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+ } else if (!isSidsAllZeros()) {
+ if (!namMatch && !mIsInPrl) {
+ // Use default
+ newSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
+ } else if (namMatch && !mIsInPrl) {
newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+ } else if (!namMatch && mIsInPrl) {
+ // Use the one from PRL/ERI
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
} else {
- // Use the default indicator
+ // It means namMatch && mIsInPrl
+ if ((mRoamingIndicator <= 2)) {
+ newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
+ } else {
+ // Use the one from PRL/ERI
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+ }
}
}
- newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
// NOTE: Some operator may require to override the mCdmaRoaming (set by the modem)
// depending on the mRoamingIndicator.
if (DBG) {
log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator()
- + ". mCdmaRoaming = " + mCdmaRoaming + ", namMatch = " + namMatch
- + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator
+ + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded
+ + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
+ + ", mRoamingIndicator = " + mRoamingIndicator
+ ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
}
pollStateDone();
@@ -773,11 +874,6 @@
// are allowed to arrive out-of-order
pollingContext[0]++;
- // RIL_REQUEST_CDMA_SUBSCRIPTION is necessary for CDMA
- cm.getCDMASubscription(
- obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION, pollingContext));
-
- pollingContext[0]++;
// RIL_REQUEST_OPERATOR is necessary for CDMA
cm.getOperator(
obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
@@ -972,7 +1068,7 @@
cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
}
- if (hasCdmaDataConnectionChanged) {
+ if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
phone.notifyDataConnection(null);
}
@@ -1047,7 +1143,7 @@
/**
* send signal-strength-changed notification if changed
- * Called both for solicited and unsolicited signal stength updates
+ * Called both for solicited and unsolicited signal strength updates
*/
private void
onSignalStrengthResult(AsyncResult ar) {
@@ -1060,15 +1156,15 @@
int[] ints = (int[])ar.result;
int offset = 2;
- int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -1;
- int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -1;
+ int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
+ int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -160;
int evdoRssi = -1;
int evdoEcio = -1;
int evdoSnr = -1;
if ((networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
|| (networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
- evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -1;
+ evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -120;
evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1;
evdoSnr = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1;
}
@@ -1152,6 +1248,33 @@
}
/**
+ * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
+ * home system
+ *
+ * @param roamInd roaming indicator in String
+ * @return true if the roamInd is in the carrier-specified list of ERIs for home network
+ */
+ private boolean isRoamIndForHomeSystem(String roamInd) {
+ // retrieve the carrier-specified list of ERIs for home system
+ String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem");
+
+ if (!TextUtils.isEmpty(homeRoamIndcators)) {
+ // searches through the comma-separated list for a match,
+ // return true if one is found.
+ for (String homeRoamInd : homeRoamIndcators.split(",")) {
+ if (homeRoamInd.equals(roamInd)) {
+ return true;
+ }
+ }
+ // no matches found against the list!
+ return false;
+ }
+
+ // no system property found for the roaming indicators for home system
+ return false;
+ }
+
+ /**
* Set roaming state when cdmaRoaming is true and ons is different from spn
* @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
* @param s ServiceState hold current ons
@@ -1396,6 +1519,31 @@
}
}
+ private boolean isSidsAllZeros() {
+ if (mHomeSystemId != null) {
+ for (int i=0; i < mHomeSystemId.length; i++) {
+ if (mHomeSystemId[i] != 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check whether a specified system ID that matches one of the home system IDs.
+ */
+ private boolean isHomeSid(int sid) {
+ if (mHomeSystemId != null) {
+ for (int i=0; i < mHomeSystemId.length; i++) {
+ if (sid == mHomeSystemId[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* @return true if phone is camping on a technology
* that could support voice and data simultaneously.
@@ -1420,6 +1568,11 @@
return mMin;
}
+ /** Returns null if NV is not yet ready */
+ public String getPrlVersion() {
+ return mPrlVersion;
+ }
+
/**
* Returns IMSI as MCC + MNC + MIN
*/
@@ -1435,4 +1588,31 @@
return null;
}
}
+
+ /**
+ * Check if subscription data has been assigned to mMin
+ *
+ * return true if MIN info is ready; false otherwise.
+ */
+ 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/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 9d9f479..734badd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -16,507 +16,34 @@
package com.android.internal.telephony.cdma;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import android.app.ActivityManagerNative;
-import android.content.Intent;
-import android.content.res.Configuration;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
/**
* Note: this class shares common code with SimCard, consider a base class to minimize code
* duplication.
* {@hide}
*/
-public final class RuimCard extends Handler implements IccCard {
- static final String LOG_TAG="CDMA";
-
- //***** Instance Variables
- private static final boolean DBG = true;
-
- private CDMAPhone phone;
-
- private CommandsInterface.IccStatus status = null;
- private boolean mDesiredPinLocked;
- private boolean mDesiredFdnEnabled;
- private boolean mRuimPinLocked = true; // default to locked
- private boolean mRuimFdnEnabled = false; // Default to disabled.
- // Will be updated when RUIM_READY.
-// //***** Constants
-
-// // FIXME I hope this doesn't conflict with the Dialer's notifications
-// Nobody is using this at the moment
-// static final int NOTIFICATION_ID_ICC_STATUS = 33456;
-
- //***** Event Constants
-
- static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1;
- static final int EVENT_GET_RUIM_STATUS_DONE = 2;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
- static final int EVENT_PINPUK_DONE = 4;
- static final int EVENT_REPOLL_STATUS_DONE = 5;
- static final int EVENT_RUIM_READY = 6;
- static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
- static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
- static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9;
- static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
- static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
- //***** Constructor
+public final class RuimCard extends IccCard {
RuimCard(CDMAPhone phone) {
- this.phone = phone;
-
- phone.mCM.registerForRUIMLockedOrAbsent(
- this, EVENT_RUIM_LOCKED_OR_ABSENT, null);
-
- phone.mCM.registerForOffOrNotAvailable(
- this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
- phone.mCM.registerForRUIMReady(
- this, EVENT_RUIM_READY, null);
-
+ super(phone, "CDMA", true);
+ mPhone.mCM.registerForRUIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+ mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mPhone.mCM.registerForRUIMReady(mHandler, EVENT_ICC_READY, null);
updateStateProperty();
}
- //***** RuimCard implementation
-
- public State
- getState() {
- if (status == null) {
- switch(phone.mCM.getRadioState()) {
- /* This switch block must not return anything in
- * State.isLocked() or State.ABSENT.
- * If it does, handleSimStatus() may break
- */
- case RADIO_OFF:
- case RADIO_UNAVAILABLE:
- case RUIM_NOT_READY:
- return State.UNKNOWN;
- case RUIM_LOCKED_OR_ABSENT:
- //this should be transient-only
- return State.UNKNOWN;
- case RUIM_READY:
- return State.READY;
- case NV_READY:
- case NV_NOT_READY:
- return State.ABSENT;
- }
- } else {
- switch (status) {
- case ICC_ABSENT: return State.ABSENT;
- case ICC_NOT_READY: return State.UNKNOWN;
- case ICC_READY: return State.READY;
- case ICC_PIN: return State.PIN_REQUIRED;
- case ICC_PUK: return State.PUK_REQUIRED;
- case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
- }
- }
-
- Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached");
- return State.UNKNOWN;
- }
-
+ @Override
public void dispose() {
//Unregister for all events
- phone.mCM.unregisterForRUIMLockedOrAbsent(this);
- phone.mCM.unregisterForOffOrNotAvailable(this);
- phone.mCM.unregisterForRUIMReady(this);
+ mPhone.mCM.unregisterForRUIMLockedOrAbsent(mHandler);
+ mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+ mPhone.mCM.unregisterForRUIMReady(mHandler);
}
- protected void finalize() {
- if(DBG) Log.d(LOG_TAG, "RuimCard finalized");
- }
-
- private RegistrantList absentRegistrants = new RegistrantList();
- private RegistrantList pinLockedRegistrants = new RegistrantList();
- private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
- public void registerForAbsent(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- absentRegistrants.add(r);
-
- if (getState() == State.ABSENT) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForAbsent(Handler h) {
- absentRegistrants.remove(h);
- }
-
- public void registerForNetworkLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- networkLockedRegistrants.add(r);
-
- if (getState() == State.NETWORK_LOCKED) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForNetworkLocked(Handler h) {
- networkLockedRegistrants.remove(h);
- }
-
- public void registerForLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- pinLockedRegistrants.add(r);
-
- if (getState().isPinLocked()) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForLocked(Handler h) {
- pinLockedRegistrants.remove(h);
- }
-
- public void supplyPin (String pin, Message onComplete) {
- phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk (String puk, String newPin, Message onComplete) {
- phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPin2 (String pin2, Message onComplete) {
- phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
- phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyNetworkDepersonalization (String pin, Message onComplete) {
- if(DBG) log("Network Despersonalization: " + pin);
- phone.mCM.supplyNetworkDepersonalization(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public boolean getIccLockEnabled() {
- return mRuimPinLocked;
- }
-
- public boolean getIccFdnEnabled() {
- return mRuimFdnEnabled;
- }
-
- public void setIccLockEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- mDesiredPinLocked = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
- }
-
- public void setIccFdnEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX +
- CommandsInterface.SERVICE_CLASS_SMS;
-
- mDesiredFdnEnabled = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
- }
-
- public void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
- }
-
- public void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin2(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
- }
-
- public String getServiceProviderName() {
- return phone.mRuimRecords.getServiceProviderName();
- }
-
- //***** Handler implementation
@Override
- public void handleMessage(Message msg){
- AsyncResult ar;
- int serviceClassX;
-
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- switch (msg.what) {
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
- status = null;
- updateStateProperty();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null);
- break;
- case EVENT_RUIM_READY:
- Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received");
- //TODO: put facility read in SIM_READY now, maybe in REG_NW
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
- break;
- case EVENT_RUIM_LOCKED_OR_ABSENT:
- Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received");
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- break;
- case EVENT_GET_RUIM_STATUS_DONE:
- Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received");
- ar = (AsyncResult)msg.obj;
-
- getRuimStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received");
- // a PIN/PUK/PIN2/PUK2/Network Personalization
- // request has completed. ar.userObj is the response Message
- // Repoll before returning
- ar = (AsyncResult)msg.obj;
- // TODO should abstract these exceptions
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- phone.mCM.getIccStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received");
- // Finished repolling status after PIN operation
- // ar.userObj is the response messaeg
- // ar.userObj.obj is already an AsyncResult with an
- // appropriate exception filled in if applicable
-
- ar = (AsyncResult)msg.obj;
- getRuimStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_QUERY_FACILITY_LOCK_DONE:
- Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received");
- ar = (AsyncResult)msg.obj;
- onQueryFacilityLock(ar);
- break;
- case EVENT_QUERY_FACILITY_FDN_DONE:
- Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received");
- ar = (AsyncResult)msg.obj;
- onQueryFdnEnabled(ar);
- break;
- case EVENT_CHANGE_FACILITY_LOCK_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received");
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mRuimPinLocked = mDesiredPinLocked;
- if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
- "mRuimPinLocked= " + mRuimPinLocked);
- } else {
- Log.e(LOG_TAG, "Error change facility lock with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_FACILITY_FDN_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received");
- ar = (AsyncResult)msg.obj;
-
- if (ar.exception == null) {
- mRuimFdnEnabled = mDesiredFdnEnabled;
- if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
- "mRuimFdnEnabled=" + mRuimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "Error change facility fdn with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_RUIM_PASSWORD_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received");
- ar = (AsyncResult)msg.obj;
- if(ar.exception != null) {
- Log.e(LOG_TAG, "Error in change sim password with exception"
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- default:
- Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what);
- }
+ public String getServiceProviderName () {
+ return ((CDMAPhone)mPhone).mRuimRecords.getServiceProviderName();
}
-
- //***** Private methods
-
- /**
- * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFacilityLock(AsyncResult ar) {
- if(ar.exception != null) {
- if (DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mRuimPinLocked = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mRuimPinLocked);
- } else {
- Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
- }
- }
-
- /**
- * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFdnEnabled(AsyncResult ar) {
- if(ar.exception != null) {
- if(DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mRuimFdnEnabled = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mRuimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
- }
- }
-
- private void
- getRuimStatusDone(AsyncResult ar) {
- if (ar.exception != null) {
- Log.e(LOG_TAG,"Error getting SIM status. "
- + "RIL_REQUEST_GET_SIM_STATUS should "
- + "never return an error", ar.exception);
- return;
- }
-
- CommandsInterface.IccStatus newStatus
- = (CommandsInterface.IccStatus) ar.result;
-
- handleRuimStatus(newStatus);
- }
-
- private void
- handleRuimStatus(CommandsInterface.IccStatus newStatus) {
- boolean transitionedIntoPinLocked;
- boolean transitionedIntoAbsent;
- boolean transitionedIntoNetworkLocked;
-
- RuimCard.State oldState, newState;
-
- oldState = getState();
- status = newStatus;
- newState = getState();
-
- updateStateProperty();
-
- transitionedIntoPinLocked = (
- (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
- || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
- transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
- transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
- && newState == State.NETWORK_LOCKED);
-
- if (transitionedIntoPinLocked) {
- if(DBG) log("Notify RUIM pin or puk locked.");
- pinLockedRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
- (newState == State.PIN_REQUIRED) ?
- INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
- } else if (transitionedIntoAbsent) {
- if(DBG) log("Notify RUIM missing.");
- absentRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null);
- } else if (transitionedIntoNetworkLocked) {
- if(DBG) log("Notify RUIM network locked.");
- networkLockedRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
- INTENT_VALUE_LOCKED_NETWORK);
- }
- }
-
- public void broadcastRuimStateChangedIntent(String value, String reason) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
- intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value);
- intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason);
- if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value
- + " reason " + reason);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
- }
-
- public void updateImsiConfiguration(String imsi) {
- if (imsi.length() >= 6) {
- Configuration config = new Configuration();
- config.mcc = ((imsi.charAt(0)-'0')*100)
- + ((imsi.charAt(1)-'0')*10)
- + (imsi.charAt(2)-'0');
- config.mnc = ((imsi.charAt(3)-'0')*100)
- + ((imsi.charAt(4)-'0')*10)
- + (imsi.charAt(5)-'0');
- try {
- ActivityManagerNative.getDefault().updateConfiguration(config);
- } catch (RemoteException e) {
- }
- }
- }
-
- private void
- updateStateProperty() {
- phone.setSystemProperty(
- TelephonyProperties.PROPERTY_SIM_STATE,
- getState().toString());
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[RuimCard] " + msg);
- }
-}
+ }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 55f48b1..7c74314 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -37,10 +37,6 @@
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import android.app.ActivityManagerNative;
-import android.content.Intent;
-
/**
* {@hide}
@@ -65,7 +61,6 @@
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
private static final int EVENT_GET_ICCID_DONE = 5;
- private static final int EVENT_NV_READY = 9;
private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
private static final int EVENT_UPDATE_DONE = 14;
private static final int EVENT_GET_SST_DONE = 17;
@@ -76,7 +71,7 @@
private static final int EVENT_GET_SMS_DONE = 22;
private static final int EVENT_RUIM_REFRESH = 31;
- private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32;
+
RuimRecords(CDMAPhone p) {
super(p);
@@ -90,14 +85,12 @@
p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null);
- p.mCM.registerForNVReady(this, EVENT_NV_READY, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
// NOTE the EVENT_SMS_ON_RUIM is not registered
p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null);
// Start off by setting empty state
onRadioOffOrNotAvailable();
- p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
}
@@ -106,8 +99,6 @@
phone.mCM.unregisterForRUIMReady(this);
phone.mCM.unregisterForOffOrNotAvailable( this);
phone.mCM.unSetOnIccRefresh(this);
- phone.mCM.unregisterForNVReady(this);
- phone.mCM.unregisterForCdmaOtaProvision(this);
}
@Override
@@ -202,9 +193,7 @@
case EVENT_RUIM_READY:
onRuimReady();
break;
- case EVENT_NV_READY:
- onNvReady();
- break;
+
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
onRadioOffOrNotAvailable();
break;
@@ -221,15 +210,7 @@
if (ar.exception != null) {
break;
}
- if (m_ota_commited) {
- if (mMyMobileNumber != localTemp[0]) {
- Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED);
- intent.putExtra("mdn", localTemp[0]);
- Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA ");
- ActivityManagerNative.broadcastStickyIntent(intent, null);
- }
- m_ota_commited = false;
- }
+
mMyMobileNumber = localTemp[0];
mMin2Min1 = localTemp[3];
mPrlVersion = localTemp[4];
@@ -281,21 +262,6 @@
}
break;
- case EVENT_OTA_PROVISION_STATUS_CHANGE:
- m_ota_commited=false;
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- int[] ints = (int[]) ar.result;
- int otaStatus = ints[0];
- if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) {
- m_ota_commited=true;
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
- } else if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
- }
- }
- break;
-
}}catch (RuntimeException exc) {
// I don't want these exceptions to be fatal
Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
@@ -329,7 +295,7 @@
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
- ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+ ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
RuimCard.INTENT_VALUE_ICC_LOADED, null);
}
@@ -338,7 +304,7 @@
READY is sent before IMSI ready
*/
- ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+ ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
RuimCard.INTENT_VALUE_ICC_READY, null);
fetchRuimRecords();
@@ -347,10 +313,6 @@
}
- private void onNvReady() {
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
-
- }
private void fetchRuimRecords() {
recordsRequested = true;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
index 44958e9..4b88057 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
@@ -35,7 +35,12 @@
static public final int IS95_CONST_IR_ALERT_MED = 0;
static public final int IS95_CONST_IR_ALERT_HIGH = 1;
static public final int IS95_CONST_IR_ALERT_LOW = 2;
- static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 255;
+
+ // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal,
+ // set TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN to 0 to avoid
+ // the alert pitch to be involved in hash calculation for
+ // signal type other than IS54B.
+ static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 0;
// public final int int IS95_CONST_IR_SIGNAL_TYPE;
static public final int IS95_CONST_IR_SIG_ISDN_NORMAL = 0;
@@ -81,6 +86,15 @@
(alertPitch < 0) || (signal > 256) || (signal < 0)) {
return new Integer(CDMA_INVALID_TONE);
}
+ // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal,
+ // the alert pitch field is ignored by the mobile station unless
+ // SIGNAL_TYPE is '10',IS-54B Alerting.
+ // Set alert pitch to TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN
+ // so the alert pitch is not involved in hash calculation
+ // when signal type is not IS-54B.
+ if (signalType != IS95_CONST_IR_SIGNAL_IS54B) {
+ alertPitch = TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN;
+ }
return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
old mode 100644
new mode 100755
index 3a92064..9c04305
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -518,6 +518,7 @@
originatingAddress = addr;
env.origAddress = addr;
mEnvelope = env;
+ mPdu = pdu;
parseSms();
}
@@ -526,6 +527,19 @@
* Parses a SMS message from its BearerData stream. (mobile-terminated only)
*/
protected void parseSms() {
+ // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
+ // It contains only an 8-bit number with the number of messages waiting
+ if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) {
+ mBearerData = new BearerData();
+ if (mEnvelope.bearerData != null) {
+ mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0];
+ }
+ if (Config.DEBUG) {
+ Log.d(LOG_TAG, "parseSms: get MWI " +
+ Integer.toString(mBearerData.numberOfMessages));
+ }
+ return;
+ }
mBearerData = BearerData.decode(mEnvelope.bearerData);
messageRef = mBearerData.messageId;
if (mBearerData.userData != null) {
@@ -583,23 +597,6 @@
}
}
- private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) {
- // see C.S0015-B, v2.0, 3.4.3.3
- CdmaSmsAddress addr = new CdmaSmsAddress();
- addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
- try {
- addr.origBytes = addrStr.getBytes("UTF-8");
- } catch (java.io.UnsupportedEncodingException ex) {
- Log.e(LOG_TAG, "CDMA address parsing failed: " + ex);
- return null;
- }
- addr.numberOfDigits = (byte)addr.origBytes.length;
- addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
- addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
- addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP;
- return addr;
- }
-
/**
* Set the nextMessageId to a random value between 0 and 65536
* See C.S0015-B, v2.0, 4.3.1.5
@@ -626,7 +623,13 @@
* TODO(cleanup): give this function a more meaningful name.
*/
- CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr);
+ /**
+ * TODO(cleanup): Make returning null from the getSubmitPdu
+ * variations meaningful -- clean up the error feedback
+ * mechanism, and avoid null pointer exceptions.
+ */
+
+ CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr);
if (destAddr == null) return null;
BearerData bearerData = new BearerData();
@@ -728,9 +731,8 @@
dos.close();
/**
- * TODO(cleanup) -- This is the only place where mPdu is
- * defined, and this is not obviously the only place where
- * it needs to be defined. It would be much nicer if
+ * TODO(cleanup) -- The mPdu field is managed in
+ * a fragile manner, and it would be much nicer if
* accessing the serialized representation used a less
* fragile mechanism. Maybe the getPdu method could
* generate a representation if there was not yet one?
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 ef3afff..fefeb12 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -233,22 +233,22 @@
public static TimeStamp fromByteArray(byte[] data) {
TimeStamp ts = new TimeStamp();
// C.S0015-B v2.0, 4.5.4: range is 1996-2095
- int year = IccUtils.beBcdByteToInt(data[0]);
+ int year = IccUtils.cdmaBcdByteToInt(data[0]);
if (year > 99 || year < 0) return null;
ts.year = year >= 96 ? year + 1900 : year + 2000;
- int month = IccUtils.beBcdByteToInt(data[1]);
+ int month = IccUtils.cdmaBcdByteToInt(data[1]);
if (month < 1 || month > 12) return null;
ts.month = month - 1;
- int day = IccUtils.beBcdByteToInt(data[2]);
+ int day = IccUtils.cdmaBcdByteToInt(data[2]);
if (day < 1 || day > 31) return null;
ts.monthDay = day;
- int hour = IccUtils.beBcdByteToInt(data[3]);
+ int hour = IccUtils.cdmaBcdByteToInt(data[3]);
if (hour < 0 || hour > 23) return null;
ts.hour = hour;
- int minute = IccUtils.beBcdByteToInt(data[4]);
+ int minute = IccUtils.cdmaBcdByteToInt(data[4]);
if (minute < 0 || minute > 59) return null;
ts.minute = minute;
- int second = IccUtils.beBcdByteToInt(data[5]);
+ int second = IccUtils.cdmaBcdByteToInt(data[5]);
if (second < 0 || second > 59) return null;
ts.second = second;
return ts;
@@ -455,53 +455,114 @@
}
}
- private static int calcUdhSeptetPadding(int userDataHeaderLen) {
- int udhBits = userDataHeaderLen * 8;
- int udhSeptets = (udhBits + 6) / 7;
- int paddingBits = (udhSeptets * 7) - udhBits;
- return paddingBits;
+ private static class Gsm7bitCodingResult {
+ int septets;
+ byte[] data;
}
- private static byte[] encode7bitGsm(String msg, int paddingBits)
+ private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
throws CodingException
{
try {
/*
* TODO(cleanup): It would be nice if GsmAlphabet provided
* an option to produce just the data without prepending
- * the length.
+ * the septet count, as this function is really just a
+ * wrapper to strip that off. Not to mention that the
+ * septet count is generally known prior to invocation of
+ * the encoder. Note that it cannot be derived from the
+ * resulting array length, since that cannot distinguish
+ * if the last contains either 1 or 8 valid bits.
+ *
+ * TODO(cleanup): The BitwiseXStreams could also be
+ * extended with byte-wise reversed endianness read/write
+ * routines to allow a corresponding implementation of
+ * stringToGsm7BitPacked, and potentially directly support
+ * access to the main bitwise stream from encode/decode.
*/
- byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true);
- byte []data = new byte[fullData.length - 1];
- System.arraycopy(fullData, 1, data, 0, fullData.length - 1);
- return data;
+ byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force);
+ 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];
+ return result;
} catch (com.android.internal.telephony.EncodeException ex) {
throw new CodingException("7bit GSM encode failed: " + ex);
}
}
+ private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
+ throws CodingException
+ {
+ int udhBytes = udhData.length + 1; // Add length octet.
+ int udhSeptets = ((udhBytes * 8) + 6) / 7;
+ Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
+ uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ uData.numFields = gcr.septets;
+ uData.payload = gcr.data;
+ uData.payload[0] = (byte)udhData.length;
+ System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+ }
+
+ private static void encode16bitEms(UserData uData, byte[] udhData)
+ throws CodingException
+ {
+ byte[] payload = encodeUtf16(uData.payloadStr);
+ int udhBytes = udhData.length + 1; // Add length octet.
+ int udhCodeUnits = (udhBytes + 1) / 2;
+ int udhPadding = udhBytes % 2;
+ int payloadCodeUnits = payload.length / 2;
+ uData.numFields = udhCodeUnits + payloadCodeUnits;
+ uData.payload = new byte[uData.numFields * 2];
+ uData.payload[0] = (byte)udhData.length;
+ System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+ System.arraycopy(payload, 0, uData.payload, udhBytes + udhPadding, payload.length);
+ }
+
+ private static void encodeEmsUserDataPayload(UserData uData)
+ throws CodingException
+ {
+ byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
+ if (uData.msgEncodingSet) {
+ if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
+ encode7bitEms(uData, headerData, true);
+ } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
+ encode16bitEms(uData, headerData);
+ } else {
+ throw new CodingException("unsupported EMS user data encoding (" +
+ uData.msgEncoding + ")");
+ }
+ } else {
+ try {
+ encode7bitEms(uData, headerData, false);
+ } catch (CodingException ex) {
+ encode16bitEms(uData, headerData);
+ }
+ }
+ }
+
private static void encodeUserDataPayload(UserData uData)
throws CodingException
{
- // TODO(cleanup): UDH can only occur in EMS mode, meaning
- // encapsulation of GSM encoding, and so the logic here should
- // be refactored to more cleanly reflect this constraint.
+ if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
+ Log.e(LOG_TAG, "user data with null payloadStr");
+ uData.payloadStr = "";
+ }
- byte[] headerData = null;
- if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
- int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet
+ if (uData.userDataHeader != null) {
+ encodeEmsUserDataPayload(uData);
+ return;
+ }
- byte[] payloadData;
- int codeUnitCount;
if (uData.msgEncodingSet) {
if (uData.msgEncoding == UserData.ENCODING_OCTET) {
if (uData.payload == null) {
Log.e(LOG_TAG, "user data with octet encoding but null payload");
- payloadData = new byte[0];
- codeUnitCount = 0;
+ uData.payload = new byte[0];
+ uData.numFields = 0;
} else {
- payloadData = uData.payload;
- codeUnitCount = uData.payload.length;
+ uData.payload = uData.payload;
+ uData.numFields = uData.payload.length;
}
} else {
if (uData.payloadStr == null) {
@@ -509,65 +570,48 @@
uData.payloadStr = "";
}
if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
- int paddingBits = calcUdhSeptetPadding(headerDataLen);
- payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
- codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
+ Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
+ uData.payload = gcr.data;
+ uData.numFields = gcr.septets;
} else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
- payloadData = encode7bitAscii(uData.payloadStr, true);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encode7bitAscii(uData.payloadStr, true);
+ uData.numFields = uData.payloadStr.length();
} else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
- payloadData = encodeUtf16(uData.payloadStr);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encodeUtf16(uData.payloadStr);
+ uData.numFields = uData.payloadStr.length();
} else {
throw new CodingException("unsupported user data encoding (" +
uData.msgEncoding + ")");
}
}
} else {
- if (uData.payloadStr == null) {
- Log.e(LOG_TAG, "user data with null payloadStr");
- uData.payloadStr = "";
- }
try {
- if (headerData == null) {
- payloadData = encode7bitAscii(uData.payloadStr, false);
- codeUnitCount = uData.payloadStr.length();
- uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
- } else {
- // If there is a header, we are in EMS mode, in
- // which case we use GSM encodings.
- int paddingBits = calcUdhSeptetPadding(headerDataLen);
- payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
- codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
- uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
- }
+ uData.payload = encode7bitAscii(uData.payloadStr, false);
+ uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
} catch (CodingException ex) {
- payloadData = encodeUtf16(uData.payloadStr);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encodeUtf16(uData.payloadStr);
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
}
+ uData.numFields = uData.payloadStr.length();
uData.msgEncodingSet = true;
}
-
- int totalLength = payloadData.length + headerDataLen;
- if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) {
- throw new CodingException("encoded user data too large (" + totalLength +
- " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
- }
-
- uData.numFields = codeUnitCount;
- uData.payload = new byte[totalLength];
- if (headerData != null) {
- uData.payload[0] = (byte)headerData.length;
- System.arraycopy(headerData, 0, uData.payload, 1, headerData.length);
- }
- System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length);
}
private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException, CodingException
{
+ /*
+ * TODO(cleanup): Do we really need to set userData.payload as
+ * a side effect of encoding? If not, we could avoid data
+ * copies by passing outStream directly.
+ */
encodeUserDataPayload(bData.userData);
+ 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
*
@@ -624,6 +668,12 @@
return rawData;
}
+ /*
+ * TODO(cleanup): CdmaSmsAddress encoding should make use of
+ * CdmaSmsAddress.parse provided that DTMF encoding is unified,
+ * and the difference in 4bit vs 8bit is resolved.
+ */
+
private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
try {
@@ -792,23 +842,34 @@
return null;
}
- private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 3) {
- throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 3 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.messageType = inStream.read(4);
+ bData.messageId = inStream.read(8) << 8;
+ bData.messageId |= inStream.read(8);
+ bData.hasUserDataHeader = (inStream.read(1) == 1);
+ inStream.skip(3);
}
- bData.messageType = inStream.read(4);
- bData.messageId = inStream.read(8) << 8;
- bData.messageId |= inStream.read(8);
- bData.hasUserDataHeader = (inStream.read(1) == 1);
- inStream.skip(3);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeUserData(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
bData.userData = new UserData();
bData.userData.msgEncoding = inStream.read(5);
bData.userData.msgEncodingSet = true;
@@ -821,13 +882,17 @@
}
bData.userData.numFields = inStream.read(8);
consumedBits += 8;
- int dataBits = (paramBytes * 8) - consumedBits;
+ int dataBits = paramBits - consumedBits;
bData.userData.payload = inStream.readByteArray(dataBits);
+ return true;
}
private static String decodeUtf16(byte[] data, int offset, int numFields)
throws CodingException
{
+ // Start reading from the next 16-bit aligned boundry after offset.
+ int padding = offset % 2;
+ numFields -= (offset + padding) / 2;
try {
return new String(data, offset, numFields * 2, "utf-16be");
} catch (java.io.UnsupportedEncodingException ex) {
@@ -835,7 +900,7 @@
}
}
- private static String decodeIa5(byte[] data, int offset, int numFields)
+ private static String decode7bitAscii(byte[] data, int offset, int numFields)
throws CodingException
{
try {
@@ -850,38 +915,20 @@
inStream.skip(offset);
for (int i = 0; i < numFields; i++) {
int charCode = inStream.read(7);
- if ((charCode < UserData.IA5_MAP_BASE_INDEX) ||
- (charCode > UserData.IA5_MAP_MAX_INDEX)) {
- throw new CodingException("unsupported AI5 character code (" + charCode + ")");
+ if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
+ (charCode <= UserData.ASCII_MAP_MAX_INDEX)) {
+ strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]);
+ } else if (charCode == UserData.ASCII_NL_INDEX) {
+ strBuf.append('\n');
+ } else if (charCode == UserData.ASCII_CR_INDEX) {
+ strBuf.append('\r');
+ } else {
+ /* For other charCodes, they are unprintable, and so simply use SPACE. */
+ strBuf.append(' ');
}
- strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]);
}
return strBuf.toString();
} catch (BitwiseInputStream.AccessException ex) {
- throw new CodingException("AI5 decode failed: " + ex);
- }
- }
-
- private static String decode7bitAscii(byte[] data, int offset, int numFields)
- throws CodingException
- {
- try {
- offset *= 8;
- BitwiseInputStream inStream = new BitwiseInputStream(data);
- int wantedBits = offset + (numFields * 7);
- if (inStream.available() < wantedBits) {
- throw new CodingException("insufficient data (wanted " + wantedBits +
- " bits, but only have " + inStream.available() + ")");
- }
- inStream.skip(offset);
- byte[] expandedData = new byte[numFields];
- for (int i = 0; i < numFields; i++) {
- expandedData[i] = (byte)inStream.read(7);
- }
- return new String(expandedData, 0, numFields, "US-ASCII");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("7bit ASCII decode failed: " + ex);
- } catch (BitwiseInputStream.AccessException ex) {
throw new CodingException("7bit ASCII decode failed: " + ex);
}
}
@@ -889,11 +936,11 @@
private static String decode7bitGsm(byte[] data, int offset, int numFields)
throws CodingException
{
- int paddingBits = calcUdhSeptetPadding(offset);
- numFields -= (((offset * 8) + paddingBits) / 7);
- // TODO: It seems wrong that only Gsm7 bit encodings would
- // take into account the header in numFields calculations.
- // This should be verified.
+ // Start reading from the next 7-bit aligned boundry after offset.
+ int offsetBits = offset * 8;
+ int offsetSeptets = (offsetBits + 6) / 7;
+ numFields -= offsetSeptets;
+ int paddingBits = (offsetSeptets * 7) - offsetBits;
String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits);
if (result == null) {
throw new CodingException("7bit GSM decoding failed");
@@ -901,6 +948,16 @@
return result;
}
+ private static String decodeLatin(byte[] data, int offset, int numFields)
+ throws CodingException
+ {
+ try {
+ return new String(data, offset, numFields - offset, "ISO-8859-1");
+ } catch (java.io.UnsupportedEncodingException ex) {
+ throw new CodingException("ISO-8859-1 decode failed: " + ex);
+ }
+ }
+
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
throws CodingException
{
@@ -914,12 +971,23 @@
}
switch (userData.msgEncoding) {
case UserData.ENCODING_OCTET:
- break;
- case UserData.ENCODING_7BIT_ASCII:
- userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
+ // Strip off any padding bytes, meaning any differences between the length of the
+ // array and the target length specified by numFields. This is to avoid any confusion
+ // by code elsewhere that only considers the payload array length.
+ byte[] payload = new byte[userData.numFields];
+ int copyLen = userData.numFields < userData.payload.length
+ ? userData.numFields : userData.payload.length;
+
+ System.arraycopy(userData.payload, 0, payload, 0, copyLen);
+ userData.payload = payload;
+
+ // There are many devices in the market that send 8bit text sms (latin encoded) as
+ // octet encoded.
+ userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
break;
case UserData.ENCODING_IA5:
- userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields);
+ case UserData.ENCODING_7BIT_ASCII:
+ userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
break;
case UserData.ENCODING_UNICODE_16:
userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields);
@@ -927,6 +995,9 @@
case UserData.ENCODING_GSM_7BIT_ALPHABET:
userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields);
break;
+ case UserData.ENCODING_LATIN:
+ userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+ break;
default:
throw new CodingException("unsupported user data encoding ("
+ userData.msgEncoding + ")");
@@ -959,7 +1030,7 @@
try {
StringBuffer strbuf = new StringBuffer(dataLen);
while (inStream.available() >= 6) {
- strbuf.append(UserData.IA5_MAP[inStream.read(6)]);
+ strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
}
String data = strbuf.toString();
bData.numberOfMessages = Integer.parseInt(data.substring(0, 2));
@@ -1001,7 +1072,7 @@
}
StringBuffer strbuf = new StringBuffer(dataLen);
for (int i = 0; i < numFields; i++) {
- strbuf.append(UserData.IA5_MAP[inStream.read(6)]);
+ strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
}
bData.userData.payloadStr = strbuf.toString();
}
@@ -1049,36 +1120,68 @@
}
}
- private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
- if (paramBytes != 1) {
- throw new CodingException("REPLY_OPTION subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userAckReq = (inStream.read(1) == 1);
+ bData.deliveryAckReq = (inStream.read(1) == 1);
+ bData.readAckReq = (inStream.read(1) == 1);
+ bData.reportReq = (inStream.read(1) == 1);
+ inStream.skip(4);
}
- bData.userAckReq = (inStream.read(1) == 1);
- bData.deliveryAckReq = (inStream.read(1) == 1);
- bData.readAckReq = (inStream.read(1) == 1);
- bData.reportReq = (inStream.read(1) == 1);
- inStream.skip(4);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "REPLY_OPTION decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
}
- bData.numberOfMessages = inStream.read(8);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 2) {
- throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 2 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
}
- bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
@@ -1112,10 +1215,10 @@
}
}
- private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.digitMode = inStream.read(1);
byte fieldBits = 4;
@@ -1128,140 +1231,274 @@
}
addr.numberOfDigits = inStream.read(8);
consumedBits += 8;
- int remainingBits = (paramBytes * 8) - consumedBits;
+ int remainingBits = paramBits - consumedBits;
int dataBits = addr.numberOfDigits * fieldBits;
int paddingBits = remainingBits - dataBits;
if (remainingBits < dataBits) {
throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
- "remainingBits " + remainingBits + ", dataBits " +
- dataBits + ", paddingBits " + paddingBits + ")");
+ "remainingBits + " + remainingBits + ", dataBits + " +
+ dataBits + ", paddingBits + " + paddingBits + ")");
}
addr.origBytes = inStream.readByteArray(dataBits);
inStream.skip(paddingBits);
decodeSmsAddress(addr);
bData.callbackNumber = addr;
+ return true;
}
- private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("MESSAGE_STATUS subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.errorClass = inStream.read(2);
+ bData.messageStatus = inStream.read(6);
}
- bData.errorClass = inStream.read(2);
- bData.messageStatus = inStream.read(6);
- bData.messageStatusSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_STATUS decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.messageStatusSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
+ inStream.readByteArray(6 * 8));
}
- bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeRelative = inStream.read(8);
}
- bData.deferredDeliveryTimeRelative = inStream.read(8);
- bData.deferredDeliveryTimeRelativeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodRelative = inStream.read(8);
}
- bData.validityPeriodRelative = inStream.read(8);
- bData.validityPeriodRelativeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.validityPeriodRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIVACY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.privacy = inStream.read(2);
+ inStream.skip(6);
}
- bData.privacy = inStream.read(2);
- inStream.skip(6);
- bData.privacyIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.privacyIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.language = inStream.read(8);
}
- bData.language = inStream.read(8);
- bData.languageIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.languageIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DISPLAY_MODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.displayMode = inStream.read(2);
+ inStream.skip(6);
}
- bData.displayMode = inStream.read(2);
- inStream.skip(6);
- bData.displayModeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DISPLAY_MODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.displayModeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIORITY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.priority = inStream.read(2);
+ inStream.skip(6);
}
- bData.priority = inStream.read(2);
- inStream.skip(6);
- bData.priorityIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.priorityIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.alert = inStream.read(2);
+ inStream.skip(6);
}
- bData.alert = inStream.read(2);
- inStream.skip(6);
- bData.alertIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.alertIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("USER_REPONSE_CODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userResponseCode = inStream.read(8);
}
- bData.userResponseCode = inStream.read(8);
- bData.userResponseCodeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "USER_REPONSE_CODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.userResponseCodeSet = decodeSuccess;
+ return decodeSuccess;
}
/**
@@ -1278,72 +1515,73 @@
BearerData bData = new BearerData();
int foundSubparamMask = 0;
while (inStream.available() > 0) {
+ boolean decodeSuccess = false;
int subparamId = inStream.read(8);
int subparamIdBit = 1 << subparamId;
if ((foundSubparamMask & subparamIdBit) != 0) {
throw new CodingException("illegal duplicate subparameter (" +
subparamId + ")");
}
- foundSubparamMask |= subparamIdBit;
switch (subparamId) {
case SUBPARAM_MESSAGE_IDENTIFIER:
- decodeMessageId(bData, inStream);
+ decodeSuccess = decodeMessageId(bData, inStream);
break;
case SUBPARAM_USER_DATA:
- decodeUserData(bData, inStream);
+ decodeSuccess = decodeUserData(bData, inStream);
break;
case SUBPARAM_USER_REPONSE_CODE:
- decodeUserResponseCode(bData, inStream);
+ decodeSuccess = decodeUserResponseCode(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
- decodeReplyOption(bData, inStream);
+ decodeSuccess = decodeReplyOption(bData, inStream);
break;
case SUBPARAM_NUMBER_OF_MESSAGES:
- decodeMsgCount(bData, inStream);
+ decodeSuccess = decodeMsgCount(bData, inStream);
break;
case SUBPARAM_CALLBACK_NUMBER:
- decodeCallbackNumber(bData, inStream);
+ decodeSuccess = decodeCallbackNumber(bData, inStream);
break;
case SUBPARAM_MESSAGE_STATUS:
- decodeMsgStatus(bData, inStream);
+ decodeSuccess = decodeMsgStatus(bData, inStream);
break;
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
- decodeMsgCenterTimeStamp(bData, inStream);
+ decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
- decodeValidityAbs(bData, inStream);
+ decodeSuccess = decodeValidityAbs(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
- decodeValidityRel(bData, inStream);
+ decodeSuccess = decodeValidityRel(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
- decodeDeferredDeliveryAbs(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
- decodeDeferredDeliveryRel(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
break;
case SUBPARAM_PRIVACY_INDICATOR:
- decodePrivacyIndicator(bData, inStream);
+ decodeSuccess = decodePrivacyIndicator(bData, inStream);
break;
case SUBPARAM_LANGUAGE_INDICATOR:
- decodeLanguageIndicator(bData, inStream);
+ decodeSuccess = decodeLanguageIndicator(bData, inStream);
break;
case SUBPARAM_MESSAGE_DISPLAY_MODE:
- decodeDisplayMode(bData, inStream);
+ decodeSuccess = decodeDisplayMode(bData, inStream);
break;
case SUBPARAM_PRIORITY_INDICATOR:
- decodePriorityIndicator(bData, inStream);
+ decodeSuccess = decodePriorityIndicator(bData, inStream);
break;
case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
- decodeMsgDeliveryAlert(bData, inStream);
+ decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
break;
case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
- decodeDepositIndex(bData, inStream);
+ decodeSuccess = decodeDepositIndex(bData, inStream);
break;
default:
throw new CodingException("unsupported bearer data subparameter ("
+ subparamId + ")");
}
+ if (decodeSuccess) foundSubparamMask |= subparamIdBit;
}
if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
index 4d799665..d9cc2c6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -16,7 +16,10 @@
package com.android.internal.telephony.cdma.sms;
+import android.util.SparseBooleanArray;
+
import com.android.internal.telephony.SmsAddress;
+import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
public class CdmaSmsAddress extends SmsAddress {
@@ -43,7 +46,8 @@
/**
* Number Types for data networks.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
* NOTE: value is stored in the parent class ton field.
*/
static public final int TON_UNKNOWN = 0x00;
@@ -98,10 +102,127 @@
builder.append(", numberPlan=" + numberPlan);
builder.append(", numberOfDigits=" + numberOfDigits);
builder.append(", ton=" + ton);
- builder.append(", address=" + address);
+ builder.append(", address=\"" + address + "\"");
builder.append(", origBytes=" + HexDump.toHexString(origBytes));
builder.append(" }");
return builder.toString();
}
+ /*
+ * TODO(cleanup): Refactor the parsing for addresses to better
+ * share code and logic with GSM. Also, gather all DTMF/BCD
+ * processing code in one place.
+ */
+
+ private static byte[] parseToDtmf(String address) {
+ int digits = address.length();
+ byte[] result = new byte[digits];
+ for (int i = 0; i < digits; i++) {
+ char c = address.charAt(i);
+ int val = 0;
+ if ((c >= '1') && (c <= '9')) val = c - '0';
+ else if (c == '0') val = 10;
+ else if (c == '*') val = 11;
+ else if (c == '#') val = 12;
+ else return null;
+ result[i] = (byte)val;
+ }
+ return result;
+ }
+
+ private static final char[] numericCharsDialable = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
+ };
+
+ private static final char[] numericCharsSugar = {
+ '(', ')', ' ', '-', '+'
+ };
+
+ private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
+ numericCharsDialable.length + numericCharsSugar.length);
+ static {
+ for (int i = 0; i < numericCharsDialable.length; i++) {
+ numericCharDialableMap.put(numericCharsDialable[i], true);
+ }
+ for (int i = 0; i < numericCharsSugar.length; i++) {
+ numericCharDialableMap.put(numericCharsSugar[i], false);
+ }
+ }
+
+ /**
+ * Given a numeric address string, return the string without
+ * syntactic sugar, meaning parens, spaces, hyphens/minuses, or
+ * plus signs. If the input string contains non-numeric
+ * non-punctuation characters, return null.
+ */
+ private static String filterNumericSugar(String address) {
+ StringBuilder builder = new StringBuilder();
+ int len = address.length();
+ for (int i = 0; i < len; i++) {
+ char c = address.charAt(i);
+ int mapIndex = numericCharDialableMap.indexOfKey(c);
+ if (mapIndex < 0) return null;
+ if (! numericCharDialableMap.valueAt(mapIndex)) continue;
+ builder.append(c);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Given a string, return the string without whitespace,
+ * including CR/LF.
+ */
+ private static String filterWhitespace(String address) {
+ StringBuilder builder = new StringBuilder();
+ int len = address.length();
+ for (int i = 0; i < len; i++) {
+ char c = address.charAt(i);
+ if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
+ builder.append(c);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Given a string, create a corresponding CdmaSmsAddress object.
+ *
+ * The result will be null if the input string is not
+ * representable using printable ASCII.
+ *
+ * For numeric addresses, the string is cleaned up by removing
+ * common punctuation. For alpha addresses, the string is cleaned
+ * up by removing whitespace.
+ */
+ public static CdmaSmsAddress parse(String address) {
+ CdmaSmsAddress addr = new CdmaSmsAddress();
+ addr.address = address;
+ addr.ton = CdmaSmsAddress.TON_UNKNOWN;
+ byte[] origBytes = null;
+ String filteredAddr = filterNumericSugar(address);
+ if (filteredAddr != null) {
+ origBytes = parseToDtmf(filteredAddr);
+ }
+ if (origBytes != null) {
+ addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ if (address.indexOf('+') != -1) {
+ addr.ton = TON_INTERNATIONAL_OR_IP;
+ }
+ } else {
+ filteredAddr = filterWhitespace(address);
+ origBytes = UserData.stringToAscii(filteredAddr);
+ if (origBytes == null) {
+ return null;
+ }
+ addr.digitMode = DIGIT_MODE_8BIT_CHAR;
+ addr.numberMode = NUMBER_MODE_DATA_NETWORK;
+ if (address.indexOf('@') != -1) {
+ addr.ton = TON_NATIONAL_OR_EMAIL;
+ }
+ }
+ addr.origBytes = origBytes;
+ addr.numberOfDigits = origBytes.length;
+ return addr;
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index f80e8c0..0dcacc1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -36,6 +36,14 @@
static public final int TELESERVICE_WAP = 0x1004;
static public final int TELESERVICE_WEMT = 0x1005;
+ /**
+ * The following are defined as extensions to the standard teleservices
+ */
+ // Voice mail notification through Message Waiting Indication in CDMA mode or Analog mode.
+ // Defined in 3GPP2 C.S-0005, 3.7.5.6, an Info Record containing an 8-bit number with the
+ // number of messages waiting, it's used by some CDMA carriers for a voice mail count.
+ static public final int TELESERVICE_MWI = 0x40000;
+
// ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
//static public final int SERVICECATEGORY_EMERGENCY = 0x0010;
//...
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 34cbbfa..9b6e19d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -35,7 +35,7 @@
//public static final int ENCODING_SHIFT_JIS = 0x05;
//public static final int ENCODING_KOREAN = 0x06;
//public static final int ENCODING_LATIN_HEBREW = 0x07;
- //public static final int ENCODING_LATIN = 0x08;
+ public static final int ENCODING_LATIN = 0x08;
public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09;
public static final int ENCODING_GSM_DCS = 0x0A;
@@ -49,19 +49,20 @@
public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85;
/**
- * IA5 data encoding character mappings.
- * (See CCITT Rec. T.50 Tables 1 and 3)
+ * US ASCII character mapping table.
*
- * Note this mapping is the the same as for printable ASCII
- * characters, with a 0x20 offset, meaning that the ASCII SPACE
- * character occurs with code 0x20.
+ * This table contains only the printable ASCII characters, with a
+ * 0x20 offset, meaning that the ASCII SPACE character is at index
+ * 0, with the resulting code of 0x20.
*
- * Note this mapping is also equivalent to that used by the IS-91
- * protocol, except for the latter using only 6 bits, and hence
- * mapping only entries up to the '_' character.
+ * Note this mapping is also equivalent to that used by both the
+ * IS5 and the IS-91 encodings. For the former this is defined
+ * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B,
+ * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits,
+ * and hence only maps entries up to the '_' character.
*
*/
- public static final char[] IA5_MAP = {
+ public static final char[] ASCII_MAP = {
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
@@ -81,23 +82,43 @@
* Only elements between these indices in the ASCII table are printable.
*/
public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
- public static final int ASCII_LF_INDEX = 0x0A;
+ public static final int ASCII_NL_INDEX = 0x0A;
public static final int ASCII_CR_INDEX = 0x0D;
public static final SparseIntArray charToAscii = new SparseIntArray();
static {
- for (int i = 0; i < IA5_MAP.length; i++) {
- charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
+ for (int i = 0; i < ASCII_MAP.length; i++) {
+ charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
}
- charToAscii.put('\r', ASCII_LF_INDEX);
- charToAscii.put('\n', ASCII_CR_INDEX);
+ charToAscii.put('\n', ASCII_NL_INDEX);
+ charToAscii.put('\r', ASCII_CR_INDEX);
+ }
+
+ /*
+ * TODO(cleanup): Move this very generic functionality somewhere
+ * more general.
+ */
+ /**
+ * Given a string generate a corresponding ASCII-encoded byte
+ * array, but limited to printable characters. If the input
+ * contains unprintable characters, return null.
+ */
+ public static byte[] stringToAscii(String str) {
+ int len = str.length();
+ byte[] result = new byte[len];
+ for (int i = 0; i < len; i++) {
+ int charCode = charToAscii.get(str.charAt(i), -1);
+ if (charCode == -1) return null;
+ result[i] = (byte)charCode;
+ }
+ return result;
}
/**
- * Mapping for IA5 values less than 32 are flow control signals
+ * Mapping for ASCII values less than 32 are flow control signals
* and not used here.
*/
- public static final int IA5_MAP_BASE_INDEX = 0x20;
- public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1;
+ public static final int ASCII_MAP_BASE_INDEX = 0x20;
+ public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1;
/**
* Contains the data header of the user data
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 3ca39de65..dc6f92d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -72,7 +72,10 @@
boolean canHandleType(String type) {
for (String t : types) {
- if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL)) {
+ // DEFAULT handles all, and HIPRI is handled by DEFAULT
+ if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) ||
+ (t.equals(Phone.APN_TYPE_DEFAULT) &&
+ type.equals(Phone.APN_TYPE_HIPRI))) {
return true;
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index d1e4b4f..bb04a43 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -51,6 +51,7 @@
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
+import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandsInterface;
@@ -101,7 +102,6 @@
GsmCallTracker mCT;
GsmServiceStateTracker mSST;
GsmSMSDispatcher mSMS;
- GsmDataConnectionTracker mDataConnection;
SIMRecords mSIMRecords;
SimCard mSimCard;
StkService mStkService;
@@ -279,14 +279,6 @@
return "GSM";
}
- public String[] getActiveApnTypes() {
- return mDataConnection.getActiveApnTypes();
- }
-
- public String getActiveApn() {
- return mDataConnection.getActiveApnString();
- }
-
public SignalStrength getSignalStrength() {
return mSST.mSignalStrength;
}
@@ -378,20 +370,19 @@
}
/**
- * Notify any interested party of a Phone state change.
+ * Notify any interested party of a Phone state change {@link Phone.State}
*/
/*package*/ void notifyPhoneStateChanged() {
mNotifier.notifyPhoneState(this);
}
/**
- * Notifies registrants (ie, activities in the Phone app) about
- * changes to call state (including Phone and Connection changes).
+ * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
+ * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
*/
- /*package*/ void
- notifyCallStateChanged() {
+ /*package*/ void notifyPreciseCallStateChanged() {
/* we'd love it if this was package-scoped*/
- super.notifyCallStateChangedP();
+ super.notifyPreciseCallStateChangedP();
}
/*package*/ void
@@ -1032,11 +1023,13 @@
/**
* Small container class used to hold information relevant to
* the carrier selection process. operatorNumeric can be ""
- * if we are looking for automatic selection.
+ * if we are looking for automatic selection. operatorAlphaLong is the
+ * corresponding operator name.
*/
private static class NetworkSelectMessage {
public Message message;
public String operatorNumeric;
+ public String operatorAlphaLong;
}
public void
@@ -1047,6 +1040,7 @@
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = "";
+ nsm.operatorAlphaLong = "";
// get the message
Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
@@ -1064,6 +1058,7 @@
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = network.operatorNumeric;
+ nsm.operatorAlphaLong = network.operatorAlphaLong;
// get the message
Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
@@ -1141,34 +1136,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);
- }
-
/**
* The only circumstances under which we report that data connectivity is not
* possible are
@@ -1495,6 +1466,7 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
+ editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong);
// commit and log the result.
if (! editor.commit()) {
@@ -1534,36 +1506,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/GsmCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
index a92e52d..9542d20 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
@@ -185,6 +185,7 @@
cn.onHangupLocal();
}
+ state = State.DISCONNECTING;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 5c5090f..91c089e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -212,7 +212,7 @@
}
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
return pendingMO;
}
@@ -279,7 +279,7 @@
internalClearDisconnected();
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
boolean
@@ -294,12 +294,15 @@
canDial() {
boolean ret;
int serviceState = phone.getServiceState().getState();
+ String disableCall = SystemProperties.get(
+ TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
- ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
- pendingMO == null
+ ret = (serviceState != ServiceState.STATE_POWER_OFF)
+ && pendingMO == null
&& !ringingCall.isRinging()
+ && !disableCall.equals("true")
&& (!foregroundCall.getState().isAlive()
- || !backgroundCall.getState().isAlive());
+ || !backgroundCall.getState().isAlive());
return ret;
}
@@ -600,7 +603,7 @@
}
if (hasNonHangupStateChanged || newRinging != null) {
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
//dumpState();
@@ -738,6 +741,7 @@
}
call.onHangupLocal();
+ phone.notifyPreciseCallStateChanged();
}
/* package */
@@ -883,7 +887,7 @@
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
droppedDuringPoll.clear();
break;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index d93ca1d..2091fb6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -381,10 +381,14 @@
} else if (phone.mSST.rs.isCsNormalRestricted()) {
return DisconnectCause.CS_RESTRICTED_NORMAL;
} else {
- return DisconnectCause.NORMAL;
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
- } else {
+ } else if (causeCode == CallFailCause.NORMAL_CLEARING) {
return DisconnectCause.NORMAL;
+ } else {
+ // If nothing else matches, report unknown call drop reason
+ // to app, not NORMAL call end.
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d48c941..b9688f3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -52,6 +52,7 @@
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.TelephonyEventLog;
import com.android.internal.telephony.DataConnection.FailCause;
@@ -62,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;
/**
@@ -85,7 +85,7 @@
INetStatService netstat;
// Indicates baseband will not auto-attach
private boolean noAutoAttach = false;
- long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+
private boolean mReregisterOnReconnectFailure = false;
private ContentResolver mResolver;
@@ -95,6 +95,9 @@
private int mPdpResetCount = 0;
private boolean mIsScreenOn = true;
+ /** Delay between APN attempts */
+ protected static final int APN_DELAY_MILLIS = 5000;
+
//useful for debugging
boolean failNextConnect = false;
@@ -115,27 +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_DEFAULT_ID = 0;
- private static int APN_MMS_ID = 1;
- private static int APN_SUPL_ID = 2;
- private static int APN_NUM_TYPES = 3;
-
- private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
-
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -207,7 +200,6 @@
GsmDataConnectionTracker(GSMPhone p) {
super(p);
mGsmPhone = p;
-
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
@@ -246,7 +238,19 @@
// and 2) whether the RIL will setup the baseband to auto-PS attach.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ enabledCount++;
+ }
noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
+
+ if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
+ if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+ // Should never happen, log an error and default to a simple linear sequence.
+ Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+ + DEFAULT_DATA_RETRY_CONFIG);
+ mRetryMgr.configure(20, 2000, 1000);
+ }
+ }
}
public void dispose() {
@@ -274,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
@@ -298,7 +302,7 @@
}
}
- String[] getActiveApnTypes() {
+ public String[] getActiveApnTypes() {
String[] result;
if (mActiveApn != null) {
result = mActiveApn.types;
@@ -318,91 +322,6 @@
}
/**
- * 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) {
- if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) &&
- !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
- return Phone.APN_REQUEST_FAILED;
- }
-
- // If already active, return
- Log.d(LOG_TAG, "enableApnType("+type+")");
- if (isApnTypeActive(type)) {
- setEnabled(type, true);
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- /**
- * We're being asked to enable a non-default APN that's already in use.
- * This means we should restart the timer that will automatically
- * switch back to the default APN and disable the non-default APN
- * when it expires.
- */
- sendMessageDelayed(
- obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- 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(type, 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) {
- Log.d(LOG_TAG, "disableApnType("+type+")");
- if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) ||
- TextUtils.equals(type, Phone.APN_TYPE_SUPL))
- && isEnabled(type)) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- setEnabled(type, false);
- if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (dataEnabled[APN_DEFAULT_ID]) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true;
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- /*
- * Note that if default data is disabled, the following
- * has the effect of disabling the MMS APN, and then
- * ignoring the request to enable the default APN.
- * The net result is that data is completely disabled.
- */
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- 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
* 2. registered to gprs service
@@ -428,12 +347,14 @@
return mGsmPhone.mSST.getDataRoaming();
}
- private boolean isApnTypeActive(String type) {
- // TODO: to support simultaneous, mActiveApn can be a List instead.
+ @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)) {
@@ -444,90 +365,6 @@
return false;
}
- private boolean isEnabled(String apnType) {
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- return dataEnabled[APN_DEFAULT_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- return dataEnabled[APN_MMS_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- return dataEnabled[APN_SUPL_ID];
- } else {
- return false;
- }
- }
-
- private void setEnabled(String apnType, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')');
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- dataEnabled[APN_DEFAULT_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- dataEnabled[APN_MMS_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- dataEnabled[APN_SUPL_ID] = enable;
- }
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
- " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] +
- " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]);
- }
-
- /**
- * 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) {
- boolean isEnabled = isEnabled(Phone.APN_TYPE_DEFAULT);
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, true);
- // trySetupData() will be a no-op if we are currently
- // connected to the MMS APN
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- return true;
- } else if (!enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, false);
- // Don't tear down if there is an active APN and it handles MMS or SUPL.
- // TODO: This isn't very general.
- if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) ||
- (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) {
- return false;
- }
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- return true;
- } else {
- // isEnabled && enable
- return true;
- }
- }
-
- /**
- * 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 dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID];
- }
-
/**
* Formerly this method was ArrayList<PdpConnection> getAllPdps()
*/
@@ -562,7 +399,7 @@
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
}
trySetupData(Phone.REASON_GPRS_ATTACHED);
}
@@ -607,7 +444,7 @@
}
if (DBG) {
- log ("Setup watingApns : " + apnListToString(waitingApns));
+ log ("Setup waitngApns : " + apnListToString(waitingApns));
}
return setupData(reason);
} else {
@@ -618,6 +455,7 @@
" sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() +
" UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() +
" phoneState=" + phone.getState() +
+ " isDataAllowed=" + isDataAllowed() +
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
" dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
@@ -742,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();
@@ -758,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();
@@ -812,7 +650,7 @@
cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
trySetupData(Phone.REASON_APN_CHANGED);
}
@@ -893,7 +731,7 @@
phone.notifyDataConnection(reason);
startNetStatPoll();
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
}
@@ -1179,20 +1017,21 @@
private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
if (state == State.FAILED) {
- if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
+ if (!mRetryMgr.isRetryNeeded()) {
if (mReregisterOnReconnectFailure) {
- // We have already tried to re-register to the network.
- // This might be a problem with the data network.
- nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
+ // We've re-registerd once now just retry forever.
+ mRetryMgr.retryForeverUsingLastTimeout();
} else {
- // Try to Re-register to the network.
+ // Try to re-register to the network.
Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
mReregisterOnReconnectFailure = true;
mGsmPhone.mSST.reRegisterNetwork(null);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
return;
}
}
+
+ int nextReconnectDelay = mRetryMgr.getRetryTimer();
Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
@@ -1206,8 +1045,7 @@
SystemClock.elapsedRealtime() + nextReconnectDelay,
mReconnectIntent);
- // double it for next time
- nextReconnectDelay *= 2;
+ mRetryMgr.increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification "
@@ -1240,15 +1078,6 @@
trySetupData(reason);
}
- protected void onRestoreDefaultApn() {
- if (DBG) Log.d(LOG_TAG, "Restore default APN");
- setEnabled(Phone.APN_TYPE_MMS, false);
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN);
- }
- }
-
/**
* Check the data roaming consistency since this can be triggered by
* voice roaming flag of ServiceState in setDataOnRoamingEnabled()
@@ -1302,7 +1131,7 @@
protected void onRadioOffOrNotAvailable() {
// Make sure our reconnect delay starts at the initial value
// next time the radio comes on
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
if (phone.getSimulatedRadioControl() != null) {
@@ -1324,22 +1153,6 @@
if (ar.exception == null) {
// everything is setup
-
- /*
- * We may have switched away from the default PDP context
- * in order to enable a "special" APN (e.g., for MMS
- * traffic). Set a timer to switch back and/or disable the
- * special APN, so that a negligient application doesn't
- * permanently prevent data connectivity. What we are
- * protecting against here is not malicious apps, but
- * rather an app that inadvertantly fails to reset to the
- * default APN, or that dies before doing so.
- */
- if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- }
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
@@ -1387,8 +1200,7 @@
setState(State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
- RECONNECT_DELAY_INITIAL_MILLIS);
+ sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
}
}
}
@@ -1433,7 +1245,7 @@
}
} else {
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
@@ -1444,18 +1256,6 @@
cleanUpConnection(tearDown, reason);
}
- private int getRestoreDefaultApnDelay() {
- String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME);
-
- if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) {
- try {
- return Integer.valueOf(restoreApnDelayStr);
- } catch (NumberFormatException e) {
- }
- }
- return RESTORE_DEFAULT_APN_DELAY;
- }
-
/**
* Based on the sim operator numeric, create a list for all possible pdps
* with all apns associated with that pdp
@@ -1580,10 +1380,7 @@
private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
notifyNoData(cause);
- if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) {
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- }
- else {
+ if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) {
reconnectAfterFail(cause, reason);
}
}
@@ -1638,7 +1435,7 @@
}
public void handleMessage (Message msg) {
-
+ if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg);
switch (msg.what) {
case EVENT_RECORDS_LOADED:
onRecordsLoaded();
@@ -1648,10 +1445,6 @@
onEnableNewApn();
break;
- case EVENT_RESTORE_DEFAULT_APN:
- onRestoreDefaultApn();
- break;
-
case EVENT_GPRS_DETACHED:
onGprsDetached();
break;
@@ -1710,7 +1503,7 @@
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
}
trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 60d4e8f..0c040e6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -154,6 +154,8 @@
static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted
static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted
+ static final int MAX_NUM_DATA_STATE_READS = 15;
+
private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
index e18da56..22b1f4f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
@@ -35,6 +35,7 @@
int smallestDigitsMnc;
String timezone;
String language;
+ int wifiChannelsAllowed;
MccEntry(int mnc, String iso, int smallestDigitsMCC) {
this(mnc, iso, smallestDigitsMCC, null);
@@ -45,11 +46,16 @@
}
MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) {
+ this(mnc, iso, smallestDigitsMCC, timezone, language, 0);
+ }
+
+ MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language, int wifiChannels) {
this.mcc = mnc;
this.iso = iso;
this.smallestDigitsMnc = smallestDigitsMCC;
this.timezone = timezone;
this.language = language;
+ this.wifiChannelsAllowed = wifiChannels;
}
public int compareTo(MccEntry o)
@@ -148,6 +154,23 @@
}
}
+ /**
+ * Given a GSM Mobile Country Code, returns
+ * the number of wifi channels allowed in that country.
+ * Returns 0 if unavailable
+ */
+ public static int wifiChannelsForMcc(int mcc) {
+ MccEntry entry;
+
+ entry = entryForMcc(mcc);
+
+ if (entry == null) {
+ return 0;
+ } else {
+ return entry.wifiChannelsAllowed;
+ }
+ }
+
static {
table = new ArrayList<MccEntry>(240);
@@ -169,7 +192,7 @@
*/
table.add(new MccEntry(202,"gr",2)); //Greece
- table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl")); //Netherlands (Kingdom of the)
+ table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl",13)); //Netherlands (Kingdom of the)
table.add(new MccEntry(206,"be",2)); //Belgium
table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France
table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of)
@@ -183,11 +206,11 @@
table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State
table.add(new MccEntry(226,"ro",2)); //Romania
table.add(new MccEntry(228,"ch",2,"Europe/Zurich","de")); //Switzerland (Confederation of)
- table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic
+ table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs", 13)); //Czech Republic
table.add(new MccEntry(231,"sk",2)); //Slovak Republic
- table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria
- table.add(new MccEntry(234,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland
- table.add(new MccEntry(235,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland
+ table.add(new MccEntry(232,"at",2,"Europe/Vienna","de", 13)); //Austria
+ table.add(new MccEntry(234,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland
+ table.add(new MccEntry(235,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland
table.add(new MccEntry(238,"dk",2)); //Denmark
table.add(new MccEntry(240,"se",2)); //Sweden
table.add(new MccEntry(242,"no",2)); //Norway
@@ -200,7 +223,7 @@
table.add(new MccEntry(257,"by",2)); //Belarus (Republic of)
table.add(new MccEntry(259,"md",2)); //Moldova (Republic of)
table.add(new MccEntry(260,"pl",2,"Europe/Warsaw")); //Poland (Republic of)
- table.add(new MccEntry(262,"de",2,"Europe/Berlin","de")); //Germany (Federal Republic of)
+ table.add(new MccEntry(262,"de",2,"Europe/Berlin","de", 13)); //Germany (Federal Republic of)
table.add(new MccEntry(266,"gi",2)); //Gibraltar
table.add(new MccEntry(268,"pt",2)); //Portugal
table.add(new MccEntry(270,"lu",2)); //Luxembourg
@@ -219,15 +242,15 @@
table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of)
table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia
table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of)
- table.add(new MccEntry(302,"ca",2)); //Canada
+ table.add(new MccEntry(302,"ca",2, "", "", 11)); //Canada
table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)
- table.add(new MccEntry(310,"us",3,"","en")); //United States of America
- table.add(new MccEntry(311,"us",3,"","en")); //United States of America
- table.add(new MccEntry(312,"us",3,"","en")); //United States of America
- table.add(new MccEntry(313,"us",3,"","en")); //United States of America
- table.add(new MccEntry(314,"us",3,"","en")); //United States of America
- table.add(new MccEntry(315,"us",3,"","en")); //United States of America
- table.add(new MccEntry(316,"us",3,"","en")); //United States of America
+ table.add(new MccEntry(310,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(311,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(312,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(313,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(314,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(315,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(316,"us",3,"","en", 11)); //United States of America
table.add(new MccEntry(330,"pr",2)); //Puerto Rico
table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands
table.add(new MccEntry(334,"mx",3)); //Mexico
@@ -283,8 +306,8 @@
table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of)
table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic
table.add(new MccEntry(438,"tm",2)); //Turkmenistan
- table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja")); //Japan
- table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja")); //Japan
+ table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja", 14)); //Japan
+ table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja", 14)); //Japan
table.add(new MccEntry(450,"kr",2)); //Korea (Republic of)
table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of)
table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China"
@@ -298,12 +321,12 @@
table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of)
table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of)
table.add(new MccEntry(502,"my",2)); //Malaysia
- table.add(new MccEntry(505,"au",2,"Australia/Sydney","en")); //Australia
+ table.add(new MccEntry(505,"au",2,"Australia/Sydney","en", 11)); //Australia
table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of)
table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste
table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the)
table.add(new MccEntry(520,"th",2)); //Thailand
- table.add(new MccEntry(525,"sg",2,"Singapore","en")); //Singapore (Republic of)
+ table.add(new MccEntry(525,"sg",2,"Singapore","en", 11)); //Singapore (Republic of)
table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam
table.add(new MccEntry(530,"nz",2,"Pacific/Auckland", "en")); //New Zealand
table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the)
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 89de867..224419e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -84,9 +84,13 @@
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
- phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE),
+ int authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+ RILConstants.SETUP_DATA_AUTH_NONE;
+
+ phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
- apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+ apn.password, Integer.toString(authType),
+ obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index e25de81..4272faa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -16,39 +16,29 @@
package com.android.internal.telephony.gsm;
-import android.app.ActivityManagerNative;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
import android.app.AlarmManager;
-import android.app.IActivityManager;
import android.content.Context;
-import android.content.res.Configuration;
+import android.net.wifi.WifiManager;
import android.os.AsyncResult;
-import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
-import android.os.Registrant;
+import android.provider.Settings;
import android.util.Log;
-import java.util.ArrayList;
-
-
-import static com.android.internal.telephony.TelephonyProperties.*;
import com.android.internal.telephony.AdnRecord;
import com.android.internal.telephony.AdnRecordCache;
import com.android.internal.telephony.AdnRecordLoader;
import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.gsm.SimCard;
-import com.android.internal.telephony.gsm.SmsMessage;
import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.IccVmFixedException;
import com.android.internal.telephony.IccVmNotSupportedException;
-import com.android.internal.telephony.PhoneProxy;
-
-
-
-
+import java.util.ArrayList;
/**
@@ -512,6 +502,29 @@
phone.setSystemLocale(language, country);
}
+ /**
+ * If the number of allowed wifi channels has not been set, set it based on
+ * the MCC of the SIM.
+ * @param mcc Mobile Country Code of the SIM
+ */
+ private void setWifiChannelsFromMccIfNeeded(int mcc) {
+ int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
+
+ if (wifiChannels != 0) {
+ Context context = phone.getContext();
+ // only set to this default if the user hasn't manually set it
+ try {
+ Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+ } catch (Settings.SettingNotFoundException e) {
+ WifiManager wM = (WifiManager)
+ context.getSystemService(Context.WIFI_SERVICE);
+ // don't persist
+ wM.setNumAllowedChannels(wifiChannels, false);
+ }
+ }
+ }
+
//***** Overridden from Handler
public void handleMessage(Message msg) {
AsyncResult ar;
@@ -552,12 +565,13 @@
Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_IMSI, null);
int mcc = Integer.parseInt(imsi.substring(0, 3));
setTimezoneFromMccIfNeeded(mcc);
setLocaleFromMccIfNeeded(mcc);
+ setWifiChannelsFromMccIfNeeded(mcc);
break;
case EVENT_GET_MBI_DONE:
@@ -1178,7 +1192,7 @@
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_LOADED, null);
}
@@ -1203,7 +1217,7 @@
/* broadcast intent SIM_READY here so that we can make sure
READY is sent before IMSI ready
*/
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_READY, null);
fetchSimRecords();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 9af3aa6..6c56682 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -17,469 +17,37 @@
package com.android.internal.telephony.gsm;
import android.app.ActivityManagerNative;
-import android.content.Intent;
import android.content.res.Configuration;
-import android.os.AsyncResult;
import android.os.RemoteException;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
import android.util.Log;
-import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
/**
- * Note: this class shares common code with RuimCard, consider a base class to minimize code
- * duplication.
* {@hide}
*/
-public final class SimCard extends Handler implements IccCard {
- static final String LOG_TAG="GSM";
-
- //***** Instance Variables
- private static final boolean DBG = true;
-
- private GSMPhone phone;
- private CommandsInterface.IccStatus status = null;
- private boolean mDesiredPinLocked;
- private boolean mDesiredFdnEnabled;
- private boolean mSimPinLocked = true; // Default to locked
- private boolean mSimFdnEnabled = false; // Default to disabled.
- // Will be updated when SIM_READY.
-
- //***** Constants
-
- // FIXME I hope this doesn't conflict with the Dialer's notifications
- static final int NOTIFICATION_ID_SIM_STATUS = 33456;
-
- //***** Event Constants
-
- static final int EVENT_SIM_LOCKED_OR_ABSENT = 1;
- static final int EVENT_GET_SIM_STATUS_DONE = 2;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
- static final int EVENT_PINPUK_DONE = 4;
- static final int EVENT_REPOLL_STATUS_DONE = 5;
- static final int EVENT_SIM_READY = 6;
- static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
- static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
- static final int EVENT_CHANGE_SIM_PASSWORD_DONE = 9;
- static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
- static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
- //***** Constructor
+public final class SimCard extends IccCard {
SimCard(GSMPhone phone) {
- this.phone = phone;
+ super(phone, "GSM", true);
- phone.mCM.registerForSIMLockedOrAbsent(
- this, EVENT_SIM_LOCKED_OR_ABSENT, null);
-
- phone.mCM.registerForOffOrNotAvailable(
- this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
- phone.mCM.registerForSIMReady(
- this, EVENT_SIM_READY, null);
-
+ mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+ mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null);
updateStateProperty();
}
+ @Override
public void dispose() {
//Unregister for all events
- phone.mCM.unregisterForSIMLockedOrAbsent(this);
- phone.mCM.unregisterForOffOrNotAvailable(this);
- phone.mCM.unregisterForSIMReady(this);
+ mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler);
+ mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+ mPhone.mCM.unregisterForSIMReady(mHandler);
}
- protected void finalize() {
- if(DBG) Log.d(LOG_TAG, "SimCard finalized");
- }
-
- //***** SimCard implementation
-
- public State
- getState() {
- if (status == null) {
- switch(phone.mCM.getRadioState()) {
- /* This switch block must not return anything in
- * State.isLocked() or State.ABSENT.
- * If it does, handleSimStatus() may break
- */
- case RADIO_OFF:
- case RADIO_UNAVAILABLE:
- case SIM_NOT_READY:
- return State.UNKNOWN;
- case SIM_LOCKED_OR_ABSENT:
- //this should be transient-only
- return State.UNKNOWN;
- case SIM_READY:
- return State.READY;
- }
- } else {
- switch (status) {
- case ICC_ABSENT: return State.ABSENT;
- case ICC_NOT_READY: return State.UNKNOWN;
- case ICC_READY: return State.READY;
- case ICC_PIN: return State.PIN_REQUIRED;
- case ICC_PUK: return State.PUK_REQUIRED;
- case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
- }
- }
-
- Log.e(LOG_TAG, "GsmSimCard.getState(): case should never be reached");
- return State.UNKNOWN;
- }
-
- private RegistrantList absentRegistrants = new RegistrantList();
- private RegistrantList pinLockedRegistrants = new RegistrantList();
- private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
- public void registerForAbsent(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- absentRegistrants.add(r);
-
- if (getState() == State.ABSENT) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForAbsent(Handler h) {
- absentRegistrants.remove(h);
- }
-
- public void registerForNetworkLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- networkLockedRegistrants.add(r);
-
- if (getState() == State.NETWORK_LOCKED) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForNetworkLocked(Handler h) {
- networkLockedRegistrants.remove(h);
- }
-
- public void registerForLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- pinLockedRegistrants.add(r);
-
- if (getState().isPinLocked()) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForLocked(Handler h) {
- pinLockedRegistrants.remove(h);
- }
-
-
- public void supplyPin (String pin, Message onComplete) {
- phone.mCM.supplyIccPin(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk (String puk, String newPin, Message onComplete) {
- phone.mCM.supplyIccPuk(puk, newPin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPin2 (String pin2, Message onComplete) {
- phone.mCM.supplyIccPin2(pin2,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
- phone.mCM.supplyIccPuk2(puk2, newPin2,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyNetworkDepersonalization (String pin, Message onComplete) {
- if(DBG) log("Network Despersonalization: " + pin);
- phone.mCM.supplyNetworkDepersonalization(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public boolean getIccLockEnabled() {
- return mSimPinLocked;
- }
-
- public boolean getIccFdnEnabled() {
- return mSimFdnEnabled;
- }
-
- public void setIccLockEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- mDesiredPinLocked = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
- }
-
- public void setIccFdnEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX +
- CommandsInterface.SERVICE_CLASS_SMS;
-
- mDesiredFdnEnabled = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
- }
-
- public void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin2(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public String getServiceProviderName () {
- return phone.mSIMRecords.getServiceProviderName();
- }
-
- //***** Handler implementation
@Override
- public void handleMessage(Message msg){
- AsyncResult ar;
- int serviceClassX;
-
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- switch (msg.what) {
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- status = null;
- updateStateProperty();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null);
- break;
- case EVENT_SIM_READY:
- //TODO: put facility read in SIM_READY now, maybe in REG_NW
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
- break;
- case EVENT_SIM_LOCKED_OR_ABSENT:
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- break;
- case EVENT_GET_SIM_STATUS_DONE:
- ar = (AsyncResult)msg.obj;
-
- getSimStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- // a PIN/PUK/PIN2/PUK2/Network Personalization
- // request has completed. ar.userObj is the response Message
- // Repoll before returning
- ar = (AsyncResult)msg.obj;
- // TODO should abstract these exceptions
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- phone.mCM.getIccStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- // Finished repolling status after PIN operation
- // ar.userObj is the response messaeg
- // ar.userObj.obj is already an AsyncResult with an
- // appropriate exception filled in if applicable
-
- ar = (AsyncResult)msg.obj;
- getSimStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_QUERY_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFacilityLock(ar);
- break;
- case EVENT_QUERY_FACILITY_FDN_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFdnEnabled(ar);
- break;
- case EVENT_CHANGE_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mSimPinLocked = mDesiredPinLocked;
- if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
- "mSimPinLocked= " + mSimPinLocked);
- } else {
- Log.e(LOG_TAG, "Error change facility lock with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_FACILITY_FDN_DONE:
- ar = (AsyncResult)msg.obj;
-
- if (ar.exception == null) {
- mSimFdnEnabled = mDesiredFdnEnabled;
- if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
- "mSimFdnEnabled=" + mSimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "Error change facility fdn with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_SIM_PASSWORD_DONE:
- ar = (AsyncResult)msg.obj;
- if(ar.exception != null) {
- Log.e(LOG_TAG, "Error in change sim password with exception"
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- default:
- Log.e(LOG_TAG, "[GsmSimCard] Unknown Event " + msg.what);
- }
- }
-
-
- //***** Private methods
-
- /**
- * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFacilityLock(AsyncResult ar) {
- if(ar.exception != null) {
- if (DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mSimPinLocked = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimPinLocked);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- /**
- * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFdnEnabled(AsyncResult ar) {
- if(ar.exception != null) {
- if(DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mSimFdnEnabled = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- private void
- getSimStatusDone(AsyncResult ar) {
- if (ar.exception != null) {
- Log.e(LOG_TAG,"Error getting ICC status. "
- + "RIL_REQUEST_GET_ICC_STATUS should "
- + "never return an error", ar.exception);
- return;
- }
-
- CommandsInterface.IccStatus newStatus
- = (CommandsInterface.IccStatus) ar.result;
-
- handleSimStatus(newStatus);
- }
-
- private void
- handleSimStatus(CommandsInterface.IccStatus newStatus) {
- boolean transitionedIntoPinLocked;
- boolean transitionedIntoAbsent;
- boolean transitionedIntoNetworkLocked;
-
- SimCard.State oldState, newState;
-
- oldState = getState();
- status = newStatus;
- newState = getState();
-
- updateStateProperty();
-
- transitionedIntoPinLocked = (
- (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
- || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
- transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
- transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
- && newState == State.NETWORK_LOCKED);
-
- if (transitionedIntoPinLocked) {
- if(DBG) log("Notify SIM pin or puk locked.");
- pinLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
- (newState == State.PIN_REQUIRED) ?
- INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
- } else if (transitionedIntoAbsent) {
- if(DBG) log("Notify SIM missing.");
- absentRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null);
- } else if (transitionedIntoNetworkLocked) {
- if(DBG) log("Notify SIM network locked.");
- networkLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
- INTENT_VALUE_LOCKED_NETWORK);
- }
- }
-
- public void broadcastSimStateChangedIntent(String value, String reason) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
- intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value);
- intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason);
- if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value
- + " reason " + reason);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+ public String getServiceProviderName () {
+ return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName();
}
public void updateImsiConfiguration(String imsi) {
@@ -494,19 +62,8 @@
try {
ActivityManagerNative.getDefault().updateConfiguration(config);
} catch (RemoteException e) {
+ Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration");
}
}
}
-
- private void
- updateStateProperty() {
- phone.setSystemProperty(
- TelephonyProperties.PROPERTY_SIM_STATE,
- getState().toString());
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[GsmSimCard] " + msg);
- }
}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index af59126..93721ff 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -519,12 +519,12 @@
long getSCTimestampMillis() {
// TP-Service-Centre-Time-Stamp
- int year = IccUtils.bcdByteToInt(pdu[cur++]);
- int month = IccUtils.bcdByteToInt(pdu[cur++]);
- int day = IccUtils.bcdByteToInt(pdu[cur++]);
- int hour = IccUtils.bcdByteToInt(pdu[cur++]);
- int minute = IccUtils.bcdByteToInt(pdu[cur++]);
- int second = IccUtils.bcdByteToInt(pdu[cur++]);
+ int year = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int month = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int day = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int second = IccUtils.gsmBcdByteToInt(pdu[cur++]);
// For the timezone, the most significant bit of the
// least signficant nibble is the sign byte
@@ -534,11 +534,9 @@
byte tzByte = pdu[cur++];
// Mask out sign bit.
- int timezoneOffset = IccUtils
- .bcdByteToInt((byte) (tzByte & (~0x08)));
+ int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
- timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset
- : -timezoneOffset;
+ timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
Time time = new Time(Time.TIMEZONE_UTC);
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index f71ea48..11b3fd6 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -27,10 +27,11 @@
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataCallState;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.Phone;
import java.util.ArrayList;
@@ -103,39 +104,8 @@
//***** CommandsInterface implementation
- public void getIccStatus(Message result) {
- switch (mState) {
- case SIM_READY:
- resultSuccess(result, IccStatus.ICC_READY);
- break;
-
- case SIM_LOCKED_OR_ABSENT:
- returnSimLockedStatus(result);
- break;
-
- default:
- resultSuccess(result, IccStatus.ICC_NOT_READY);
- break;
- }
- }
-
- private void returnSimLockedStatus(Message result) {
- switch (mSimLockedState) {
- case REQUIRE_PIN:
- Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN");
- resultSuccess(result, IccStatus.ICC_PIN);
- break;
-
- case REQUIRE_PUK:
- Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK");
- resultSuccess(result, IccStatus.ICC_PUK);
- break;
-
- default:
- Log.i(LOG_TAG,
- "[SimCmd] returnSimLockedStatus: mSimLockedState==NONE !?");
- break;
- }
+ public void getIccCardStatus(Message result) {
+ unimplemented(result);
}
public void supplyIccPin(String pin, Message result) {
@@ -974,7 +944,7 @@
}
public void setupDataCall(String radioTechnology, String profile, String apn, String user,
- String password, Message result) {
+ String password, String authType, Message result) {
unimplemented(result);
}
diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java
index 79cedb0..00440b43 100644
--- a/test-runner/android/test/AndroidTestRunner.java
+++ b/test-runner/android/test/AndroidTestRunner.java
@@ -158,16 +158,18 @@
mTestResult.addListener(testListener);
}
+ Context testContext = mInstrumentation.getContext();
for (TestCase testCase : mTestCases) {
- setContextIfAndroidTestCase(testCase, mContext);
+ setContextIfAndroidTestCase(testCase, mContext, testContext);
setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
testCase.run(mTestResult);
}
}
- private void setContextIfAndroidTestCase(Test test, Context context) {
+ private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) {
if (AndroidTestCase.class.isAssignableFrom(test.getClass())) {
((AndroidTestCase) test).setContext(context);
+ ((AndroidTestCase) test).setTestContext(testContext);
}
}
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 859b2e5..4bd9528 100644
--- a/test-runner/android/test/IsolatedContext.java
+++ b/test-runner/android/test/IsolatedContext.java
@@ -2,6 +2,8 @@
import com.google.android.collect.Lists;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
import android.content.ContextWrapper;
import android.content.ContentResolver;
import android.content.Intent;
@@ -11,6 +13,8 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import java.util.List;
import java.io.File;
@@ -22,6 +26,7 @@
public class IsolatedContext extends ContextWrapper {
private ContentResolver mResolver;
+ private final MockAccountManager mMockAccountManager;
private List<Intent> mBroadcastIntents = Lists.newArrayList();
@@ -29,6 +34,7 @@
ContentResolver resolver, Context targetContext) {
super(targetContext);
mResolver = resolver;
+ mMockAccountManager = new MockAccountManager();
}
/** Returns the list of intents that were broadcast since the last call to this method. */
@@ -79,10 +85,23 @@
@Override
public Object getSystemService(String name) {
- // No services exist in this context.
+ if (Context.ACCOUNT_SERVICE.equals(name)) {
+ return mMockAccountManager;
+ }
+ // No other services exist in this context.
return null;
}
+ private class MockAccountManager extends AccountManager {
+ public MockAccountManager() {
+ super(IsolatedContext.this, null /* IAccountManager */, null /* handler */);
+ }
+
+ public void addOnAccountsUpdatedListener(OnAccountsUpdatedListener listener,
+ Handler handler, boolean updateImmediately) {
+ // do nothing
+ }
+ }
@Override
public File getFilesDir() {
return new File("/dev/null");
diff --git a/test-runner/android/test/RenamingDelegatingContext.java b/test-runner/android/test/RenamingDelegatingContext.java
index 3f64340..0ea43ab 100644
--- a/test-runner/android/test/RenamingDelegatingContext.java
+++ b/test-runner/android/test/RenamingDelegatingContext.java
@@ -6,6 +6,8 @@
import android.content.ContextWrapper;
import android.content.ContentProvider;
import android.database.sqlite.SQLiteDatabase;
+import android.os.FileUtils;
+import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
@@ -22,6 +24,8 @@
private Context mFileContext;
private String mFilePrefix = null;
+ private File mCacheDir;
+ private final Object mSync = new Object();
private Set<String> mDatabaseNames = Sets.newHashSet();
private Set<String> mFileNames = Sets.newHashSet();
@@ -136,6 +140,11 @@
return false;
}
}
+
+ @Override
+ public File getDatabasePath(String name) {
+ return mFileContext.getDatabasePath(renamedFileName(name));
+ }
@Override
public String[] databaseList() {
@@ -179,6 +188,32 @@
public String[] fileList() {
return mFileNames.toArray(new String[]{});
}
+
+ /**
+ * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
+ * one) and return it instead. This code is basically getCacheDir(), except it uses the real
+ * cache dir as the parent directory and creates a test cache dir inside that.
+ */
+ @Override
+ public File getCacheDir() {
+ synchronized (mSync) {
+ if (mCacheDir == null) {
+ mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache"));
+ }
+ if (!mCacheDir.exists()) {
+ if(!mCacheDir.mkdirs()) {
+ Log.w("RenamingDelegatingContext", "Unable to create cache directory");
+ return null;
+ }
+ FileUtils.setPermissions(
+ mCacheDir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ }
+ return mCacheDir;
+ }
+
// /**
// * Given an array of files returns only those whose names indicate that they belong to this
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index 772d75c..a860bb3 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -19,9 +19,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.net.Uri;
+import android.accounts.Account;
/**
* If you would like to test sync a single provider with an
@@ -44,12 +44,12 @@
* Syncs the specified provider.
* @throws Exception
*/
- protected void syncProvider(Uri uri, String account, String authority) throws Exception {
+ protected void syncProvider(Uri uri, String accountName, String authority) throws Exception {
Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ Account account = new Account(accountName, "com.google.GAIA");
- mContentResolver.startSync(uri, extras);
+ ContentResolver.requestSync(account, authority, extras);
long startTimeInMillis = SystemClock.elapsedRealtime();
long endTimeInMillis = startTimeInMillis + MAX_TIME_FOR_SYNC_IN_MINS * 60000;
@@ -64,7 +64,7 @@
break;
}
- if (isSyncActive(account, authority)) {
+ if (ContentResolver.isSyncActive(account, authority)) {
counter = 0;
continue;
}
@@ -73,24 +73,7 @@
}
protected void cancelSyncsandDisableAutoSync() {
- try {
- ContentResolver.getContentService().setListenForNetworkTickles(false);
- } catch (RemoteException e) {
- }
- mContentResolver.cancelSync(null);
- }
-
- /**
- * This method tests if any sync is active or not. Sync is considered to be active if the
- * entry is in either the Pending or Active tables.
- * @return
- */
- private boolean isSyncActive(String account, String authority) {
- try {
- return ContentResolver.getContentService().isSyncActive(account,
- authority);
- } catch (RemoteException e) {
- return false;
- }
+ ContentResolver.setMasterSyncAutomatically(false);
+ ContentResolver.cancelSync(null /* all accounts */, null /* all authorities */);
}
}
diff --git a/test-runner/android/test/TestRunner.java b/test-runner/android/test/TestRunner.java
index efa2480..012df35 100644
--- a/test-runner/android/test/TestRunner.java
+++ b/test-runner/android/test/TestRunner.java
@@ -39,7 +39,7 @@
* and you probably will not need to instantiate, extend, or call this
* class yourself. See the full {@link android.test} package description
* to learn more about testing Android applications.
- *
+ *
* {@hide} Not needed for 1.0 SDK.
*/
public class TestRunner implements PerformanceTestCase.Intermediates {
@@ -84,6 +84,7 @@
super();
}
+ @Override
public void run(TestResult result) {
result.addListener(this);
super.run(result);
@@ -301,7 +302,7 @@
if (mMode == PERFORMANCE) {
runInPerformanceMode(test, className, false, className);
} else if (mMode == PROFILING) {
- //Need a way to mark a test to be run in profiling mode or not.
+ //Need a way to mark a test to be run in profiling mode or not.
startProfiling();
test.run();
finishProfiling();
@@ -337,6 +338,7 @@
AndroidTestCase testcase = (AndroidTestCase) test;
try {
testcase.setContext(mContext);
+ testcase.setTestContext(mContext);
} catch (Exception ex) {
Log.i("TestHarness", ex.toString());
}
@@ -700,7 +702,7 @@
}
} catch (ClassNotFoundException e) {
return 1; // this gets the count right, because either this test
- // is missing, and it will fail when run or it is a single Junit test to be run.
+ // is missing, and it will fail when run or it is a single Junit test to be run.
}
return 0;
}
diff --git a/test-runner/android/test/mock/MockContentProvider.java b/test-runner/android/test/mock/MockContentProvider.java
index d04fc44..74f86d8 100644
--- a/test-runner/android/test/mock/MockContentProvider.java
+++ b/test-runner/android/test/mock/MockContentProvider.java
@@ -18,7 +18,11 @@
import android.content.ContentValues;
import android.content.IContentProvider;
-import android.content.ISyncAdapter;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.content.ContentProviderResult;
+import android.content.ContentProviderOperation;
+import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
@@ -30,6 +34,7 @@
import android.os.ParcelFileDescriptor;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* Mock implementation of IContentProvider that does nothing. All methods are non-functional and
@@ -48,6 +53,10 @@
return 0;
}
+ public Uri insertEntity(Uri uri, Entity entities) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, IContentObserver observer,
@@ -62,11 +71,6 @@
}
@SuppressWarnings("unused")
- public ISyncAdapter getSyncAdapter() throws RemoteException {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("unused")
public String getType(Uri url) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -87,19 +91,33 @@
throws FileNotFoundException {
throw new UnsupportedOperationException("unimplemented mock method");
}
-
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
String sortOrder) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public int update(Uri url, ContentValues values, String selection, String[] selectionArgs)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
public IBinder asBinder() {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index d5cd6ef..4a50c5d 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -139,6 +139,11 @@
}
@Override
+ public int checkSignatures(int uid1, int uid2) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
throw new UnsupportedOperationException();
}
@@ -292,9 +297,6 @@
throw new UnsupportedOperationException();
}
- /**
- * @hide - to match hiding in superclass
- */
@Override
public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 845f547..d94327a 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -52,6 +52,7 @@
<uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
+ <uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
<uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
diff --git a/tests/AndroidTests/res/raw/v21_simple_1.vcf b/tests/AndroidTests/res/raw/v21_simple_1.vcf
new file mode 100644
index 0000000..6aabb4c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_1.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:Ando;Roid;
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple_2.vcf b/tests/AndroidTests/res/raw/v21_simple_2.vcf
new file mode 100644
index 0000000..f0d5ab5
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_2.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+FN:Ando Roid
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple.vcf b/tests/AndroidTests/res/raw/v21_simple_3.vcf
similarity index 100%
rename from tests/AndroidTests/res/raw/v21_simple.vcf
rename to tests/AndroidTests/res/raw/v21_simple_3.vcf
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
index 7ada698..bc06b7e 100755
--- a/tests/AndroidTests/run_test.sh
+++ b/tests/AndroidTests/run_test.sh
@@ -1,4 +1,4 @@
framework=/system/framework
bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
-adb shell exec dalvikvm -Xbootclasspath:$bpath -cp /system/app/AndroidTests.apk:/data/app/com.android.unit_tests.apk \
+adb shell exec dalvikvm -Xbootclasspath:$bpath -cp /system/app/AndroidTests.apk:/data/app/com.android.unit_tests.apk:/data/app/AndroidTests.apk \
com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index f0ba573..02af547 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -18,9 +18,11 @@
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.cdma.SmsMessage;
import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
import com.android.internal.util.HexDump;
@@ -28,16 +30,77 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
import java.util.Iterator;
import java.lang.Integer;
-import android.util.Log;
-
public class CdmaSmsTest extends AndroidTestCase {
private final static String LOG_TAG = "CDMA";
@SmallTest
+ public void testCdmaSmsAddrParsing() throws Exception {
+ CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 10);
+ assertEquals(addr.origBytes.length, 10);
+ byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
+ for (int i = 0; i < data.length; i++) {
+ assertEquals(addr.origBytes[i], data[i]);
+ }
+ addr = CdmaSmsAddress.parse("(650) 253-1000");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 10);
+ assertEquals(addr.origBytes.length, 10);
+ byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
+ for (int i = 0; i < data2.length; i++) {
+ assertEquals(addr.origBytes[i], data2[i]);
+ }
+ addr = CdmaSmsAddress.parse("(+886) 917 222 555");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 12);
+ assertEquals(addr.origBytes.length, 12);
+ byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5};
+ for (int i = 0; i < data3.length; i++) {
+ assertEquals(addr.origBytes[i], data3[i]);
+ }
+ addr = CdmaSmsAddress.parse("(650) *253-1000 #600");
+ byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10};
+ for (int i = 0; i < data4.length; i++) {
+ assertEquals(addr.origBytes[i], data4[i]);
+ }
+ String input = "x@y.com,a@b.com";
+ addr = CdmaSmsAddress.parse(input);
+ assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 15);
+ assertEquals(addr.origBytes.length, 15);
+ assertEquals(new String(addr.origBytes), input);
+ addr = CdmaSmsAddress.parse("foo bar");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 6);
+ assertEquals(addr.origBytes.length, 6);
+ assertEquals(new String(addr.origBytes), "foobar");
+ addr = CdmaSmsAddress.parse("f\noo\tb a\rr");
+ assertEquals(new String(addr.origBytes), "foobar");
+ assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
+ }
+
+ @SmallTest
public void testUserData7bitGsm() throws Exception {
String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98";
BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu));
@@ -84,6 +147,15 @@
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \u007f standard \u0000 SMS";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals("Test standard SMS", revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \n standard \r SMS";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
@@ -105,6 +177,21 @@
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "1234567";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "12345678901234567890123456789012345678901234567890" +
+ "12345678901234567890123456789012345678901234567890" +
+ "12345678901234567890123456789012345678901234567890" +
+ "1234567890";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \u007f illegal \u0000 SMS chars";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals("Test illegal SMS chars", revBearerData.userData.payloadStr);
userData.payloadStr = "More @ testing\nis great^|^~woohoo";
revBearerData = BearerData.decode(BearerData.encode(bearerData));
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
@@ -153,6 +240,12 @@
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "1234567";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
@@ -576,6 +669,16 @@
BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4));
assertEquals(bd4.alert, 3);
assertEquals(bd4.userData.payloadStr, "Test Alert 3");
+ String pdu5 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840E1062D3D39A900C028000";
+ BearerData bd5 = BearerData.decode(HexDump.hexStringToByteArray(pdu5));
+ assertEquals(bd5.alert, BearerData.ALERT_MEDIUM_PRIO);
+ assertEquals(bd5.userData.payloadStr, "test message delivery alert (with 8 bits)");
+ String pdu6 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840C1062D3D39A900C00";
+ BearerData bd6 = BearerData.decode(HexDump.hexStringToByteArray(pdu6));
+ assertEquals(bd6.userData.payloadStr, "test message delivery alert (with 0 bits)");
+ assertEquals(bd6.alertIndicatorSet, false);
}
@SmallTest
@@ -707,4 +810,24 @@
assertEquals(bd4.userData.payloadStr, "ABCDEFG");
}
+ @SmallTest
+ public void testUserDataHeaderWithEightCharMsg() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 55;
+ SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+ concatRef.refNumber = 0xEE;
+ concatRef.msgCount = 2;
+ concatRef.seqNumber = 2;
+ concatRef.isEightBits = true;
+ SmsHeader smsHeader = new SmsHeader();
+ smsHeader.concatRef = concatRef;
+ UserData userData = new UserData();
+ userData.payloadStr = "01234567";
+ userData.userDataHeader = smsHeader;
+ bearerData.userData = userData;
+ byte[] encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ }
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
deleted file mode 100644
index b7f562d..0000000
--- a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
+++ /dev/null
@@ -1,773 +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 com.android.unit_tests;
-
-import android.content.ContentValues;
-import android.syncml.pim.PropertyNode;
-import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VNode;
-import android.syncml.pim.vcard.VCardException;
-import android.syncml.pim.vcard.VCardParser_V21;
-import android.syncml.pim.vcard.VCardParser_V30;
-import android.test.AndroidTestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Vector;
-
-public class VCardTests extends AndroidTestCase {
-
- private class PropertyNodesVerifier {
- private HashMap<String, Vector<PropertyNode>> mPropertyNodeMap;
- public PropertyNodesVerifier(PropertyNode... nodes) {
- mPropertyNodeMap = new HashMap<String, Vector<PropertyNode>>();
- for (PropertyNode propertyNode : nodes) {
- String propName = propertyNode.propName;
- Vector<PropertyNode> expectedNodes =
- mPropertyNodeMap.get(propName);
- if (expectedNodes == null) {
- expectedNodes = new Vector<PropertyNode>();
- mPropertyNodeMap.put(propName, expectedNodes);
- }
- expectedNodes.add(propertyNode);
- }
- }
-
- public void verify(VNode vnode) {
- for (PropertyNode propertyNode : vnode.propList) {
- String propName = propertyNode.propName;
- Vector<PropertyNode> nodes = mPropertyNodeMap.get(propName);
- if (nodes == null) {
- fail("Unexpected propName \"" + propName + "\" exists.");
- }
- boolean successful = false;
- int size = nodes.size();
- for (int i = 0; i < size; i++) {
- PropertyNode expectedNode = nodes.get(i);
- if (expectedNode.propName.equals(propName)) {
- if (expectedNode.equals(propertyNode)) {
- successful = true;
- nodes.remove(i);
- if (nodes.size() == 0) {
- mPropertyNodeMap.remove(propName);
- }
- break;
- } else {
- fail("Property \"" + propName + "\" has wrong value.\n"
- + "expected: " + expectedNode.toString()
- + "\n actual: " + propertyNode.toString());
- }
- }
- }
- if (!successful) {
- fail("Unexpected property \"" + propName + "\" exists.");
- }
- }
- if (mPropertyNodeMap.size() != 0) {
- Vector<String> expectedProps = new Vector<String>();
- for (Vector<PropertyNode> nodes : mPropertyNodeMap.values()) {
- for (PropertyNode node : nodes) {
- expectedProps.add(node.propName);
- }
- }
- fail("expected props " + Arrays.toString(expectedProps.toArray()) +
- " was not found");
- }
- }
- }
-
- public void testV21SimpleCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("N", "Ando;Roid;",
- Arrays.asList("Ando", "Roid", ""),
- null, null, null, null),
- new PropertyNode("FN", "Ando Roid",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21BackslashCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
- Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
- null, null, null, null),
- new PropertyNode("FN", "A;B\\C\\;D:E\\\\",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21ComplicatedCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- ContentValues contentValuesForPhoto = new ContentValues();
- contentValuesForPhoto.put("ENCODING", "BASE64");
- // Push data into int array at first since values like 0x80 are
- // interpreted as int by the compiler and casting all of them is
- // cumbersome...
- int[] photoIntArray = {
- 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
- 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
- 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
- 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
- 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
- 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
- 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
- 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
- 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
- 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
- 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
- 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
- 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
- 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
- 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
- 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
- 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
- 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
- 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
- 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
- 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
- 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
- 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
- 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
- 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
- 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
- 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
- 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
- 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
- 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
- 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
- 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
- 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
- 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
- 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
- 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
- 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
- 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
- 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
- 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
- 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
- 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
- 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
- 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
- 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
- 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
- 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
- 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
- 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
- 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
- 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
- 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
- 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
- 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
- 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
- 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
- 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
- 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
- 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
- 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
- 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
- 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
- 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
- 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
- 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
- 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
- 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
- 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
- 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
- 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
- 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
- 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
- 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
- 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
- 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
- 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
- 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
- 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
- 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
- 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
- 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
- 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
- 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
- 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
- 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
- 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
- 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
- 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
- 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
- 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
- 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
- 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
- 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
- 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
- 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
- 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
- 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
- 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
- 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
- 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
- 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
- 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
- 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
- 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
- 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
- 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
- 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
- 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
- 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
- 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
- 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
- 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
- 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
- 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
- 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
- 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
- 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
- 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
- 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
- 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
- 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
- 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
- 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
- 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
- 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
- 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
- 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
- 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
- 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
- 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
- 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
- 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
- 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
- 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
- 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
- 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
- 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
- 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
- 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
- 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
- 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
- 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
- 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
- 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
- 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
- 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
- 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
- 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
- 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
- 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
- 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
- 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
- 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
- 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
- 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
- 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
- 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
- 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
- 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
- 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
- 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
- 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
- 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
- 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
- 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
- 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
- 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
- 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
- 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
- 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
- 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
- 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
- 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
- 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
- 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
- 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
- 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
- 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
- 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
- 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
- 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
- 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
- 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
- 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
- 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
- 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
- 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
- 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
- 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
- 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
- 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
- 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
- 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
- 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
- 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
- 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
- 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
- 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
- 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
- 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
- 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
- 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
- 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
- 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
- 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
- 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
- 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
- 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
- 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
- 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
- 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
- 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
- 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
- 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
- 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
- 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
- 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
- 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
- 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
- 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
- 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
- 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
- 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
- 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
- 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
- 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
- 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
- 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
- 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
- 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
- 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
- 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
- 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
- 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
- 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
- 0x0c, 0xd1, 0x00, 0xff, 0xd9};
- int length = photoIntArray.length;
- byte[] photoByteArray = new byte[length];
- for (int i = 0; i < length; i++) {
- photoByteArray[i] = (byte)photoIntArray[i];
- }
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
- Arrays.asList("Gump", "Forrest",
- "Hoge", "Pos", "Tao"),
- null, null, null, null),
- new PropertyNode("FN", "Joe Due",
- null, null, null, null, null),
- new PropertyNode("ORG",
- "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
- Arrays.asList("Gump Shrimp Co.",
- "Sales Dept.;Manager",
- "Fish keeper"),
- null, null, null, null),
- new PropertyNode("ROLE", "Fish Cake Keeper!",
- null, null, null, null, null),
- new PropertyNode("TITLE", "Shrimp Man",
- null, null, null, null, null),
- new PropertyNode("X-CLASS", "PUBLIC",
- null, null, null, null, null),
- new PropertyNode("TEL", "(111) 555-1212",
- null, null, null,
- new HashSet<String>(Arrays.asList("WORK", "VOICE")), null),
- new PropertyNode("TEL", "(404) 555-1212",
- null, null, null,
- new HashSet<String>(Arrays.asList("HOME", "VOICE")), null),
- new PropertyNode("TEL", "0311111111",
- null, null, null,
- new HashSet<String>(Arrays.asList("CELL")), null),
- new PropertyNode("TEL", "0322222222",
- null, null, null,
- new HashSet<String>(Arrays.asList("VIDEO")), null),
- new PropertyNode("TEL", "0333333333",
- null, null, null,
- new HashSet<String>(Arrays.asList("VOICE")), null),
- new PropertyNode("ADR",
- ";;100 Waters Edge;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "100 Waters Edge", "Baytown",
- "LA", "30314", "United States of America"),
- null, null,
- new HashSet<String>(Arrays.asList("WORK")), null),
- new PropertyNode("LABEL",
- "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("WORK")), null),
- new PropertyNode("ADR",
- ";;42 Plantation St.;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "42 Plantation St.", "Baytown",
- "LA", "30314", "United States of America"), null, null,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("LABEL",
- "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("EMAIL", "forrestgump@walladalla.com",
- null, null, null,
- new HashSet<String>(Arrays.asList("PREF", "INTERNET")), null),
- new PropertyNode("EMAIL", "cell@example.com",
- null, null, null,
- new HashSet<String>(Arrays.asList("CELL")), null),
- new PropertyNode("NOTE", "The following note is the example from RFC 2045.",
- null, null, null, null, null),
- new PropertyNode("NOTE",
- "Now's the time for all folk to come to the aid of their country.",
- null, null, contentValuesForQP, null, null),
- new PropertyNode("PHOTO", null,
- null, photoByteArray, contentValuesForPhoto,
- new HashSet<String>(Arrays.asList("JPEG")), null),
- new PropertyNode("X-ATTRIBUTE", "Some String",
- null, null, null, null, null),
- new PropertyNode("BDAY", "19800101",
- null, null, null, null, null),
- new PropertyNode("GEO", "35.6563854,139.6994233",
- null, null, null, null, null),
- new PropertyNode("URL", "http://www.example.com/",
- null, null, null, null, null),
- new PropertyNode("REV", "20080424T195243Z",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21Japanese1() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- contentValuesForQP.put("CHARSET", "SHIFT_JIS");
- // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
- // vCard 2.1/3.0 specification does not allow multiple values.
- // Do not need to handle it as multiple values.
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "0300000000",
- null, null, null,
- new HashSet<String>(Arrays.asList("VOICE", "PREF")), null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21Japanese2() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- contentValuesForQP.put("CHARSET", "SHIFT_JIS");
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
- Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
- "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("FN",
- "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
- null, null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- ("\uFF71\uFF9D\uFF84\uFF9E\uFF73" +
- ";\uFF9B\uFF72\uFF84\uFF9E\u0031;;;"),
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("ADR",
- (";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
- "\u968E;;;;150-8512;"),
- Arrays.asList("",
- "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
- "\u0036\u968E", "", "", "", "150-8512", ""),
- null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("NOTE", "\u30E1\u30E2",
- null, null, contentValuesForQP, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21MultipleEntryCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(3, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "9",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-SECRET")), null),
- new PropertyNode("TEL", "10",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-HOTEL")), null),
- new PropertyNode("TEL", "11",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-SCHOOL")), null),
- new PropertyNode("TEL", "12",
- null, null, null,
- new HashSet<String>(Arrays.asList("FAX", "HOME")), null));
- verifier.verify(builder.vNodeList.get(0));
-
- verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "13",
- null, null, null,
- new HashSet<String>(Arrays.asList("MODEM")), null),
- new PropertyNode("TEL", "14",
- null, null, null,
- new HashSet<String>(Arrays.asList("PAGER")), null),
- new PropertyNode("TEL", "15",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-FAMILY")), null),
- new PropertyNode("TEL", "16",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-GIRL")), null));
- verifier.verify(builder.vNodeList.get(1));
- verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "17",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-BOY")), null),
- new PropertyNode("TEL", "18",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-FRIEND")), null),
- new PropertyNode("TEL", "19",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-PHS")), null),
- new PropertyNode("TEL", "20",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-RESTAURANT")), null));
- verifier.verify(builder.vNodeList.get(2));
- }
-
- public void testV30SimpleCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V30();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "3.0",
- null, null, null, null, null),
- new PropertyNode("FN", "And Roid",
- null, null, null, null, null),
- new PropertyNode("N", "And;Roid;;;",
- Arrays.asList("And", "Roid", "", "", ""),
- null, null, null, null),
- new PropertyNode("ORG", "Open;Handset; Alliance",
- Arrays.asList("Open", "Handset", " Alliance"),
- null, null, null, null),
- new PropertyNode("SORT-STRING", "android", null, null, null, null, null),
- new PropertyNode("TEL", "0300000000",
- null, null, null,
- new HashSet<String>(Arrays.asList("PREF", "VOICE")), null),
- new PropertyNode("CLASS", "PUBLIC", null, null, null, null, null),
- new PropertyNode("X-GNO", "0", null, null, null, null, null),
- new PropertyNode("X-GN", "group0", null, null, null, null, null),
- new PropertyNode("X-REDUCTION", "0",
- null, null, null, null, null),
- new PropertyNode("REV", "20081031T065854Z",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
new file mode 100644
index 0000000..1e4f161
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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 com.android.unit_tests.accounts;
+
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.IsolatedContext;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.content.*;
+import android.accounts.Account;
+import android.accounts.AccountManagerService;
+import android.os.Bundle;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class AccountManagerServiceTest extends AndroidTestCase {
+ @Override
+ protected void setUp() throws Exception {
+ final String filenamePrefix = "test.";
+ MockContentResolver resolver = new MockContentResolver();
+ RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+ new MockContext(), // The context that most methods are delegated to
+ getContext(), // The context that file methods are delegated to
+ filenamePrefix);
+ Context context = new IsolatedContext(resolver, targetContextWrapper);
+ setContext(context);
+ }
+
+ public class AccountSorter implements Comparator<Account> {
+ public int compare(Account object1, Account object2) {
+ if (object1 == object2) return 0;
+ if (object1 == null) return 1;
+ if (object2 == null) return -1;
+ int result = object1.type.compareTo(object2.type);
+ if (result != 0) return result;
+ return object1.name.compareTo(object2.name);
+ }
+ }
+
+ public void testCheckAddAccount() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a21 = new Account("account2", "type1");
+ Account a31 = new Account("account3", "type1");
+ Account a12 = new Account("account1", "type2");
+ Account a22 = new Account("account2", "type2");
+ Account a32 = new Account("account3", "type2");
+ 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);
+
+ Account[] accounts = ams.getAccounts(null);
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(6, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a21, accounts[1]);
+ assertEquals(a31, accounts[2]);
+ assertEquals(a12, accounts[3]);
+ assertEquals(a22, accounts[4]);
+ assertEquals(a32, accounts[5]);
+
+ accounts = ams.getAccountsByType("type1" );
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(3, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a21, accounts[1]);
+ assertEquals(a31, accounts[2]);
+
+ ams.removeAccount(null, a21);
+
+ accounts = ams.getAccountsByType("type1" );
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(2, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a31, accounts[1]);
+ }
+
+ public void testPasswords() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a12 = new Account("account1", "type2");
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
+
+ assertEquals("p11", ams.getPassword(a11));
+ assertEquals("p12", ams.getPassword(a12));
+
+ ams.setPassword(a11, "p11b");
+
+ assertEquals("p11b", ams.getPassword(a11));
+ assertEquals("p12", ams.getPassword(a12));
+ }
+
+ public void testUserdata() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Bundle u11 = new Bundle();
+ u11.putString("a", "a_a11");
+ u11.putString("b", "b_a11");
+ u11.putString("c", "c_a11");
+ Account a12 = new Account("account1", "type2");
+ Bundle u12 = new Bundle();
+ u12.putString("a", "a_a12");
+ u12.putString("b", "b_a12");
+ u12.putString("c", "c_a12");
+ ams.addAccount(a11, "p11", u11);
+ ams.addAccount(a12, "p12", u12);
+
+ assertEquals("a_a11", ams.getUserData(a11, "a"));
+ assertEquals("b_a11", ams.getUserData(a11, "b"));
+ assertEquals("c_a11", ams.getUserData(a11, "c"));
+ assertEquals("a_a12", ams.getUserData(a12, "a"));
+ assertEquals("b_a12", ams.getUserData(a12, "b"));
+ assertEquals("c_a12", ams.getUserData(a12, "c"));
+
+ ams.setUserData(a11, "b", "b_a11b");
+
+ assertEquals("a_a11", ams.getUserData(a11, "a"));
+ assertEquals("b_a11b", ams.getUserData(a11, "b"));
+ assertEquals("c_a11", ams.getUserData(a11, "c"));
+ assertEquals("a_a12", ams.getUserData(a12, "a"));
+ assertEquals("b_a12", ams.getUserData(a12, "b"));
+ assertEquals("c_a12", ams.getUserData(a12, "c"));
+ }
+
+ public void testAuthtokens() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a12 = new Account("account1", "type2");
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
+
+ ams.setAuthToken(a11, "att1", "a11_att1");
+ ams.setAuthToken(a11, "att2", "a11_att2");
+ ams.setAuthToken(a11, "att3", "a11_att3");
+ ams.setAuthToken(a12, "att1", "a12_att1");
+ ams.setAuthToken(a12, "att2", "a12_att2");
+ ams.setAuthToken(a12, "att3", "a12_att3");
+
+ assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+ assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+ assertEquals("a11_att3", ams.peekAuthToken(a11, "att3"));
+ assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+ assertEquals("a12_att2", ams.peekAuthToken(a12, "att2"));
+ assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+ ams.setAuthToken(a11, "att3", "a11_att3b");
+ ams.invalidateAuthToken(a12.type, "a12_att2");
+
+ assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+ assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+ assertEquals("a11_att3b", ams.peekAuthToken(a11, "att3"));
+ assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+ assertNull(ams.peekAuthToken(a12, "att2"));
+ assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+ assertNull(ams.readAuthTokenFromDatabase(a12, "att2"));
+ }
+}
\ No newline at end of file
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
new file mode 100644
index 0000000..0ee74df
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
@@ -0,0 +1,322 @@
+/*
+ * 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 com.android.unit_tests.vcard;
+
+import android.content.ContentValues;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+/**
+ * @hide old class just for test
+ */
+public class PropertyNode {
+ public String propName;
+ public String propValue;
+ public List<String> propValue_vector;
+
+ /** Store value as byte[],after decode.
+ * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
+ */
+ public byte[] propValue_bytes;
+
+ /** param store: key=paramType, value=paramValue
+ * Note that currently PropertyNode class does not support multiple param-values
+ * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
+ * one String value like "A,B", not ["A", "B"]...
+ * TODO: fix this.
+ */
+ public ContentValues paramMap;
+
+ /** Only for TYPE=??? param store. */
+ public Set<String> paramMap_TYPE;
+
+ /** Store group values. Used only in VCard. */
+ public Set<String> propGroupSet;
+
+ public PropertyNode() {
+ propName = "";
+ propValue = "";
+ propValue_vector = new ArrayList<String>();
+ paramMap = new ContentValues();
+ paramMap_TYPE = new HashSet<String>();
+ propGroupSet = new HashSet<String>();
+ }
+
+ public PropertyNode(
+ String propName, String propValue, List<String> propValue_vector,
+ byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
+ Set<String> propGroupSet) {
+ if (propName != null) {
+ this.propName = propName;
+ } else {
+ this.propName = "";
+ }
+ if (propValue != null) {
+ this.propValue = propValue;
+ } else {
+ this.propValue = "";
+ }
+ if (propValue_vector != null) {
+ this.propValue_vector = propValue_vector;
+ } else {
+ this.propValue_vector = new ArrayList<String>();
+ }
+ this.propValue_bytes = propValue_bytes;
+ if (paramMap != null) {
+ this.paramMap = paramMap;
+ } else {
+ this.paramMap = new ContentValues();
+ }
+ if (paramMap_TYPE != null) {
+ this.paramMap_TYPE = paramMap_TYPE;
+ } else {
+ this.paramMap_TYPE = new HashSet<String>();
+ }
+ if (propGroupSet != null) {
+ this.propGroupSet = propGroupSet;
+ } else {
+ this.propGroupSet = new HashSet<String>();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PropertyNode)) {
+ return false;
+ }
+
+ PropertyNode node = (PropertyNode)obj;
+
+ if (propName == null || !propName.equals(node.propName)) {
+ return false;
+ } else if (!paramMap.equals(node.paramMap)) {
+ return false;
+ } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
+ return false;
+ } else if (!propGroupSet.equals(node.propGroupSet)) {
+ return false;
+ }
+
+ if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
+ return true;
+ } else {
+ // Log.d("@@@", propValue + ", " + node.propValue);
+ if (!propValue.equals(node.propValue)) {
+ return false;
+ }
+
+ // The value in propValue_vector is not decoded even if it should be
+ // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
+ // is 1, the encoded value is stored in propValue, so we do not have to
+ // check it.
+ return (propValue_vector.equals(node.propValue_vector) ||
+ propValue_vector.size() == 1 ||
+ node.propValue_vector.size() == 1);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("propName: ");
+ builder.append(propName);
+ builder.append(", paramMap: ");
+ builder.append(paramMap.toString());
+ builder.append(", propmMap_TYPE: ");
+ builder.append(paramMap_TYPE.toString());
+ builder.append(", propGroupSet: ");
+ builder.append(propGroupSet.toString());
+ if (propValue_vector != null && propValue_vector.size() > 1) {
+ builder.append(", propValue_vector size: ");
+ builder.append(propValue_vector.size());
+ }
+ if (propValue_bytes != null) {
+ builder.append(", propValue_bytes size: ");
+ builder.append(propValue_bytes.length);
+ }
+ builder.append(", propValue: ");
+ builder.append(propValue);
+ return builder.toString();
+ }
+
+ /**
+ * Encode this object into a string which can be decoded.
+ */
+ public String encode() {
+ // 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("],");
+ }
+ int size = propGroupSet.size();
+ if (size > 0) {
+ Set<String> set = propGroupSet;
+ builder.append("propGroup:[");
+ int i = 0;
+ for (String group : set) {
+ // We do not need to double quote groups.
+ // group = 1*(ALPHA / DIGIT / "-")
+ builder.append(group);
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ if (paramMap.size() > 0 || paramMap_TYPE.size() > 0) {
+ ContentValues values = paramMap;
+ builder.append("paramMap:[");
+ size = paramMap.size();
+ int i = 0;
+ for (Entry<String, Object> entry : values.valueSet()) {
+ // Assuming param-key does not contain NON-ASCII nor symbols.
+ //
+ // According to vCard 3.0:
+ // param-name = iana-token / x-name
+ builder.append(entry.getKey());
+
+ // param-value may contain any value including NON-ASCIIs.
+ // We use the following replacing rule.
+ // \ -> \\
+ // , -> \,
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ builder.append("=");
+ builder.append(entry.getValue().toString()
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ i++;
+ }
+
+ Set<String> set = paramMap_TYPE;
+ size = paramMap_TYPE.size();
+ if (i > 0 && size > 0) {
+ builder.append(",");
+ }
+ i = 0;
+ for (String type : set) {
+ builder.append("TYPE=");
+ builder.append(type
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ size = propValue_vector.size();
+ if (size > 0) {
+ builder.append("propValue:[");
+ List<String> list = propValue_vector;
+ for (int i = 0; i < size; i++) {
+ builder.append(list.get(i)
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ }
+ builder.append("],");
+ }
+
+ return builder.toString();
+ }
+
+ public static PropertyNode decode(String encodedString) {
+ PropertyNode propertyNode = new PropertyNode();
+ String trimed = encodedString.trim();
+ if (trimed.length() == 0) {
+ return propertyNode;
+ }
+ String[] elems = trimed.split("],");
+
+ for (String elem : elems) {
+ int index = elem.indexOf('[');
+ String name = elem.substring(0, index - 1);
+ Pattern pattern = Pattern.compile("(?<!\\\\),");
+ String[] values = pattern.split(elem.substring(index + 1), -1);
+ if (name.equals("propName")) {
+ propertyNode.propName = values[0];
+ } else if (name.equals("propGroupSet")) {
+ for (String value : values) {
+ propertyNode.propGroupSet.add(value);
+ }
+ } else if (name.equals("paramMap")) {
+ ContentValues paramMap = propertyNode.paramMap;
+ Set<String> paramMap_TYPE = propertyNode.paramMap_TYPE;
+ for (String value : values) {
+ String[] tmp = value.split("=", 2);
+ String mapKey = tmp[0];
+ // \, -> ,
+ // \\ -> \
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ String mapValue =
+ tmp[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
+ if (mapKey.equalsIgnoreCase("TYPE")) {
+ paramMap_TYPE.add(mapValue);
+ } else {
+ paramMap.put(mapKey, mapValue);
+ }
+ }
+ } else if (name.equals("propValue")) {
+ StringBuilder builder = new StringBuilder();
+ List<String> list = propertyNode.propValue_vector;
+ int length = values.length;
+ for (int i = 0; i < length; i++) {
+ String normValue = values[i]
+ .replaceAll("\\\\,", ",")
+ .replaceAll("\\\\\\\\", "\\\\");
+ list.add(normValue);
+ builder.append(normValue);
+ if (i < length - 1) {
+ builder.append(";");
+ }
+ }
+ propertyNode.propValue = builder.toString();
+ }
+ }
+
+ // At this time, QUOTED-PRINTABLE is already decoded to Java String.
+ // We just need to decode BASE64 String to binary.
+ String encoding = propertyNode.paramMap.getAsString("ENCODING");
+ if (encoding != null &&
+ (encoding.equalsIgnoreCase("BASE64") ||
+ encoding.equalsIgnoreCase("B"))) {
+ propertyNode.propValue_bytes =
+ Base64.decodeBase64(propertyNode.propValue_vector.get(0).getBytes());
+ }
+
+ return propertyNode;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
new file mode 100644
index 0000000..af5562ad
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
@@ -0,0 +1,926 @@
+/*
+ * 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 com.android.unit_tests.vcard;
+
+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;
+import android.test.AndroidTestCase;
+
+import com.android.unit_tests.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+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 onEntryCreated(ContactStruct contactStruct) {
+ contacts.add(contactStruct);
+ }
+ public void onFinal() {
+ }
+ }
+
+ static void verify(ContactStruct expected, ContactStruct actual) {
+ if (!equalsString(expected.getName(), actual.getName())) {
+ fail(String.format("Names do not equal: \"%s\" != \"%s\"",
+ expected.getName(), actual.getName()));
+ }
+ if (!equalsString(
+ expected.getPhoneticName(), actual.getPhoneticName())) {
+ fail(String.format("Phonetic names do not equal: \"%s\" != \"%s\"",
+ expected.getPhoneticName(), actual.getPhoneticName()));
+ }
+ {
+ final byte[] expectedPhotoBytes = expected.getPhotoBytes();
+ final byte[] actualPhotoBytes = actual.getPhotoBytes();
+ if (!((expectedPhotoBytes == null && actualPhotoBytes == null) ||
+ Arrays.equals(expectedPhotoBytes, actualPhotoBytes))) {
+ fail("photoBytes is not equal.");
+ }
+ }
+ verifyInternal(expected.getNotes(), actual.getNotes(), "notes");
+ verifyInternal(expected.getPhoneList(), actual.getPhoneList(), "phones");
+ verifyInternal(expected.getContactMethodList(), actual.getContactMethodList(),
+ "contact lists");
+ verifyInternal(expected.getOrganizationList(), actual.getOrganizationList(),
+ "organizations");
+ {
+ final Map<String, List<String>> expectedMap =
+ expected.getExtensionMap();
+ final Map<String, List<String>> actualMap =
+ actual.getExtensionMap();
+ if (verifySize((expectedMap == null ? 0 : expectedMap.size()),
+ (actualMap == null ? 0 : actualMap.size()), "extensions") > 0) {
+ for (String key : expectedMap.keySet()) {
+ if (!actualMap.containsKey(key)) {
+ fail(String.format(
+ "Actual does not have %s extension while expected has",
+ key));
+ }
+ final List<String> expectedList = expectedMap.get(key);
+ final List<String> actualList = actualMap.get(key);
+ verifyInternal(expectedList, actualList,
+ String.format("extension \"%s\"", key));
+ }
+ }
+ }
+ }
+
+ private static boolean equalsString(String a, String b) {
+ if (a == null || a.length() == 0) {
+ return b == null || b.length() == 0;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ private static int verifySize(int expectedSize, int actualSize, String name) {
+ if (expectedSize != actualSize) {
+ fail(String.format("Size of %s is different: %d != %d",
+ name, expectedSize, actualSize));
+ }
+ return expectedSize;
+ }
+
+ private static <T> void verifyInternal(final List<T> expected, final List<T> actual,
+ String name) {
+ if(verifySize((expected == null ? 0 : expected.size()),
+ (actual == null ? 0 : actual.size()), name) > 0) {
+ int size = expected.size();
+ for (int i = 0; i < size; i++) {
+ final T expectedObj = expected.get(i);
+ final T actualObj = actual.get(i);
+ if (!expected.equals(actual)) {
+ fail(String.format("The %i %s are different: %s != %s",
+ i, name, expectedObj, actualObj));
+ }
+ }
+ }
+ }
+
+ private class PropertyNodesVerifier {
+ private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap;
+ public PropertyNodesVerifier(PropertyNode... nodes) {
+ mPropertyNodeMap = new HashMap<String, ArrayList<PropertyNode>>();
+ for (PropertyNode propertyNode : nodes) {
+ String propName = propertyNode.propName;
+ ArrayList<PropertyNode> expectedNodes =
+ mPropertyNodeMap.get(propName);
+ if (expectedNodes == null) {
+ expectedNodes = new ArrayList<PropertyNode>();
+ mPropertyNodeMap.put(propName, expectedNodes);
+ }
+ expectedNodes.add(propertyNode);
+ }
+ }
+
+ public void verify(VNode vnode) {
+ for (PropertyNode propertyNode : vnode.propList) {
+ String propName = propertyNode.propName;
+ ArrayList<PropertyNode> nodes = mPropertyNodeMap.get(propName);
+ if (nodes == null) {
+ fail("Unexpected propName \"" + propName + "\" exists.");
+ }
+ boolean successful = false;
+ int size = nodes.size();
+ for (int i = 0; i < size; i++) {
+ PropertyNode expectedNode = nodes.get(i);
+ if (expectedNode.propName.equals(propName)) {
+ if (expectedNode.equals(propertyNode)) {
+ successful = true;
+ nodes.remove(i);
+ if (nodes.size() == 0) {
+ mPropertyNodeMap.remove(propName);
+ }
+ break;
+ } else {
+ fail("Property \"" + propName + "\" has wrong value.\n"
+ + "expected: " + expectedNode.toString()
+ + "\n actual: " + propertyNode.toString());
+ }
+ }
+ }
+ if (!successful) {
+ fail("Unexpected property \"" + propName + "\" exists.");
+ }
+ }
+ if (mPropertyNodeMap.size() != 0) {
+ ArrayList<String> expectedProps = new ArrayList<String>();
+ for (ArrayList<PropertyNode> nodes : mPropertyNodeMap.values()) {
+ for (PropertyNode node : nodes) {
+ expectedProps.add(node.propName);
+ }
+ }
+ fail("expected props " + Arrays.toString(expectedProps.toArray()) +
+ " was not found");
+ }
+ }
+ }
+
+ public void testV21SimpleCase1_1() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Roid Ando", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase1_2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_JAPANESE);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase3() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder1 = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder1.addEntryHandler(holder);
+ VNodeBuilder builder2 = new VNodeBuilder();
+ VCardBuilderCollection collection =
+ new VCardBuilderCollection(
+ new ArrayList<VCardBuilder>(Arrays.asList(builder1, builder2)));
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_3);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", collection));
+ is.close();
+
+ assertEquals(1, builder2.vNodeList.size());
+ VNode vnode = builder2.vNodeList.get(0);
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("N", "Ando;Roid;",
+ Arrays.asList("Ando", "Roid", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "Ando Roid",
+ null, null, null, null, null));
+ verifier.verify(vnode);
+
+ // FN is prefered.
+ assertEquals(1, holder.contacts.size());
+ ContactStruct actual = holder.contacts.get(0);
+ 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();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
+ Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "A;B\\C\\;D:E\\\\",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21ComplicatedCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ ContentValues contentValuesForPhoto = new ContentValues();
+ contentValuesForPhoto.put("ENCODING", "BASE64");
+ // Push data into int array at first since values like 0x80 are
+ // interpreted as int by the compiler and casting all of them is
+ // cumbersome...
+ int[] photoIntArray = {
+ 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
+ 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
+ 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
+ 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
+ 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
+ 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
+ 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
+ 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
+ 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
+ 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
+ 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
+ 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
+ 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
+ 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
+ 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
+ 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
+ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
+ 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
+ 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
+ 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
+ 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
+ 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
+ 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
+ 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
+ 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
+ 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
+ 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
+ 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
+ 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
+ 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
+ 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
+ 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+ 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
+ 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
+ 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
+ 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
+ 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
+ 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
+ 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
+ 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
+ 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
+ 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
+ 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+ 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
+ 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+ 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+ 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+ 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
+ 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
+ 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
+ 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
+ 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
+ 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
+ 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
+ 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
+ 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
+ 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
+ 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
+ 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
+ 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
+ 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
+ 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
+ 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
+ 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
+ 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
+ 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
+ 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
+ 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
+ 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
+ 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
+ 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
+ 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
+ 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
+ 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
+ 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
+ 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
+ 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
+ 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
+ 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
+ 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
+ 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
+ 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
+ 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
+ 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
+ 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
+ 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
+ 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
+ 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
+ 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
+ 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
+ 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
+ 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
+ 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
+ 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
+ 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
+ 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
+ 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
+ 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
+ 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
+ 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
+ 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
+ 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
+ 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
+ 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
+ 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
+ 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
+ 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
+ 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
+ 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
+ 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
+ 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
+ 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
+ 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
+ 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
+ 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
+ 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
+ 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
+ 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
+ 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
+ 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
+ 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
+ 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
+ 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
+ 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
+ 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
+ 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
+ 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
+ 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
+ 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
+ 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
+ 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
+ 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
+ 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
+ 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
+ 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
+ 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
+ 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+ 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
+ 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
+ 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
+ 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
+ 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
+ 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+ 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+ 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+ 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
+ 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
+ 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
+ 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
+ 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
+ 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
+ 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
+ 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
+ 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
+ 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
+ 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
+ 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
+ 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
+ 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
+ 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
+ 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
+ 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
+ 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
+ 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
+ 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
+ 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
+ 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
+ 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
+ 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
+ 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
+ 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
+ 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
+ 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
+ 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
+ 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
+ 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
+ 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
+ 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
+ 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
+ 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
+ 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
+ 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
+ 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
+ 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
+ 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
+ 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
+ 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
+ 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
+ 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
+ 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
+ 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
+ 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
+ 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
+ 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
+ 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
+ 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
+ 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
+ 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
+ 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
+ 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
+ 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
+ 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
+ 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
+ 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
+ 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
+ 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
+ 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
+ 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
+ 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
+ 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
+ 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
+ 0x0c, 0xd1, 0x00, 0xff, 0xd9};
+ int length = photoIntArray.length;
+ byte[] photoByteArray = new byte[length];
+ for (int i = 0; i < length; i++) {
+ photoByteArray[i] = (byte)photoIntArray[i];
+ }
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
+ Arrays.asList("Gump", "Forrest",
+ "Hoge", "Pos", "Tao"),
+ null, null, null, null),
+ new PropertyNode("FN", "Joe Due",
+ null, null, null, null, null),
+ new PropertyNode("ORG",
+ "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
+ Arrays.asList("Gump Shrimp Co.",
+ "Sales Dept.;Manager",
+ "Fish keeper"),
+ null, null, null, null),
+ new PropertyNode("ROLE", "Fish Cake Keeper!",
+ null, null, null, null, null),
+ new PropertyNode("TITLE", "Shrimp Man",
+ null, null, null, null, null),
+ new PropertyNode("X-CLASS", "PUBLIC",
+ null, null, null, null, null),
+ new PropertyNode("TEL", "(111) 555-1212",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("WORK", "VOICE")), null),
+ new PropertyNode("TEL", "(404) 555-1212",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("HOME", "VOICE")), null),
+ new PropertyNode("TEL", "0311111111",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("CELL")), null),
+ new PropertyNode("TEL", "0322222222",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VIDEO")), null),
+ new PropertyNode("TEL", "0333333333",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VOICE")), null),
+ new PropertyNode("ADR",
+ ";;100 Waters Edge;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "100 Waters Edge", "Baytown",
+ "LA", "30314", "United States of America"),
+ null, null,
+ new HashSet<String>(Arrays.asList("WORK")), null),
+ new PropertyNode("LABEL",
+ "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("WORK")), null),
+ new PropertyNode("ADR",
+ ";;42 Plantation St.;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "42 Plantation St.", "Baytown",
+ "LA", "30314", "United States of America"), null, null,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("LABEL",
+ "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("EMAIL", "forrestgump@walladalla.com",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PREF", "INTERNET")), null),
+ new PropertyNode("EMAIL", "cell@example.com",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("CELL")), null),
+ new PropertyNode("NOTE", "The following note is the example from RFC 2045.",
+ null, null, null, null, null),
+ new PropertyNode("NOTE",
+ "Now's the time for all folk to come to the aid of their country.",
+ null, null, contentValuesForQP, null, null),
+ new PropertyNode("PHOTO", null,
+ null, photoByteArray, contentValuesForPhoto,
+ new HashSet<String>(Arrays.asList("JPEG")), null),
+ new PropertyNode("X-ATTRIBUTE", "Some String",
+ null, null, null, null, null),
+ new PropertyNode("BDAY", "19800101",
+ null, null, null, null, null),
+ new PropertyNode("GEO", "35.6563854,139.6994233",
+ null, null, null, null, null),
+ new PropertyNode("URL", "http://www.example.com/",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20080424T195243Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese1() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
+ // vCard 2.1/3.0 specification does not allow multiple values.
+ // Do not need to handle it as multiple values.
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VOICE", "PREF")), null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese2() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
+ Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
+ "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("FN",
+ "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
+ null, null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ ("\uFF71\uFF9D\uFF84\uFF9E\uFF73" +
+ ";\uFF9B\uFF72\uFF84\uFF9E\u0031;;;"),
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("ADR",
+ (";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
+ "\u968E;;;;150-8512;"),
+ Arrays.asList("",
+ "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
+ "\u0036\u968E", "", "", "", "150-8512", ""),
+ null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("NOTE", "\u30E1\u30E2",
+ null, null, contentValuesForQP, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21MultipleEntryCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(3, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "9",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-SECRET")), null),
+ new PropertyNode("TEL", "10",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-HOTEL")), null),
+ new PropertyNode("TEL", "11",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-SCHOOL")), null),
+ new PropertyNode("TEL", "12",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("FAX", "HOME")), null));
+ verifier.verify(builder.vNodeList.get(0));
+
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "13",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("MODEM")), null),
+ new PropertyNode("TEL", "14",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PAGER")), null),
+ new PropertyNode("TEL", "15",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-FAMILY")), null),
+ new PropertyNode("TEL", "16",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-GIRL")), null));
+ verifier.verify(builder.vNodeList.get(1));
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "17",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-BOY")), null),
+ new PropertyNode("TEL", "18",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-FRIEND")), null),
+ new PropertyNode("TEL", "19",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-PHS")), null),
+ new PropertyNode("TEL", "20",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-RESTAURANT")), null));
+ verifier.verify(builder.vNodeList.get(2));
+ }
+
+ public void testV30SimpleCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V30();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "3.0",
+ null, null, null, null, null),
+ new PropertyNode("FN", "And Roid",
+ null, null, null, null, null),
+ new PropertyNode("N", "And;Roid;;;",
+ Arrays.asList("And", "Roid", "", "", ""),
+ null, null, null, null),
+ new PropertyNode("ORG", "Open;Handset; Alliance",
+ Arrays.asList("Open", "Handset", " Alliance"),
+ null, null, null, null),
+ new PropertyNode("SORT-STRING", "android", null, null, null, null, null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PREF", "VOICE")), null),
+ new PropertyNode("CLASS", "PUBLIC", null, null, null, null, null),
+ new PropertyNode("X-GNO", "0", null, null, null, null, null),
+ new PropertyNode("X-GN", "group0", null, null, null, null, null),
+ new PropertyNode("X-REDUCTION", "0",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20081031T065854Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
new file mode 100644
index 0000000..3eb827b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
@@ -0,0 +1,30 @@
+/*
+ * 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 com.android.unit_tests.vcard;
+
+import java.util.ArrayList;
+
+/**
+ * @hide old class. Just for testing
+ */
+public class VNode {
+ public String VName;
+
+ public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
+
+ /** 0:parse over. 1:parsing. */
+ public int parseStatus = 1;
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
new file mode 100644
index 0000000..6d69223
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
@@ -0,0 +1,313 @@
+/*
+ * 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 com.android.unit_tests.vcard;
+
+import android.content.ContentValues;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardConfig;
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.net.QuotedPrintableCodec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Store the parse result to custom datastruct: VNode, PropertyNode
+ * Maybe several vcard instance, so use vNodeList to store.
+ * VNode: standy by a vcard instance.
+ * PropertyNode: standy by a property line of a card.
+ * @hide old class, just for testing use
+ */
+public class VNodeBuilder implements VCardBuilder {
+ static private String LOG_TAG = "VDATABuilder";
+
+ /**
+ * If there's no other information available, this class uses this charset for encoding
+ * byte arrays.
+ */
+ static public String TARGET_CHARSET = "UTF-8";
+
+ /** type=VNode */
+ public List<VNode> vNodeList = new ArrayList<VNode>();
+ private int mNodeListPos = 0;
+ private VNode mCurrentVNode;
+ private PropertyNode mCurrentPropNode;
+ private String mCurrentParamType;
+
+ /**
+ * The charset using which VParser parses the text.
+ */
+ private String mSourceCharset;
+
+ /**
+ * The charset with which byte array is encoded to String.
+ */
+ private String mTargetCharset;
+
+ private boolean mStrictLineBreakParsing;
+
+ public VNodeBuilder() {
+ this(VCardConfig.DEFAULT_CHARSET, TARGET_CHARSET, false);
+ }
+
+ public VNodeBuilder(String charset, boolean strictLineBreakParsing) {
+ this(null, charset, strictLineBreakParsing);
+ }
+
+ /**
+ * @hide sourceCharset is temporal.
+ */
+ public VNodeBuilder(String sourceCharset, String targetCharset,
+ boolean strictLineBreakParsing) {
+ if (sourceCharset != null) {
+ mSourceCharset = sourceCharset;
+ } else {
+ mSourceCharset = VCardConfig.DEFAULT_CHARSET;
+ }
+ if (targetCharset != null) {
+ mTargetCharset = targetCharset;
+ } else {
+ mTargetCharset = TARGET_CHARSET;
+ }
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ // Note: I guess that this code assumes the Record may nest like this:
+ // START:VPOS
+ // ...
+ // START:VPOS2
+ // ...
+ // END:VPOS2
+ // ...
+ // END:VPOS
+ //
+ // However the following code has a bug.
+ // When error occurs after calling startRecord(), the entry which is probably
+ // the cause of the error remains to be in vNodeList, while endRecord() is not called.
+ //
+ // I leave this code as is since I'm not familiar with vcalendar specification.
+ // But I believe we should refactor this code in the future.
+ // Until this, the last entry has to be removed when some error occurs.
+ public void startRecord(String type) {
+
+ VNode vnode = new VNode();
+ vnode.parseStatus = 1;
+ vnode.VName = type;
+ // I feel this should be done in endRecord(), but it cannot be done because of
+ // the reason above.
+ vNodeList.add(vnode);
+ mNodeListPos = vNodeList.size() - 1;
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void endRecord() {
+ VNode endNode = vNodeList.get(mNodeListPos);
+ endNode.parseStatus = 0;
+ while(mNodeListPos > 0){
+ mNodeListPos--;
+ if((vNodeList.get(mNodeListPos)).parseStatus == 1)
+ break;
+ }
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void startProperty() {
+ mCurrentPropNode = new PropertyNode();
+ }
+
+ public void endProperty() {
+ mCurrentVNode.propList.add(mCurrentPropNode);
+ }
+
+ public void propertyName(String name) {
+ mCurrentPropNode.propName = name;
+ }
+
+ // Used only in VCard.
+ public void propertyGroup(String group) {
+ mCurrentPropNode.propGroupSet.add(group);
+ }
+
+ public void propertyParamType(String type) {
+ mCurrentParamType = type;
+ }
+
+ public void propertyParamValue(String value) {
+ if (mCurrentParamType == null ||
+ mCurrentParamType.equalsIgnoreCase("TYPE")) {
+ mCurrentPropNode.paramMap_TYPE.add(value);
+ } else {
+ mCurrentPropNode.paramMap.put(mCurrentParamType, value);
+ }
+
+ mCurrentParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetCharset) {
+ if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
+ return originalString;
+ }
+ Charset charset = Charset.forName(mSourceCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return null;
+ }
+ }
+
+ private String handleOneValue(String value, String targetCharset, String encoding) {
+ if (encoding != null) {
+ if (encoding.equals("BASE64") || encoding.equals("B")) {
+ // Assume BASE64 is used only when the number of values is 1.
+ mCurrentPropNode.propValue_bytes =
+ Base64.decodeBase64(value.getBytes());
+ return value;
+ } else if (encoding.equals("QUOTED-PRINTABLE")) {
+ String quotedPrintable = value
+ .replaceAll("= ", " ").replaceAll("=\t", "\t");
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ StringBuilder builder = new StringBuilder();
+ int length = quotedPrintable.length();
+ ArrayList<String> list = new ArrayList<String>();
+ for (int i = 0; i < length; i++) {
+ char ch = quotedPrintable.charAt(i);
+ if (ch == '\n') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else if (ch == '\r') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ if (i < length - 1) {
+ char nextCh = quotedPrintable.charAt(i + 1);
+ if (nextCh == '\n') {
+ i++;
+ }
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ String finalLine = builder.toString();
+ if (finalLine.length() > 0) {
+ list.add(finalLine);
+ }
+ lines = list.toArray(new String[0]);
+ }
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes;
+ try {
+ bytes = builder.toString().getBytes(mSourceCharset);
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
+ bytes = builder.toString().getBytes();
+ }
+
+ try {
+ bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
+ } catch (DecoderException e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
+ return "";
+ }
+
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return new String(bytes);
+ }
+ }
+ // Unknown encoding. Fall back to default.
+ }
+ return encodeString(value, targetCharset);
+ }
+
+ public void propertyValues(List<String> values) {
+ if (values == null || values.size() == 0) {
+ mCurrentPropNode.propValue_bytes = null;
+ mCurrentPropNode.propValue_vector.clear();
+ mCurrentPropNode.propValue_vector.add("");
+ mCurrentPropNode.propValue = "";
+ return;
+ }
+
+ ContentValues paramMap = mCurrentPropNode.paramMap;
+
+ String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
+ String encoding = paramMap.getAsString("ENCODING");
+
+ if (targetCharset == null || targetCharset.length() == 0) {
+ targetCharset = mTargetCharset;
+ }
+
+ for (String value : values) {
+ mCurrentPropNode.propValue_vector.add(
+ handleOneValue(value, targetCharset, encoding));
+ }
+
+ mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
+ }
+
+ private String listToString(List<String> list){
+ int size = list.size();
+ if (size > 1) {
+ StringBuilder typeListB = new StringBuilder();
+ for (String type : list) {
+ typeListB.append(type).append(";");
+ }
+ int len = typeListB.length();
+ if (len > 0 && typeListB.charAt(len - 1) == ';') {
+ return typeListB.substring(0, len - 1);
+ }
+ return typeListB.toString();
+ } else if (size == 1) {
+ return list.get(0);
+ } else {
+ return "";
+ }
+ }
+
+ public String getResult(){
+ return null;
+ }
+}
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
index dee6e38..533338e 100644
--- a/tests/CoreTests/android/content/SyncStorageEngineTest.java
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -20,6 +20,7 @@
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContext;
import android.test.mock.MockContentResolver;
+import android.accounts.Account;
public class SyncStorageEngineTest extends AndroidTestCase {
@@ -28,7 +29,7 @@
* correcponding sync is finished. This can happen if the clock changes while we are syncing.
*/
public void testPurgeActiveSync() throws Exception {
- final String account = "a@example.com";
+ final Account account = new Account("a@example.com", "example.type");
final String authority = "testprovider";
MockContentResolver mockResolver = new MockContentResolver();
diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java
index d89f5ae..94eb23e 100644
--- a/tests/CoreTests/android/core/RequestAPITest.java
+++ b/tests/CoreTests/android/core/RequestAPITest.java
@@ -72,7 +72,7 @@
RequestHandle handle =
mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", headers, null,
- null, 0, false);
+ null, 0);
handle.waitUntilComplete();
fail("expected exception not thrown");
@@ -121,7 +121,7 @@
mTestWebServer.setKeepAlive(false);
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", headers, null,
- null, 0, false);
+ null, 0);
handle.waitUntilComplete();
}
@@ -197,7 +197,7 @@
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testGet - sent request. Waiting");
handle.waitUntilComplete();
@@ -231,11 +231,11 @@
RequestHandle handle0 = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
handle0.waitUntilComplete();
RequestHandle handle1 = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler2,
- null, 0, false);
+ null, 0);
handle1.waitUntilComplete();
/* It's not correct to use same listener for multiple
@@ -270,7 +270,7 @@
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "HEAD", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testHead - sent request waiting");
handle.waitUntilComplete();
@@ -297,7 +297,7 @@
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testChunked - sent request waiting");
handle.waitUntilComplete();
@@ -330,7 +330,7 @@
Log.d(LOGTAG, testName + " start - rq = " + mRequestQueue);
RequestHandle requestHandle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0);
Log.d(LOGTAG, testName + " - sent request waiting");
requestHandle.waitUntilComplete();
@@ -398,10 +398,10 @@
leh2.expectHeaders();
RequestHandle handle0 = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0);
handle0.waitUntilComplete();
RequestHandle handle1 = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0);
Log.d(LOGTAG, "testGetAndHead - sent request. Waiting");
handle1.waitUntilComplete();
@@ -432,7 +432,7 @@
Log.d(LOGTAG, "testPost start - rq = " + mRequestQueue);
RequestHandle handle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0);
Log.d(LOGTAG, "testPost - sent request waiting");
handle.waitUntilComplete();
@@ -470,7 +470,7 @@
InputStream bodyProvider = new ByteArrayInputStream(mBody.getBytes());
RequestHandle handle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength, false);
+ "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength);
Log.d(LOGTAG, "testPostWithData - sent request waiting");
handle.waitUntilComplete();
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 577d384..466b555 100644
--- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -309,6 +309,11 @@
number.append("800-55512");
PhoneNumberUtils.formatNanpNumber(number);
assertEquals("800-555-12", number.toString());
+
+ number.clear();
+ number.append("46645");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("46645", number.toString());
}
@SmallTest
@@ -330,4 +335,73 @@
assertEquals("(800) 222-3334",
PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG"));
}
+
+ @SmallTest
+ public void testCheckAndProcessPlusCode() {
+ assertEquals("8475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000"));
+ assertEquals("18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000"));
+ assertEquals("0111234567",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+1234567"));
+ assertEquals("01123456700000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+23456700000"));
+ assertEquals("01111875767800",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800"));
+ assertEquals("8475797000,18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753"));
+ assertEquals("8475797000,18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753"));
+ assertEquals("8475797000;8475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8475231753"));
+ 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,;18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753"));
+ assertEquals("8475797000;,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+11875767000"));
+ assertEquals("8475797000,;01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+11875767000"));
+ assertEquals("8475797000,,,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,,+11875767000"));
+ assertEquals("8475797000;,,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,,+11875767000"));
+ assertEquals("+;,8475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+;,8475797000"));
+ assertEquals("8475797000,",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,"));
+ assertEquals("847+579-7000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847+579-7000"));
+ assertEquals(",8475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(",8475797000"));
+ assertEquals(";;8475797000,,",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(";;8475797000,,"));
+ assertEquals("+this+is$weird;,+",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+this+is$weird;,+"));
+ assertEquals("",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(""));
+ assertNull(PhoneNumberUtils.cdmaCheckAndProcessPlusCode(null));
+ }
+
+ @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));
+ }
}
diff --git a/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
index e733af9..6f25fd9 100644
--- a/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
@@ -44,13 +44,22 @@
assertEquals("890", IccUtils.bcdToString(data, 0, data.length));
/*
- * bcdByteToInt()
- */
+ * gsmBcdByteToInt()
+ */
- assertEquals(98, IccUtils.bcdByteToInt((byte) 0x89));
+ assertEquals(98, IccUtils.gsmBcdByteToInt((byte) 0x89));
// Out of range is treated as 0
- assertEquals(8, IccUtils.bcdByteToInt((byte) 0x8c));
+ assertEquals(8, IccUtils.gsmBcdByteToInt((byte) 0x8c));
+
+ /*
+ * cdmaBcdByteToInt()
+ */
+
+ assertEquals(89, IccUtils.cdmaBcdByteToInt((byte) 0x89));
+
+ // Out of range is treated as 0
+ assertEquals(80, IccUtils.gsmBcdByteToInt((byte) 0x8c));
/*
* adnStringFieldToString()
@@ -76,4 +85,3 @@
}
}
-
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
index b4fb324..fdfafe1 100644
--- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
@@ -47,6 +47,7 @@
suite.addTestSuite(SimUtilsTest.class);
suite.addTestSuite(SimPhoneBookTest.class);
suite.addTestSuite(SimSmsTest.class);
+ suite.addTestSuite(TelephonyUtilsTest.class);
return suite;
}
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
new file mode 100644
index 0000000..bf0c88b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
@@ -0,0 +1,219 @@
+/**
+ * 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 com.android.internal.telephony;
+
+import com.android.internal.telephony.RetryManager;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class TelephonyUtilsTest extends TestCase {
+
+ /**
+ * After first creating the RetryManager
+ * isRetryNeeded should be false and the time 0
+ */
+ @SmallTest
+ public void testRetryManagerEmpty() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertEquals(0, rm.getRetryCount());
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.setRetryCount(123);
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ assertTrue(rm.isRetryForever());
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.setRetryCount(2);
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+ }
+
+ /**
+ * A simple test and that randomization is doing something.
+ */
+ @SmallTest
+ public void testRetryManagerSimplest() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure(1, 500, 10));
+ int loops = 10;
+ int count = 0;
+ for (int i = 0; i < loops; i++) {
+ assertTrue(rm.isRetryNeeded());
+ int time = rm.getRetryTimer();
+ assertTrue((time >= 500) && (time < 600));
+ if (time == 500) {
+ count++;
+ }
+ }
+ assertFalse(count == loops);
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ rm.setRetryCount(0);
+ assertTrue(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test multiple values using simple configuration.
+ */
+ @SmallTest
+ public void testRetryManagerSimple() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure(3, 1000, 0));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ assertEquals(rm.getRetryTimer(), 1000);
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ }
+
+ /**
+ * Test string configuration, simplest
+ */
+ @SmallTest
+ public void testRetryManageSimpleString() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure("101"));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(101, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test infinite retires
+ */
+ @SmallTest
+ public void testRetryManageInfinite() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure("1000,2000,3000,max_retries=infinite"));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(2000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ // All others are 3000 and isRetryNeeded is always true
+ for (int i=0; i < 100; i++) {
+ assertEquals(3000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ }
+ }
+
+ /**
+ * Test string configuration using all options.
+ */
+ @SmallTest
+ public void testRetryManageString() throws Exception {
+ RetryManager rm = new RetryManager();
+ int time;
+
+ assertTrue(rm.configure("max_retries=4,"
+ + "default_randomization=100,1000, 2000 :200 , 3000"));
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 1000) && (time < 1100));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 2000) && (time < 2200));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 3000) && (time < 3100));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 3000) && (time < 3100));
+
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test string configuration using all options.
+ */
+ @SmallTest
+ public void testRetryManageForever() throws Exception {
+ RetryManager rm = new RetryManager();
+ int time;
+
+ assertTrue(rm.configure("1000, 2000, 3000"));
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(1000, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ rm.increaseRetryCount();
+ rm.increaseRetryCount();
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertTrue(rm.isRetryForever());
+ assertEquals(3, rm.getRetryCount());
+ assertEquals(3000, rm.getRetryTimer());
+
+ rm.setRetryCount(1);
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(1, rm.getRetryCount());
+ assertEquals(2000, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ assertTrue(rm.isRetryNeeded());
+ assertTrue(rm.isRetryForever());
+ rm.resetRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(1000, rm.getRetryTimer());
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
index 7107412..b96743a 100644
--- a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -81,7 +81,7 @@
mRadioControl = mGSMTestHandler.getSimulatedCommands();
mHandler = mGSMTestHandler.getHandler();
- mGSMPhone.registerForPhoneStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
+ mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null);
mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
@@ -109,7 +109,7 @@
protected void tearDown() throws Exception {
mRadioControl.shutdown();
- mGSMPhone.unregisterForPhoneStateChanged(mHandler);
+ mGSMPhone.unregisterForPreciseCallStateChanged(mHandler);
mGSMPhone.unregisterForNewRingingConnection(mHandler);
mGSMPhone.unregisterForDisconnect(mHandler);
mGSMPhone.setOnPostDialCharacter(mHandler, 0, null);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index a389461..b61b307 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -18,6 +18,8 @@
import android.os.Handler;
import android.os.Message;
+import android.webkit.MockGeolocation;
+import android.webkit.WebStorage;
import java.util.HashMap;
@@ -25,7 +27,7 @@
private EventSender mEventSender;
private LayoutTestController mLayoutTestController;
-
+
private static final int EVENT_DOM_LOG = 1;
private static final int EVENT_FIRE_KBD = 2;
private static final int EVENT_KEY_DOWN_1 = 3;
@@ -57,6 +59,8 @@
private static final int LAYOUT_SET_WINDOW_KEY = 38;
private static final int LAYOUT_TEST_REPAINT = 39;
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;
CallbackProxy(EventSender eventSender,
LayoutTestController layoutTestController) {
@@ -190,6 +194,14 @@
case LAYOUT_WAIT_UNTIL_DONE:
mLayoutTestController.waitUntilDone();
break;
+
+ case LAYOUT_DUMP_DATABASE_CALLBACKS:
+ mLayoutTestController.dumpDatabaseCallbacks();
+ break;
+
+ case LAYOUT_SET_CAN_OPEN_WINDOWS:
+ mLayoutTestController.setCanOpenWindows();
+ break;
}
}
@@ -314,7 +326,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() {
@@ -325,4 +337,31 @@
obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
}
+ public void dumpDatabaseCallbacks() {
+ obtainMessage(LAYOUT_DUMP_DATABASE_CALLBACKS).sendToTarget();
+ }
+
+ public void clearAllDatabases() {
+ WebStorage.getInstance().deleteAllData();
+ }
+
+ public void setDatabaseQuota(long quota) {
+ WebStorage.getInstance().setQuotaForOrigin("file://", quota);
+ }
+
+ public void setCanOpenWindows() {
+ 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);
+ }
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4f162b3..ede5197 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -83,7 +83,20 @@
};
static final String [] ignoreTestList = {
- };
+ // RegExp is exponatal
+ "fast/regex/test1.html",
+ "fast/regex/slow.html",
+ // RegExp is too large, causing OOM
+ "fast/js/regexp-charclass-crash.html",
+ // The Android browser has no notion of private browsing.
+ "storage/private-browsing-readonly.html",
+ "storage/domstorage/localstorage/private-browsing-affects-storage.html",
+ "storage/domstorage/sessionstorage/private-browsing-affects-storage.html",
+ // Android layout tests are stored in "layout_tests". The following two
+ // tests expect "LayoutTests" in their output.
+ "storage/domstorage/localstorage/iframe-events.html",
+ "storage/domstorage/sessionstorage/iframe-events.html"
+ };
static void fillIgnoreResultSet() {
// need test plugin
@@ -195,11 +208,7 @@
ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
// extra spacing because iFrames rendered next to each other on Apple
ignoreResultList.add("fast/loader/opaque-base-url.html");
- // RegExp is too large, causing OOM
- ignoreResultList.add("fast/js/regexp-charclass-crash.html");
ignoreResultList.add("fast/text/plain-text-line-breaks.html");
-
-
}
static void fillBugTable() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index 6166dd0..e1d802a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -58,5 +58,8 @@
public void queueLoad(String Url, String frameTarget);
public void setAcceptsEditing(boolean b);
-
+
+ // For storage tests
+ public void dumpDatabaseCallbacks();
+ public void setCanOpenWindows();
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
@@ -42,7 +45,7 @@
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
private BufferedOutputStream mBufferedOutputTimedoutStream;
-
+
public void passed(String layout_file) {
try {
mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@
e.printStackTrace();
}
}
-
+
public void failed(String layout_file) {
try {
mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@
e.printStackTrace();
}
}
-
+
public void noresult(String layout_file) {
try {
mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@
e.printStackTrace();
}
}
-
+
public void timedout(String url) {
try {
mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@
e.printStackTrace();
}
}
-
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-
+
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@
e.printStackTrace();
}
}
-
+
public void close() {
try {
mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@
private static final String LOGTAG = "LayoutTests";
static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
+
static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
private String mTestPathPrefix;
private boolean mFinished;
-
+
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
+
+ int addr = -1;
+ try {
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address.", ioe);
+ }
+ if(addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
}
// This function writes the result of the layout test to
@@ -157,7 +181,7 @@
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
+
private void getTestList() {
// Read test list.
try {
@@ -174,7 +198,7 @@
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
}
-
+
private void resumeTestList() {
// read out the test name it stoped last time.
try {
@@ -189,7 +213,7 @@
Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
}
}
-
+
private void clearTestStatus() {
// Delete TEST_STATUS_FILE
try {
@@ -208,13 +232,13 @@
// Write actual results to result directory.
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
-
+
private String getExpectedResultFile(String test) {
int pos = test.lastIndexOf('.');
if(pos == -1)
return null;
String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ return shortName + "-expected.txt";
}
private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@
// Wrap up
private void failedCase(String file) {
Log.w("Layout test: ", file + " failed");
- mResultRecorder.failed(file);
+ mResultRecorder.failed(file);
}
private void passedCase(String file) {
@@ -236,7 +260,7 @@
Log.v("Layout test:", file + " no expected result");
mResultRecorder.noresult(file);
}
-
+
private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
Log.v(LOGTAG, " Processing result: " + testFile);
@@ -257,13 +281,13 @@
break;
}
}
-
+
if (passing) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
+
fe.close();
fr.close();
} catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@
noresultCase(testFile);
}
}
-
+
private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
activity.setCallback(new TestShellCallback() {
public void finished() {
@@ -287,7 +311,7 @@
LayoutTestsAutoTest.this.notifyAll();
}
}
-
+
public void timedOut(String url) {
}
});
@@ -306,16 +330,16 @@
resultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
mFinished = false;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
-
+
// Wait until done.
synchronized (this) {
while(!mFinished){
@@ -324,18 +348,18 @@
} catch (InterruptedException e) { }
}
}
-
+
if (!mRebaselineResults) {
String expectedResultFile = getExpectedResultFile(test);
File f = new File(expectedResultFile);
if (!f.exists()) {
expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
processResult(test, resultFile, expectedResultFile);
}
- }
-
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@
}
this.mTestList = new Vector<String>();
-
+
// Read settings
try {
this.mTestPathPrefix =
(new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
return;
}
-
+
this.mRebaselineResults = runner.mRebaseline;
-
+
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
timeout = DEFAULT_TIMEOUT_IN_MILLIS;
}
-
+
this.mResultRecorder = new MyTestRecorder(resume);
-
+
if (!resume)
clearTestStatus();
-
+
getTestList();
if (resume)
resumeTestList();
@@ -377,6 +401,15 @@
TestShellActivity activity = (TestShellActivity) getActivity();
// Run tests.
+ int addr = -1;
+ try{
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while resolving test host name", ioe);
+ }
+ if(addr == -1) {
+ Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+ }
for (int i = 0; i < mTestList.size(); i++) {
String s = mTestList.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-
+ if(fs8000 != null)
+ fs8000.stop();
+ if(fs8080 != null)
+ fs8080.stop();
+ if(fs8443 != null)
+ fs8443.stop();
+
activity.finish();
}
+ private void startForwardServerIfNeeded() {
+ try {
+ if(fs8000 != null)
+ fs8000.start();
+ if(fs8080 != null)
+ fs8080.start();
+ if(fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ }
+ }
+
+ private String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ startForwardServerIfNeeded();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@
Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
}
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
+
return test_path;
}
-
+
public void generateTestList() {
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@
} catch (Exception e) {
e.printStackTrace();
}
-
+
executeLayoutTests(false);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 09f7cbc..e060388 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -34,6 +34,7 @@
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
+import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
@@ -43,6 +44,8 @@
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Vector;
public class TestShellActivity extends Activity implements LayoutTestController {
@@ -88,7 +91,7 @@
}
public void clearCache() {
- mWebView.clearCache(true);
+ mWebView.freeMemory();
}
@Override
@@ -100,52 +103,20 @@
setContentView(contentView);
mWebView = new WebView(this);
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(mChromeClient);
- mWebView.setWebViewClient(new WebViewClient(){
-
- @Override
- public void onPageFinished(WebView view, String url) {
- Log.v(LOGTAG, "onPageFinished, url=" + url);
- super.onPageFinished(view, url);
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- Log.v(LOGTAG, "onPageStarted, url=" + url);
- super.onPageStarted(view, url, favicon);
- }
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description,
- String failingUrl) {
- Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
- + ", desc=" + description + ", url=" + failingUrl);
- super.onReceivedError(view, errorCode, description, failingUrl);
- }
-
- @Override
- public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
- String host, String realm) {
- handler.cancel();
- }
-
- @Override
- public void onReceivedSslError(WebView view, SslErrorHandler handler,
- SslError error) {
- handler.proceed();
- }
-
- });
mEventSender = new WebViewEventSender(mWebView);
mCallbackProxy = new CallbackProxy(mEventSender, this);
- mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
- mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ setupWebViewForLayoutTests(mWebView, mCallbackProxy);
+
contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+ // Expose window.gc function to JavaScript. JSC build exposes
+ // this function by default, but V8 requires the flag to turn it on.
+ // WebView::setJsFlags is noop in JSC build.
+ mWebView.setJsFlags("--expose_gc");
+
mHandler = new AsyncHandler();
Intent intent = getIntent();
@@ -262,8 +233,8 @@
@Override
public void onLowMemory() {
super.onLowMemory();
- Log.e(LOGTAG, "Low memory, kill self");
- System.exit(1);
+ Log.e(LOGTAG, "Low memory, clearing caches");
+ mWebView.freeMemory();
}
// Dump the page
@@ -290,6 +261,12 @@
if (mDialogStrings != null)
os.write(mDialogStrings.toString().getBytes());
mDialogStrings = null;
+ if (mDatabaseCallbackStrings != null)
+ os.write(mDatabaseCallbackStrings.toString().getBytes());
+ mDatabaseCallbackStrings = null;
+ if (mConsoleMessages != null)
+ os.write(mConsoleMessages.toString().getBytes());
+ mConsoleMessages = null;
if (webkitData != null)
os.write(webkitData.getBytes());
os.flush();
@@ -438,6 +415,51 @@
mWebView.invalidate();
}
+ public void dumpDatabaseCallbacks() {
+ Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
+ mDumpDatabaseCallbacks = true;
+ }
+
+ public void setCanOpenWindows() {
+ Log.v(LOGTAG, "setCanOpenWindows called.");
+ mCanOpenWindows = true;
+ }
+
+ private final WebViewClient mViewClient = new WebViewClient(){
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ Log.v(LOGTAG, "onPageFinished, url=" + url);
+ super.onPageFinished(view, url);
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ Log.v(LOGTAG, "onPageStarted, url=" + url);
+ super.onPageStarted(view, url, favicon);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
+ + ", desc=" + description + ", url=" + failingUrl);
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
+ String host, String realm) {
+ handler.cancel();
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ handler.proceed();
+ }
+ };
+
+
private final WebChromeClient mChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
@@ -512,6 +534,78 @@
result.confirm();
return true;
}
+
+ @Override
+ public boolean onJsTimeout() {
+ Log.v(LOGTAG, "JavaScript timeout");
+ return false;
+ }
+
+ @Override
+ public void onExceededDatabaseQuota(String url_str,
+ String databaseIdentifier, long currentQuota, long totalUsedQuota,
+ WebStorage.QuotaUpdater callback) {
+ if (mDumpDatabaseCallbacks) {
+ if (mDatabaseCallbackStrings == null) {
+ mDatabaseCallbackStrings = new StringBuffer();
+ }
+
+ String protocol = "";
+ String host = "";
+ int port = 0;
+
+ try {
+ URL url = new URL(url_str);
+ protocol = url.getProtocol();
+ host = url.getHost();
+ if (url.getPort() > -1) {
+ port = url.getPort();
+ }
+ } catch (MalformedURLException e) {}
+
+ String databaseCallbackString =
+ "UI DELEGATE DATABASE CALLBACK: " +
+ "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
+ ", " + host + ", " + port + "} database:" +
+ databaseIdentifier + "\n";
+ Log.v(LOGTAG, "LOG: "+databaseCallbackString);
+ mDatabaseCallbackStrings.append(databaseCallbackString);
+ }
+ // Give 5MB more quota.
+ callback.updateQuota(currentQuota + 1024 * 1024 * 5);
+ }
+
+ @Override
+ public void addMessageToConsole(String message, int lineNumber,
+ String sourceID) {
+ if (mConsoleMessages == null) {
+ mConsoleMessages = new StringBuffer();
+ }
+ String consoleMessage = "CONSOLE MESSAGE: line "
+ + lineNumber +": "+ message +"\n";
+ mConsoleMessages.append(consoleMessage);
+ Log.v(LOGTAG, "LOG: "+consoleMessage);
+ }
+
+ @Override
+ public boolean onCreateWindow(WebView view, boolean dialog,
+ boolean userGesture, Message resultMsg) {
+ if (!mCanOpenWindows) {
+ return false;
+ }
+
+ // We never display the new window, just create the view and
+ // allow it's content to execute and be recorded by the test
+ // runner.
+
+ WebView newWindowView = new WebView(TestShellActivity.this);
+ setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
+ WebView.WebViewTransport transport =
+ (WebView.WebViewTransport) resultMsg.obj;
+ transport.setWebView(newWindowView);
+ resultMsg.sendToTarget();
+ return true;
+ }
};
private void resetTestStatus() {
@@ -520,9 +614,36 @@
mTimedOut = false;
mDumpTitleChanges = false;
mRequestedWebKitData = false;
+ mDumpDatabaseCallbacks = false;
+ mCanOpenWindows = false;
mEventSender.resetMouse();
}
+ private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
+ if (webview == null) {
+ return;
+ }
+
+ WebSettings settings = webview.getSettings();
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+ settings.setAppCacheMaxSize(Long.MAX_VALUE);
+ settings.setJavaScriptEnabled(true);
+ settings.setJavaScriptCanOpenWindowsAutomatically(true);
+ settings.setSupportMultipleWindows(true);
+ settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+ settings.setDatabaseEnabled(true);
+ settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
+ settings.setDomStorageEnabled(true);
+ settings.setWorkersEnabled(false);
+
+ webview.addJavascriptInterface(callbackProxy, "layoutTestController");
+ webview.addJavascriptInterface(callbackProxy, "eventSender");
+
+ webview.setWebChromeClient(mChromeClient);
+ webview.setWebViewClient(mViewClient);
+ }
+
private WebView mWebView;
private WebViewEventSender mEventSender;
private AsyncHandler mHandler;
@@ -550,6 +671,10 @@
private StringBuffer mDialogStrings;
private boolean mKeepWebHistory;
private Vector mWebHistory;
+ private boolean mDumpDatabaseCallbacks;
+ private StringBuffer mDatabaseCallbackStrings;
+ private StringBuffer mConsoleMessages;
+ private boolean mCanOpenWindows;
static final String TIMEOUT_STR = "**Test timeout";
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ private static final String LOGTAG = "AdbUtils";
+
+ /**
+ *
+ * Convert integer format IP into xxx.xxx.xxx.xxx format
+ *
+ * @param host IP address in integer format
+ * @return human readable format
+ */
+ public static String convert(int host) {
+ return ((host >> 24) & 0xFF) + "."
+ + ((host >> 16) & 0xFF) + "."
+ + ((host >> 8) & 0xFF) + "."
+ + (host & 0xFF);
+ }
+
+ /**
+ *
+ * Resolve DNS name into IP address
+ *
+ * @param host DNS name
+ * @return IP address in integer format
+ * @throws IOException
+ */
+ public static int resolve(String host) throws IOException {
+ Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+ DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+ OutputStream os = localSocket.getOutputStream();
+ int count_read = 0;
+ byte[] buf = new byte[128];
+
+ if (localSocket == null || dis == null || os == null)
+ return -1;
+ String cmd = "dns:" + host;
+
+ if(!sendAdbCmd(dis, os, cmd))
+ return -1;
+
+ count_read = dis.readInt();
+ localSocket.close();
+ return count_read;
+ }
+
+ /**
+ *
+ * Send an ADB command using existing socket connection
+ *
+ * the streams provided must be from a socket connected to adbd already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ public static boolean sendAdbCmd(InputStream is, OutputStream os,
+ String cmd) throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOGTAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+ if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+ private static final String LOGTAG = "ForwardServer";
+
+ private int remotePort;
+ private int remoteAddress;
+ private int localPort;
+ private ServerSocket serverSocket;
+ private boolean started;
+
+ private Set<Forwarder> forwarders;
+
+ public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+ this.localPort = localPort;
+ this.remoteAddress = remoteAddress;
+ this.remotePort = remotePort;
+ started = false;
+ forwarders = new HashSet<Forwarder>();
+ }
+
+ public synchronized void start() throws IOException {
+ if(!started) {
+ serverSocket = new ServerSocket(localPort);
+ Thread serverThread = new Thread(new ServerRunner(serverSocket));
+ serverThread.setName(LOGTAG);
+ serverThread.start();
+ started = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(started) {
+ synchronized (forwarders) {
+ for(Forwarder forwarder : forwarders)
+ forwarder.stop();
+ forwarders.clear();
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "exception while closing", ioe);
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ public synchronized boolean isRunning() {
+ return started;
+ }
+
+ private class ServerRunner implements Runnable {
+
+ private ServerSocket socket;
+
+ public ServerRunner(ServerSocket socket) {
+ this.socket = socket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ Socket localSocket = socket.accept();
+ Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+ if(remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while closing socket", ioe);
+ } finally {
+ Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+ }
+ } else {
+ Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+ ForwardServer.this);
+ forwarder.start();
+ }
+ }
+ } catch (IOException ioe) {
+ return;
+ }
+ }
+ }
+
+ public void register(Forwarder forwarder) {
+ synchronized (forwarders) {
+ if(!forwarders.contains(forwarder)) {
+ forwarders.add(forwarder);
+ }
+ }
+ }
+
+ public void unregister(Forwarder recyclable) {
+ synchronized (forwarders) {
+ if(forwarders.contains(recyclable)) {
+ recyclable.stop();
+ forwarders.remove(recyclable);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+ private ForwardServer server;
+ private Socket from, to;
+
+ private static final String LOGTAG = "Forwarder";
+
+ public Forwarder (Socket from, Socket to, ForwardServer server) {
+ this.server = server;
+ this.from = from;
+ this.to = to;
+ server.register(this);
+ }
+
+ public void start() {
+ Thread outgoing = new Thread(new SocketPipe(from, to));
+ Thread incoming = new Thread(new SocketPipe(to, from));
+ outgoing.setName(LOGTAG);
+ incoming.setName(LOGTAG);
+ outgoing.start();
+ incoming.start();
+ }
+
+ public void stop() {
+ shutdown(from);
+ shutdown(to);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ socket.shutdownInput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownInput", e);
+ }
+ try {
+ socket.shutdownOutput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownOutput", e);
+ }
+ try {
+ socket.close();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#close", e);
+ }
+ }
+
+ private class SocketPipe implements Runnable {
+
+ private Socket in, out;
+
+ public SocketPipe(Socket in, Socket out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int length;
+ InputStream is = in.getInputStream();
+ OutputStream os = out.getOutputStream();
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException ioe) {
+ } finally {
+ server.unregister(Forwarder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipe{" + in + "=>" + out + "}";
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index aa3d186..a8af7f8 100644
--- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -8,6 +8,7 @@
import android.net.Uri;
import android.test.AndroidTestCase;
import android.text.TextUtils;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Map;
@@ -26,7 +27,7 @@
static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
- private final String ACCOUNT = "account@goo.com";
+ private final Account ACCOUNT = new Account("account@goo.com", "example.type");
private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
@@ -65,25 +66,31 @@
mExpectations.clear();
}
- ContentValues newValues(String data, String syncId, String syncAccount,
+ ContentValues newValues(String data, String syncId, Account syncAccount,
String syncTime, String syncVersion, Long syncLocalId) {
ContentValues values = new ContentValues();
if (data != null) values.put("data", data);
if (syncTime != null) values.put("_sync_time", syncTime);
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.name);
+ values.put("_sync_account_type", syncAccount.type);
+ }
values.put("_sync_local_id", syncLocalId);
values.put("_sync_dirty", 0);
return values;
}
- ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+ ContentValues newDeletedValues(String syncId, Account syncAccount, String syncVersion,
Long syncLocalId) {
ContentValues values = new ContentValues();
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.name);
+ values.put("_sync_account_type", syncAccount.type);
+ }
if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
return values;
}
@@ -380,6 +387,7 @@
+ "_sync_local_id INTEGER, "
+ "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
mDb.execSQL("CREATE TABLE deleted_items ("
@@ -388,6 +396,7 @@
+ "_sync_id TEXT, "
+ "_sync_local_id INTEGER, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
}
@@ -501,7 +510,7 @@
throw new UnsupportedOperationException();
}
- public void onSyncStart(SyncContext context, String account) {
+ public void onSyncStart(SyncContext context, Account account) {
throw new UnsupportedOperationException();
}
@@ -509,7 +518,7 @@
throw new UnsupportedOperationException();
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
throw new UnsupportedOperationException();
}
@@ -544,24 +553,24 @@
throw new UnsupportedOperationException();
}
- protected void onAccountsChanged(String[] accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
throw new UnsupportedOperationException();
}
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
- String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table
+ ) {
throw new UnsupportedOperationException();
}
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
throw new UnsupportedOperationException();
}
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
throw new UnsupportedOperationException();
}
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
throw new UnsupportedOperationException();
}
}
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
new file mode 100644
index 0000000..1ba9d66a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Map;
+import java.util.Map.Entry;
+
+@SmallTest
+public class ContentProviderOperationTest extends TestCase {
+ private final static Uri sTestUri1 = Uri.parse("content://authority/blah");
+ private final static ContentValues sTestValues1;
+
+ private final static Class<ContentProviderOperation.Builder> CLASS_BUILDER =
+ ContentProviderOperation.Builder.class;
+ private final static Class<ContentProviderOperation> CLASS_OPERATION =
+ ContentProviderOperation.class;
+
+ static {
+ sTestValues1 = new ContentValues();
+ sTestValues1.put("a", 1);
+ sTestValues1.put("b", "two");
+ }
+
+ public void testInsert() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, null, 0);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testInsertNoValues() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertNull(values);
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, null, 0);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testInsertFailed() {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ try {
+ op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return null;
+ }
+ }, null, 0);
+ fail("the apply should have thrown an OperationApplicationException");
+ } catch (OperationApplicationException e) {
+ // this is the expected case
+ }
+ }
+
+ public void testInsertWithBackRefs() throws OperationApplicationException {
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .withValueBackReference("a1", 3)
+ .withValueBackReference("a2", 1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ ContentValues expected = new ContentValues(sTestValues1);
+ expected.put("a1", 103);
+ expected.put("a2", 101);
+ assertEquals(expected.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, previousResults, previousResults.length);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testUpdate() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ ContentProviderResult[] backRefs = new ContentProviderResult[2];
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, backRefs, 1);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testAssert() {
+ // Build an operation to assert values match provider
+ ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+ .withValues(sTestValues1).build();
+
+ try {
+ // Assert that values match from cursor
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // Return cursor over specific set of values
+ return getCursor(sTestValues1);
+ }
+ }, null, 0);
+ } catch (OperationApplicationException e) {
+ fail("newAssert() failed");
+ }
+ }
+
+ /**
+ * Build a {@link Cursor} with a single row that contains all values
+ * provided through the given {@link ContentValues}.
+ */
+ private Cursor getCursor(ContentValues contentValues) {
+ final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
+ final String[] keys = new String[valueSet.size()];
+ final Object[] values = new Object[valueSet.size()];
+
+ int i = 0;
+ for (Entry<String, Object> entry : valueSet) {
+ keys[i] = entry.getKey();
+ values[i] = entry.getValue();
+ i++;
+ }
+
+ final MatrixCursor cursor = new MatrixCursor(keys);
+ cursor.addRow(values);
+ return cursor;
+ }
+
+ public void testValueBackRefs() {
+ ContentValues values = new ContentValues();
+ values.put("a", "in1");
+ values.put("a2", "in2");
+ values.put("b", "in3");
+ values.put("c", "in4");
+
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+
+ ContentValues expectedValues = new ContentValues(values);
+ expectedValues.put("a1", "103");
+ expectedValues.put("a2", "101");
+ expectedValues.put("a3", "102");
+
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(values)
+ .withValueBackReference("a1", 3)
+ .withValueBackReference("a2", 1)
+ .withValueBackReference("a3", 2)
+ .build();
+ ContentValues v2 = op1.resolveValueBackReferences(previousResults, previousResults.length);
+ assertEquals(expectedValues, v2);
+ }
+
+ public void testSelectionBackRefs() {
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+
+ String[] selectionArgs = new String[]{"a", null, null, "b", null};
+
+ final ContentValues values = new ContentValues();
+ values.put("unused", "unused");
+
+ ContentProviderOperation op1 = ContentProviderOperation.newUpdate(sTestUri1)
+ .withSelectionBackReference(1, 3)
+ .withSelectionBackReference(2, 1)
+ .withSelectionBackReference(4, 2)
+ .withSelection("unused", selectionArgs)
+ .withValues(values)
+ .build();
+ String[] s2 = op1.resolveSelectionArgsBackReferences(
+ previousResults, previousResults.length);
+ assertEquals("a,103,101,b,102", TextUtils.join(",", s2));
+ }
+
+ public void testParcelingOperation() throws NoSuchFieldException, IllegalAccessException,
+ NoSuchMethodException, InvocationTargetException, InstantiationException {
+ Parcel parcel = Parcel.obtain();
+ ContentProviderOperation op1;
+ ContentProviderOperation op2;
+
+ HashMap<Integer, Integer> selArgsBackRef = new HashMap<Integer, Integer>();
+ selArgsBackRef.put(1, 2);
+ selArgsBackRef.put(3, 4);
+
+ ContentValues values = new ContentValues();
+ values.put("v1", "val1");
+ values.put("v2", "43");
+
+ ContentValues valuesBackRef = new ContentValues();
+ values.put("v3", "val3");
+ values.put("v4", "44");
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(
+ Uri.parse("content://goo/bar"));
+
+ builderSetExpectedCount(builder, 42);
+ builderSetSelection(builder, "selection");
+ builderSetSelectionArgs(builder, new String[]{"a", "b"});
+ builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
+ builderSetValues(builder, values);
+ builderSetValuesBackReferences(builder, valuesBackRef);
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(ContentProviderOperation.TYPE_INSERT, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
+ assertEquals("selection", operationGetSelection(op2));
+ assertEquals(2, operationGetSelectionArgs(op2).length);
+ assertEquals("a", operationGetSelectionArgs(op2)[0]);
+ assertEquals("b", operationGetSelectionArgs(op2)[1]);
+ assertEquals(values, operationGetValues(op2));
+ assertEquals(valuesBackRef, operationGetValuesBackReferences(op2));
+ assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
+ assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
+ assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
+ } finally {
+ parcel.recycle();
+ }
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(
+ Uri.parse("content://goo/bar"));
+
+ builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+ assertEquals(ContentProviderOperation.TYPE_UPDATE, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertNull(operationGetExpectedCount(op2));
+ assertNull(operationGetSelection(op2));
+ assertNull(operationGetSelectionArgs(op2));
+ assertNull(operationGetValues(op2));
+ assertNull(operationGetValuesBackReferences(op2));
+ assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
+ assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
+ assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
+ } finally {
+ parcel.recycle();
+ }
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(
+ Uri.parse("content://goo/bar"));
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+ assertEquals(ContentProviderOperation.TYPE_DELETE, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertNull(operationGetExpectedCount(op2));
+ assertNull(operationGetSelection(op2));
+ assertNull(operationGetSelectionArgs(op2));
+ assertNull(operationGetValues(op2));
+ assertNull(operationGetValuesBackReferences(op2));
+ assertNull(operationGetSelectionArgsBackReferences(op2));
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static ContentProviderOperation newOperationFromBuilder(
+ ContentProviderOperation.Builder builder)
+ throws NoSuchMethodException, InstantiationException, IllegalAccessException,
+ InvocationTargetException {
+ final Constructor constructor = CLASS_OPERATION.getDeclaredConstructor(CLASS_BUILDER);
+ constructor.setAccessible(true);
+ return (ContentProviderOperation) constructor.newInstance(builder);
+ }
+
+ private void builderSetSelectionArgsBackReferences(
+ ContentProviderOperation.Builder builder, HashMap<Integer, Integer> selArgsBackRef)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelectionArgsBackReferences");
+ field.setAccessible(true);
+ field.set(builder, selArgsBackRef);
+ }
+
+ private void builderSetValuesBackReferences(
+ ContentProviderOperation.Builder builder, ContentValues valuesBackReferences)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mValuesBackReferences");
+ field.setAccessible(true);
+ field.set(builder, valuesBackReferences);
+ }
+
+ private void builderSetSelection(
+ ContentProviderOperation.Builder builder, String selection)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelection");
+ field.setAccessible(true);
+ field.set(builder, selection);
+ }
+
+ private void builderSetSelectionArgs(
+ ContentProviderOperation.Builder builder, String[] selArgs)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelectionArgs");
+ field.setAccessible(true);
+ field.set(builder, selArgs);
+ }
+
+ private void builderSetValues(
+ ContentProviderOperation.Builder builder, ContentValues values)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mValues");
+ field.setAccessible(true);
+ field.set(builder, values);
+ }
+
+ private void builderSetExpectedCount(
+ ContentProviderOperation.Builder builder, Integer expectedCount)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mExpectedCount");
+ field.setAccessible(true);
+ field.set(builder, expectedCount);
+ }
+
+ private int operationGetType(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mType");
+ field.setAccessible(true);
+ return field.getInt(operation);
+ }
+
+ private Uri operationGetUri(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mUri");
+ field.setAccessible(true);
+ return (Uri) field.get(operation);
+ }
+
+ private String operationGetSelection(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelection");
+ field.setAccessible(true);
+ return (String) field.get(operation);
+ }
+
+ private String[] operationGetSelectionArgs(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgs");
+ field.setAccessible(true);
+ return (String[]) field.get(operation);
+ }
+
+ private ContentValues operationGetValues(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mValues");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ private Integer operationGetExpectedCount(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mExpectedCount");
+ field.setAccessible(true);
+ return (Integer) field.get(operation);
+ }
+
+ private ContentValues operationGetValuesBackReferences(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mValuesBackReferences");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ private Map<Integer, Integer> operationGetSelectionArgsBackReferences(
+ ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgsBackReferences");
+ field.setAccessible(true);
+ return (Map<Integer, Integer>) field.get(operation);
+ }
+
+ public void testParcelingResult() {
+ Parcel parcel = Parcel.obtain();
+ ContentProviderResult result1;
+ ContentProviderResult result2;
+ try {
+ result1 = new ContentProviderResult(Uri.parse("content://goo/bar"));
+ result1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ result2 = ContentProviderResult.CREATOR.createFromParcel(parcel);
+ assertEquals("content://goo/bar", result2.uri.toString());
+ assertNull(result2.count);
+ } finally {
+ parcel.recycle();
+ }
+
+ parcel = Parcel.obtain();
+ try {
+ result1 = new ContentProviderResult(42);
+ result1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ result2 = ContentProviderResult.CREATOR.createFromParcel(parcel);
+ assertEquals(Integer.valueOf(42), result2.count);
+ assertNull(result2.uri);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ static class TestContentProvider extends ContentProvider {
+ public boolean onCreate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 3778742..d992627 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.backuptest">
+ <uses-permission android:name="android.permission.BACKUP_DATA" />
<application android:backupAgent="BackupTestAgent">
<activity android:name="BackupTestActivity" android:label="_BackupTest">
<intent-filter>
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_backup.sh b/tests/backup/test_backup.sh
index dbf9ed2..10b809d 100755
--- a/tests/backup/test_backup.sh
+++ b/tests/backup/test_backup.sh
@@ -1,27 +1,63 @@
#!/bin/bash
-#adb kill-server
+# 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.
+
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
+
+# wipe prior backup data for packages
+b_pkgs=$(a shell dumpsys backup | \
+ ruby -ne 'print($1+" ") if $_ =~ /^\s*ApplicationInfo\S+ (.+?)\}/')
+
+for pkg in $b_pkgs; do
+ a shell bmgr wipe "$pkg"
+done
+
+echo 'Waiting 5 seconds for things to settle...'
+sleep 5
+
+# run adb as root so we can poke at com.android.backuptest's data
+adb_root
+
+# show commands as we go
+set -x
# set the transport
-adb shell bmgr transport 1
+a shell bmgr transport com.google.android.backup/.BackupTransportService
# load up the three files
-adb shell "rm /data/data/com.android.backuptest/files/* ; \
- mkdir /data/data/com.android.backuptest ; \
- mkdir /data/data/com.android.backuptest/files ; \
- mkdir /data/data/com.android.backuptest/shared_prefs ; \
- echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
- echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
- echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
- echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
- echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+a shell \
+ "rm /data/data/com.android.backuptest/files/file.txt ; \
+ rm /data/data/com.android.backuptest/files/another_file.txt ; \
+ rm /data/data/com.android.backuptest/files/empty.txt ; \
+ mkdir /data/data/com.android.backuptest ; \
+ mkdir /data/data/com.android.backuptest/files ; \
+ mkdir /data/data/com.android.backuptest/shared_prefs ; \
+ echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" \
+ > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
+ echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
+ echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
+ echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+ date >> /data/data/com.android.backuptest/files/3.txt ; \
"
+# echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
# say that the data has changed
-adb shell bmgr backup com.android.backuptest
+a shell bmgr backup com.android.backuptest
# run the backup
-adb shell bmgr run
-
-
+a shell bmgr run
diff --git a/tests/backup/test_backup_common.sh b/tests/backup/test_backup_common.sh
new file mode 100755
index 0000000..61ec833
--- /dev/null
+++ b/tests/backup/test_backup_common.sh
@@ -0,0 +1,33 @@
+#!/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.
+
+export ADB_OPTS="$@"
+
+# run adb with options
+function a { $DRY_RUN adb $ADB_OPTS "$@"; }
+
+# restart adb as root and wait for it to come back again
+function adb_root
+{
+ root_status=$(a root)
+ if [ "$root_status" != "adbd is already running as root" ]; then
+ echo -n "Restarting adb as root..."
+ sleep 2
+ a 'wait-for-device'
+ echo done.
+ fi
+}
+
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
index ccf29cf..46b46e4 100755
--- a/tests/backup/test_restore.sh
+++ b/tests/backup/test_restore.sh
@@ -1,53 +1,111 @@
#!/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.
+
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
+
+[ -z "$BUGREPORT_DIR" ] && BUGREPORT_DIR="$HOME/backup/bugreports"
+
function check_file
{
- data=$(adb shell cat /data/data/com.android.backuptest/$1)
+ data=$(a shell cat /data/data/com.android.backuptest/$1)
if [ "$data" = "$2" ] ; then
echo "$1 has correct value [$2]"
+ return 0
else
echo $1 is INCORRECT
echo " value: [$data]"
echo " expected: [$2]"
+ return 1
fi
}
+function check_exists
+{
+ # return 0 if file exists, 1 otherwise
+ data=$(a shell "ls $@ 2> /dev/null >/dev/null && echo -n exists")
+ if [ "$data" = "exists" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# run adb as root so we can poke at com.android.backuptest's data
+adb_root
+
# delete the old data
echo --- Previous files
-adb shell "ls -l /data/data/com.android.backuptest/files"
-adb shell "rm /data/data/com.android.backuptest/files/*"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "rm /data/data/com.android.backuptest/files/*"
echo --- Previous shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
-adb shell "rm /data/data/com.android.backuptest/shared_prefs/*"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "rm /data/data/com.android.backuptest/shared_prefs/*"
echo --- Erased files and shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/files"
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
echo ---
echo
echo
-echo
+
+# FIXME: there's probably a smarter way to do this
+# FIXME: if we can get the android ID, that's probably the safest thing to do
+# pick the most recent set and restore from it
+restore_set=$(a shell bmgr list sets | head -n1 | awk '{print $1}')
# run the restore
-adb shell bmgr restore 0
+echo "Restoring from set [$restore_set]"
+a shell bmgr restore "$restore_set"
echo
echo
-echo
# check the results
-check_file files/file.txt "first file"
-check_file files/another_file.txt "asdf"
-check_file files/3.txt "3"
-check_file files/empty.txt ""
-check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>'
+export need_bug=0
+
+# make sure files have the expected contents
+check_file files/file.txt "first file" || need_bug=1
+check_file files/another_file.txt "asdf" || need_bug=1
+#check_file files/3.txt "3" || need_bug=1
+check_file files/empty.txt "" || need_bug=1
+check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>' || need_bug=1
+
+# make sure that missing files weren't somehow created
+check_exists files/file_doesnt_exist.txt && need_bug=1
+check_exists files/no_files_here.txt && need_bug=1
+
+if [ \( "$need_bug" -ne 0 \) -a -d "$BUGREPORT_DIR" ]; then
+ dev_id=$(a get-serialno)
+ filename="${dev_id}_`date +%s`"
+ echo "Grabbing bugreport; filename is $filename"
+ a bugreport > "$BUGREPORT_DIR/$filename.txt"
+fi
echo
-echo
-echo
echo --- Restored files
-adb shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/files"
echo --- Restored shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
echo ---
echo
+
+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/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
index 719e758..aebd68c 100644
--- a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
@@ -46,7 +46,7 @@
*/
public void testVibrate() throws RemoteException {
try {
- mHardwareService.vibrate(2000);
+ mHardwareService.vibrate(2000, new Binder());
fail("vibrate did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected
@@ -77,7 +77,7 @@
*/
public void testCancelVibrate() throws RemoteException {
try {
- mHardwareService.cancelVibrate();
+ mHardwareService.cancelVibrate(new Binder());
fail("cancelVibrate did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 63afe5c..32efa4e 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -15,7 +15,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
-#include <utils/ZipFile.h>
+#include "ZipFile.h"
#include "Bundle.h"
#include "SourcePos.h"
@@ -131,7 +131,9 @@
{
//printf("new AaptFile created %s\n", (const char*)sourceFile);
}
- virtual ~AaptFile() { }
+ virtual ~AaptFile() {
+ free(mData);
+ }
const String8& getPath() const { return mPath; }
const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
@@ -447,7 +449,13 @@
AaptSymbolEntry mDefSymbol;
};
-class ResourceTypeSet;
+class ResourceTypeSet : public RefBase,
+ public KeyedVector<String8,sp<AaptGroup> >
+{
+public:
+ ResourceTypeSet();
+};
+
/**
* Asset hierarchy being operated on.
@@ -455,8 +463,8 @@
class AaptAssets : public AaptDir
{
public:
- AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false) { }
- virtual ~AaptAssets() { }
+ AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false), mRes(NULL) { }
+ virtual ~AaptAssets() { delete mRes; }
const String8& getPackage() const { return mPackage; }
void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; }
@@ -474,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,
@@ -504,7 +514,7 @@
inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
inline void
- setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { mRes = res; }
+ setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
private:
String8 mPackage;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index fdc859c..2d8973d 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -17,7 +17,10 @@
ResourceTable.cpp \
Images.cpp \
Resource.cpp \
- SourcePos.cpp
+ SourcePos.cpp \
+ ZipEntry.cpp \
+ ZipFile.cpp
+
LOCAL_CFLAGS += -Wno-format-y2k
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a6fedf3..a671bd7 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -7,7 +7,10 @@
#define __BUNDLE_H
#include <stdlib.h>
-#include <utils.h> // android
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index e04491d..c0ae592 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -8,8 +8,10 @@
#include "ResourceTable.h"
#include "XMLNode.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <fcntl.h>
#include <errno.h>
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 0a4c68b..f2414dd 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -44,6 +44,9 @@
}
free(allocRows);
}
+ free(info9Patch.xDivs);
+ free(info9Patch.yDivs);
+ free(info9Patch.colors);
}
png_uint_32 width;
@@ -833,6 +836,7 @@
int i;
png_unknown_chunk unknowns[1];
+ unknowns[0].data = NULL;
png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * png_sizeof(png_bytep));
if (outRows == (png_bytepp) 0) {
@@ -939,6 +943,7 @@
free(outRows[i]);
}
free(outRows);
+ free(unknowns[0].data);
png_get_IHDR(write_ptr, write_info, &width, &height,
&bit_depth, &color_type, &interlace_type,
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 12a0445..882714c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -6,8 +6,10 @@
#include "Main.h"
#include "Bundle.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <getopt.h>
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index 65c0a8a..34ca5e5 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -6,10 +6,13 @@
#ifndef __MAIN_H
#define __MAIN_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include "Bundle.h"
#include "AaptAssets.h"
-#include <utils/ZipFile.h>
+#include "ZipFile.h"
extern int doVersion(Bundle* bundle);
extern int doList(Bundle* bundle);
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index eb7d6f5..999a5cf 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -7,8 +7,10 @@
#include "AaptAssets.h"
#include "ResourceTable.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <sys/types.h>
#include <dirent.h>
@@ -166,7 +168,7 @@
delete zip; // close the file so we can remove it in Win32
zip = NULL;
if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "WARNING: could not unlink '%s'\n", outputFile.string());
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
}
}
@@ -179,7 +181,7 @@
printf("Removing %s due to earlier failures\n", outputFile.string());
}
if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "WARNING: could not unlink '%s'\n", outputFile.string());
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
}
}
@@ -281,7 +283,7 @@
if (fileNameLen > excludeExtensionLen
&& (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen),
kExcludeExtension))) {
- fprintf(stderr, "WARNING: '%s' not added to Zip\n", storageName.string());
+ fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string());
return true;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 027e3ab..9a5127d 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -45,13 +45,6 @@
}
}
-class ResourceTypeSet : public RefBase,
- public KeyedVector<String8,sp<AaptGroup> >
-{
-public:
- ResourceTypeSet();
-};
-
ResourceTypeSet::ResourceTypeSet()
:RefBase(),
KeyedVector<String8,sp<AaptGroup> >()
@@ -181,7 +174,7 @@
static status_t parsePackage(const sp<AaptAssets>& assets, const sp<AaptGroup>& grp)
{
if (grp->getFiles().size() != 1) {
- fprintf(stderr, "WARNING: Multiple AndroidManifest.xml files found, using %s\n",
+ fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
grp->getFiles().valueAt(0)->getPrintableSource().string());
}
@@ -279,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,
@@ -295,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,
@@ -426,7 +421,7 @@
if (code == ResXMLTree::START_TAG) {
ssize_t index = parser.indexOfAttribute(NULL, "id");
if (index >= 0) {
- fprintf(stderr, "%s:%d: WARNING: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
+ fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
path.string(), parser.getLineNumber());
}
}
@@ -479,13 +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)
- fprintf(stderr, "aapt: error: "
- "*** Resource file '%s' exists only in an overlay\n",
- overlaySet->keyAt(overlayIndex).string());
- return false;
+ 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
@@ -1118,6 +1122,7 @@
printf(" Writing public definitions to %s.\n", bundle->getPublicOutputFile());
}
table.writePublicDefinitions(String16(assets->getPackage()), fp);
+ fclose(fp);
}
NOISY(
@@ -1135,7 +1140,6 @@
return err;
}
}
-
return err;
}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b004664..95a2384 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -663,6 +663,7 @@
const String16 public16("public");
const String16 public_padding16("public-padding");
const String16 private_symbols16("private-symbols");
+ const String16 add_resource16("add-resource");
const String16 skip16("skip");
const String16 eat_comment16("eat-comment");
@@ -960,6 +961,36 @@
}
continue;
+ } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+ SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+
+ String16 typeName;
+ ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+ if (typeIdx < 0) {
+ srcPos.error("A 'type' attribute is required for <add-resource>\n");
+ hasErrors = localHasErrors = true;
+ }
+ typeName = String16(block.getAttributeStringValue(typeIdx, &len));
+
+ String16 name;
+ ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+ if (nameIdx < 0) {
+ srcPos.error("A 'name' attribute is required for <add-resource>\n");
+ hasErrors = localHasErrors = true;
+ }
+ name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+ outTable->canAddEntry(srcPos, myPackage, typeName, name);
+
+ while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+ break;
+ }
+ }
+ }
+ continue;
+
} else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
@@ -1557,9 +1588,21 @@
}
#endif
if (overlay && !hasBagOrEntry(package, type, name)) {
- sourcePos.error("Can't add new bags in an overlay. See '%s'\n",
- String8(name).string());
- return UNKNOWN_ERROR;
+ bool canAdd = false;
+ sp<Package> p = mPackages.valueFor(package);
+ if (p != NULL) {
+ sp<Type> t = p->getTypes().valueFor(type);
+ if (t != NULL) {
+ if (t->getCanAddEntries().indexOf(name) >= 0) {
+ canAdd = true;
+ }
+ }
+ }
+ if (!canAdd) {
+ sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
+ String8(name).string());
+ return UNKNOWN_ERROR;
+ }
}
sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
if (e == NULL) {
@@ -1724,6 +1767,15 @@
return false;
}
+void ResourceTable::canAddEntry(const SourcePos& pos,
+ const String16& package, const String16& type, const String16& name)
+{
+ sp<Type> t = getType(package, type, pos);
+ if (t != NULL) {
+ t->canAddEntry(name);
+ }
+}
+
size_t ResourceTable::size() const {
return mPackages.size();
}
@@ -3215,6 +3267,11 @@
return NO_ERROR;
}
+void ResourceTable::Type::canAddEntry(const String16& name)
+{
+ mCanAddEntries.add(name);
+}
+
sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
const SourcePos& sourcePos,
const ResTable_config* config,
@@ -3224,9 +3281,10 @@
int pos = -1;
sp<ConfigList> c = mConfigs.valueFor(entry);
if (c == NULL) {
- if (overlay == true) {
- sourcePos.error("Resource %s appears in overlay but not"
- " in the base package.\n", String8(entry).string());
+ if (overlay == true && mCanAddEntries.indexOf(entry) < 0) {
+ sourcePos.error("Resource at %s appears in overlay but not"
+ " in the base package; use <add-resource> to add.\n",
+ String8(entry).string());
return NULL;
}
c = new ConfigList(entry, sourcePos);
@@ -3554,26 +3612,26 @@
}
if (p == NULL) {
- fprintf(stderr, "WARNING: Package not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Package not found for resource #%08x\n", resID);
return NULL;
}
int tid = Res_GETTYPE(resID);
if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) {
- fprintf(stderr, "WARNING: Type not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Type not found for resource #%08x\n", resID);
return NULL;
}
sp<Type> t = p->getOrderedTypes()[tid];
int eid = Res_GETENTRY(resID);
if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) {
- fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
return NULL;
}
sp<ConfigList> c = t->getOrderedConfigs()[eid];
if (c == NULL) {
- fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
return NULL;
}
@@ -3581,7 +3639,7 @@
if (config) cdesc = *config;
sp<Entry> e = c->getEntries().valueFor(cdesc);
if (c == NULL) {
- fprintf(stderr, "WARNING: Entry configuration not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID);
return NULL;
}
@@ -3599,7 +3657,7 @@
for (size_t i=0; i<N; i++) {
const Item& it = e->getBag().valueAt(i);
if (it.bagKeyId == 0) {
- fprintf(stderr, "WARNING: ID not yet assigned to '%s' in bag '%s'\n",
+ fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
String8(e->getName()).string(),
String8(e->getBag().keyAt(i)).string());
}
@@ -3627,7 +3685,7 @@
break;
}
}
- fprintf(stderr, "WARNING: Circular reference detected in key '%s' of bag '%s'\n",
+ fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
String8(e->getName()).string(),
String8(e->getBag().keyAt(i)).string());
return false;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index ec4331a..caa01b3 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -132,6 +132,9 @@
const String16& name,
const String16& comment);
+ void canAddEntry(const SourcePos& pos,
+ const String16& package, const String16& type, const String16& name);
+
size_t size() const;
size_t numLocalResources() const;
bool hasResources() const;
@@ -413,7 +416,9 @@
status_t addPublic(const SourcePos& pos,
const String16& name,
const uint32_t ident);
-
+
+ void canAddEntry(const String16& name);
+
String16 getName() const { return mName; }
sp<Entry> getEntry(const String16& entry,
const SourcePos& pos,
@@ -435,6 +440,8 @@
const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
+ const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
+
const SourcePos& getPos() const { return mPos; }
private:
String16 mName;
@@ -443,6 +450,7 @@
SortedVector<ConfigDescription> mUniqueConfigs;
DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
Vector<sp<ConfigList> > mOrderedConfigs;
+ SortedVector<String16> mCanAddEntries;
int32_t mPublicIndex;
int32_t mIndex;
SourcePos mPos;
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index 2761d18..e2a921c 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -86,7 +86,7 @@
void
ErrorPos::print(FILE* to) const
{
- const char* type = fatal ? "ERROR" : "WARNING";
+ const char* type = fatal ? "error:" : "warning:";
if (this->line >= 0) {
fprintf(to, "%s:%d: %s %s\n", this->file.string(), this->line, type, this->error.string());
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 2a85bc7..6daa0d2 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -220,7 +220,7 @@
spanStack.pop();
if (empty) {
- fprintf(stderr, "%s:%d: WARNING: empty '%s' span found in text '%s'\n",
+ fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
fileName, inXml->getLineNumber(),
String8(spanTag).string(), String8(*outString).string());
@@ -486,6 +486,7 @@
XMLNode::XMLNode(const String8& filename)
: mFilename(filename)
{
+ memset(&mCharsValue, 0, sizeof(mCharsValue));
}
XMLNode::type XMLNode::getType() const
diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
new file mode 100644
index 0000000..a0b54c2
--- /dev/null
+++ b/tools/aapt/ZipEntry.cpp
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "ZipEntry.h"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+ status_t result;
+ long posn;
+ bool hasDD;
+
+ //LOGV("initFromCDE ---\n");
+
+ /* read the CDE */
+ result = mCDE.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mCDE.read failed\n");
+ return result;
+ }
+
+ //mCDE.dump();
+
+ /* using the info in the CDE, go load up the LFH */
+ posn = ftell(fp);
+ if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+ LOGD("local header seek failed (%ld)\n",
+ mCDE.mLocalHeaderRelOffset);
+ return UNKNOWN_ERROR;
+ }
+
+ result = mLFH.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mLFH.read failed\n");
+ return result;
+ }
+
+ if (fseek(fp, posn, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ //mLFH.dump();
+
+ /*
+ * We *might* need to read the Data Descriptor at this point and
+ * integrate it into the LFH. If this bit is set, the CRC-32,
+ * compressed size, and uncompressed size will be zero. In practice
+ * these seem to be rare.
+ */
+ hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+ if (hasDD) {
+ // do something clever
+ //LOGD("+++ has data descriptor\n");
+ }
+
+ /*
+ * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
+ * flag is set, because the LFH is incomplete. (Not a problem, since we
+ * prefer the CDE values.)
+ */
+ if (!hasDD && !compareHeaders()) {
+ LOGW("warning: header mismatch\n");
+ // keep going?
+ }
+
+ /*
+ * If the mVersionToExtract is greater than 20, we may have an
+ * issue unpacking the record -- could be encrypted, compressed
+ * with something we don't support, or use Zip64 extensions. We
+ * can defer worrying about that to when we're extracting data.
+ */
+
+ return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry. Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+ assert(fileName != NULL && *fileName != '\0'); // name required
+
+ /* most fields are properly initialized by constructor */
+ mCDE.mVersionMadeBy = kDefaultMadeBy;
+ mCDE.mVersionToExtract = kDefaultVersion;
+ mCDE.mCompressionMethod = kCompressStored;
+ mCDE.mFileNameLength = strlen(fileName);
+ if (comment != NULL)
+ mCDE.mFileCommentLength = strlen(comment);
+ mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ strcpy((char*) mCDE.mFileName, fileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ /* TODO: stop assuming null-terminated ASCII here? */
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ strcpy((char*) mCDE.mFileComment, comment);
+ }
+
+ copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+ const ZipEntry* pEntry)
+{
+ /*
+ * Copy everything in the CDE over, then fix up the hairy bits.
+ */
+ memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ if (mCDE.mFileName == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ if (mCDE.mFileComment == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+ }
+ if (mCDE.mExtraFieldLength > 0) {
+ /* we null-terminate this, though it may not be a string */
+ mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+ if (mCDE.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+ mCDE.mExtraFieldLength+1);
+ }
+
+ /* construct the LFH from the CDE */
+ copyCDEtoLFH();
+
+ /*
+ * The LFH "extra" field is independent of the CDE "extra", so we
+ * handle it here.
+ */
+ assert(mLFH.mExtraField == NULL);
+ mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+ if (mLFH.mExtraFieldLength > 0) {
+ mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+ if (mLFH.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+ mLFH.mExtraFieldLength+1);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field. This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+ if (padding <= 0)
+ return INVALID_OPERATION;
+
+ //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+ // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+ if (mLFH.mExtraFieldLength > 0) {
+ /* extend existing field */
+ unsigned char* newExtra;
+
+ newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+ if (newExtra == NULL)
+ return NO_MEMORY;
+ memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+ memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+ delete[] mLFH.mExtraField;
+ mLFH.mExtraField = newExtra;
+ mLFH.mExtraFieldLength += padding;
+ } else {
+ /* create new field */
+ mLFH.mExtraField = new unsigned char[padding];
+ memset(mLFH.mExtraField, 0, padding);
+ mLFH.mExtraFieldLength = padding;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+ mLFH.mVersionToExtract = mCDE.mVersionToExtract;
+ mLFH.mGPBitFlag = mCDE.mGPBitFlag;
+ mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+ mLFH.mLastModFileTime = mCDE.mLastModFileTime;
+ mLFH.mLastModFileDate = mCDE.mLastModFileDate;
+ mLFH.mCRC32 = mCDE.mCRC32;
+ mLFH.mCompressedSize = mCDE.mCompressedSize;
+ mLFH.mUncompressedSize = mCDE.mUncompressedSize;
+ mLFH.mFileNameLength = mCDE.mFileNameLength;
+ // the "extra field" is independent
+
+ delete[] mLFH.mFileName;
+ if (mLFH.mFileNameLength > 0) {
+ mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+ strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+ } else {
+ mLFH.mFileName = NULL;
+ }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod)
+{
+ mCDE.mCompressionMethod = compressionMethod;
+ mCDE.mCRC32 = crc32;
+ mCDE.mCompressedSize = compLen;
+ mCDE.mUncompressedSize = uncompLen;
+ mCDE.mCompressionMethod = compressionMethod;
+ if (compressionMethod == kCompressDeflated) {
+ mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
+ }
+ copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up. This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+ if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+ LOGV("cmp: VersionToExtract\n");
+ return false;
+ }
+ if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+ LOGV("cmp: GPBitFlag\n");
+ return false;
+ }
+ if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+ LOGV("cmp: CompressionMethod\n");
+ return false;
+ }
+ if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+ LOGV("cmp: LastModFileTime\n");
+ return false;
+ }
+ if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+ LOGV("cmp: LastModFileDate\n");
+ return false;
+ }
+ if (mCDE.mCRC32 != mLFH.mCRC32) {
+ LOGV("cmp: CRC32\n");
+ return false;
+ }
+ if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+ LOGV("cmp: CompressedSize\n");
+ return false;
+ }
+ if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+ LOGV("cmp: UncompressedSize\n");
+ return false;
+ }
+ if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+ LOGV("cmp: FileNameLength\n");
+ return false;
+ }
+#if 0 // this seems to be used for padding, not real data
+ if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+ LOGV("cmp: ExtraFieldLength\n");
+ return false;
+ }
+#endif
+ if (mCDE.mFileName != NULL) {
+ if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+ LOGV("cmp: FileName\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+ struct tm parts;
+
+ parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+ parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+ parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+ parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+ parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+ parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+ parts.tm_wday = parts.tm_yday = 0;
+ parts.tm_isdst = -1; // DST info "not available"
+
+ return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+ struct tm tmResult;
+#endif
+ time_t even;
+ unsigned short zdate, ztime;
+
+ struct tm* ptm;
+
+ /* round up to an even number of seconds */
+ even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+ /* expand */
+#ifdef HAVE_LOCALTIME_R
+ ptm = localtime_r(&even, &tmResult);
+#else
+ ptm = localtime(&even);
+#endif
+
+ int year;
+ year = ptm->tm_year;
+ if (year < 80)
+ year = 80;
+
+ zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+ ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+ mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+ mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kLFHLen];
+
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+
+ if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+ // TODO: validate sizes
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* grab extra field */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+ unsigned char buf[kLFHLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+ ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+ if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+ LOGD(" LocalFileHeader contents:\n");
+ LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u\n",
+ mFileNameLength, mExtraFieldLength);
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry. On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kCDELen];
+
+ /* no re-use */
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+ assert(mFileComment == NULL);
+
+ if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("Whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+ mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+ mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+ mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+ mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+ mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+ // TODO: validate sizes and offsets
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* read "extra field" */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+
+ /* grab comment, if any */
+ if (mFileCommentLength != 0) {
+ mFileComment = new unsigned char[mFileCommentLength+1];
+ if (mFileComment == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileComment[mFileCommentLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+ unsigned char buf[kCDELen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+ ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x10], mCRC32);
+ ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+ ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+ ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+ ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+ ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+ ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+ if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write comment */
+ if (mFileCommentLength != 0) {
+ if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+ LOGD(" CentralDirEntry contents:\n");
+ LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
+ mFileNameLength, mExtraFieldLength, mFileCommentLength);
+ LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+ mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+ mLocalHeaderRelOffset);
+
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+ if (mFileComment != NULL)
+ LOGD(" comment: '%s'\n", mFileComment);
+}
+
diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h
new file mode 100644
index 0000000..7f721b4
--- /dev/null
+++ b/tools/aapt/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include <utils/Errors.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself. (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry). The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+ friend class ZipFile;
+
+ ZipEntry(void)
+ : mDeleted(false), mMarked(false)
+ {}
+ ~ZipEntry(void) {}
+
+ /*
+ * Returns "true" if the data is compressed.
+ */
+ bool isCompressed(void) const {
+ return mCDE.mCompressionMethod != kCompressStored;
+ }
+ int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+ /*
+ * Return the uncompressed length.
+ */
+ off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+ /*
+ * Return the compressed length. For uncompressed data, this returns
+ * the same thing as getUncompresesdLen().
+ */
+ off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+ /*
+ * Return the absolute file offset of the start of the compressed or
+ * uncompressed data.
+ */
+ off_t getFileOffset(void) const {
+ return mCDE.mLocalHeaderRelOffset +
+ LocalFileHeader::kLFHLen +
+ mLFH.mFileNameLength +
+ mLFH.mExtraFieldLength;
+ }
+
+ /*
+ * Return the data CRC.
+ */
+ unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+ /*
+ * Return file modification time in UNIX seconds-since-epoch.
+ */
+ time_t getModWhen(void) const;
+
+ /*
+ * Return the archived file name.
+ */
+ const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+ /*
+ * Application-defined "mark". Can be useful when synchronizing the
+ * contents of an archive with contents on disk.
+ */
+ bool getMarked(void) const { return mMarked; }
+ void setMarked(bool val) { mMarked = val; }
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short getShortLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long getLongLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+ static inline void putShortLE(unsigned char* buf, short val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ }
+ static inline void putLongLE(unsigned char* buf, long val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ buf[2] = (unsigned char) (val >> 16);
+ buf[3] = (unsigned char) (val >> 24);
+ }
+
+ /* defined for Zip archives */
+ enum {
+ kCompressStored = 0, // no compression
+ // shrunk = 1,
+ // reduced 1 = 2,
+ // reduced 2 = 3,
+ // reduced 3 = 4,
+ // reduced 4 = 5,
+ // imploded = 6,
+ // tokenized = 7,
+ kCompressDeflated = 8, // standard deflate
+ // Deflate64 = 9,
+ // lib imploded = 10,
+ // reserved = 11,
+ // bzip2 = 12,
+ };
+
+ /*
+ * Deletion flag. If set, the entry will be removed on the next
+ * call to "flush".
+ */
+ bool getDeleted(void) const { return mDeleted; }
+
+protected:
+ /*
+ * Initialize the structure from the file, which is pointing at
+ * our Central Directory entry.
+ */
+ status_t initFromCDE(FILE* fp);
+
+ /*
+ * Initialize the structure for a new file. We need the filename
+ * and comment so that we can properly size the LFH area. The
+ * filename is mandatory, the comment is optional.
+ */
+ void initNew(const char* fileName, const char* comment);
+
+ /*
+ * Initialize the structure with the contents of a ZipEntry from
+ * another file.
+ */
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+ /*
+ * Add some pad bytes to the LFH. We do this by adding or resizing
+ * the "extra" field.
+ */
+ status_t addPadding(int padding);
+
+ /*
+ * Set information about the data for this entry.
+ */
+ void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod);
+
+ /*
+ * Set the modification date.
+ */
+ void setModWhen(time_t when);
+
+ /*
+ * Return the offset of the local file header.
+ */
+ off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+ /*
+ * Set the offset of the local file header, relative to the start of
+ * the current file.
+ */
+ void setLFHOffset(off_t offset) {
+ mCDE.mLocalHeaderRelOffset = (long) offset;
+ }
+
+ /* mark for deletion; used by ZipFile::remove() */
+ void setDeleted(void) { mDeleted = true; }
+
+private:
+ /* these are private and not defined */
+ ZipEntry(const ZipEntry& src);
+ ZipEntry& operator=(const ZipEntry& src);
+
+ /* returns "true" if the CDE and the LFH agree */
+ bool compareHeaders(void) const;
+ void copyCDEtoLFH(void);
+
+ bool mDeleted; // set if entry is pending deletion
+ bool mMarked; // app-defined marker
+
+ /*
+ * Every entry in the Zip archive starts off with one of these.
+ */
+ class LocalFileHeader {
+ public:
+ LocalFileHeader(void) :
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileName(NULL),
+ mExtraField(NULL)
+ {}
+ virtual ~LocalFileHeader(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+
+ enum {
+ kSignature = 0x04034b50,
+ kLFHLen = 30, // LocalFileHdr len, excl. var fields
+ };
+
+ void dump(void) const;
+ };
+
+ /*
+ * Every entry in the Zip archive has one of these in the "central
+ * directory" at the end of the file.
+ */
+ class CentralDirEntry {
+ public:
+ CentralDirEntry(void) :
+ mVersionMadeBy(0),
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileCommentLength(0),
+ mDiskNumberStart(0),
+ mInternalAttrs(0),
+ mExternalAttrs(0),
+ mLocalHeaderRelOffset(0),
+ mFileName(NULL),
+ mExtraField(NULL),
+ mFileComment(NULL)
+ {}
+ virtual ~CentralDirEntry(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionMadeBy;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned short mFileCommentLength;
+ unsigned short mDiskNumberStart;
+ unsigned short mInternalAttrs;
+ unsigned long mExternalAttrs;
+ unsigned long mLocalHeaderRelOffset;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+ unsigned char* mFileComment;
+
+ void dump(void) const;
+
+ enum {
+ kSignature = 0x02014b50,
+ kCDELen = 46, // CentralDirEnt len, excl. var fields
+ };
+ };
+
+ enum {
+ //kDataDescriptorSignature = 0x08074b50, // currently unused
+ kDataDescriptorLen = 16, // four 32-bit fields
+
+ kDefaultVersion = 20, // need deflate, nothing much else
+ kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
+ kUsesDataDescr = 0x0008, // GPBitFlag bit 3
+ };
+
+ LocalFileHeader mLFH;
+ CentralDirEntry mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
new file mode 100644
index 0000000..62c9383
--- /dev/null
+++ b/tools/aapt/ZipFile.cpp
@@ -0,0 +1,1297 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include <utils/ZipUtils.h>
+#include <utils/Log.h>
+
+#include "ZipFile.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO "rb"
+#define FILE_OPEN_RW "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+ if (err == ENOENT)
+ return NAME_NOT_FOUND;
+ else if (err == EACCES)
+ return PERMISSION_DENIED;
+ else
+ return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+ bool newArchive = false;
+
+ assert(mZipFp == NULL); // no reopen
+
+ if ((flags & kOpenTruncate))
+ flags |= kOpenCreate; // trunc implies create
+
+ if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+ return INVALID_OPERATION; // not both
+ if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+ return INVALID_OPERATION; // not neither
+ if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+ return INVALID_OPERATION; // create requires write
+
+ if (flags & kOpenTruncate) {
+ newArchive = true;
+ } else {
+ newArchive = (access(zipFileName, F_OK) != 0);
+ if (!(flags & kOpenCreate) && newArchive) {
+ /* not creating, must already exist */
+ LOGD("File %s does not exist", zipFileName);
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ /* open the file */
+ const char* openflags;
+ if (flags & kOpenReadWrite) {
+ if (newArchive)
+ openflags = FILE_OPEN_RW_CREATE;
+ else
+ openflags = FILE_OPEN_RW;
+ } else {
+ openflags = FILE_OPEN_RO;
+ }
+ mZipFp = fopen(zipFileName, openflags);
+ if (mZipFp == NULL) {
+ int err = errno;
+ LOGD("fopen failed: %d\n", err);
+ return errnoToStatus(err);
+ }
+
+ status_t result;
+ if (!newArchive) {
+ /*
+ * Load the central directory. If that fails, then this probably
+ * isn't a Zip archive.
+ */
+ result = readCentralDir();
+ } else {
+ /*
+ * Newly-created. The EndOfCentralDir constructor actually
+ * sets everything to be the way we want it (all zeroes). We
+ * set mNeedCDRewrite so that we create *something* if the
+ * caller doesn't add any files. (We could also just unlink
+ * the file if it's brand new and nothing was added, but that's
+ * probably doing more than we really should -- the user might
+ * have a need for empty zip files.)
+ */
+ mNeedCDRewrite = true;
+ result = NO_ERROR;
+ }
+
+ if (flags & kOpenReadOnly)
+ mReadOnly = true;
+ else
+ assert(!mReadOnly);
+
+ return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+ if (idx < 0 || idx >= (int) mEntries.size())
+ return NULL;
+
+ return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+ /*
+ * Do a stupid linear string-compare search.
+ *
+ * There are various ways to speed this up, especially since it's rare
+ * to intermingle changes to the archive with "get by name" calls. We
+ * don't want to sort the mEntries vector itself, however, because
+ * it's used to recreate the Central Directory.
+ *
+ * (Hash table works, parallel list of pointers in sorted order is good.)
+ */
+ int idx;
+
+ for (idx = mEntries.size()-1; idx >= 0; idx--) {
+ ZipEntry* pEntry = mEntries[idx];
+ if (!pEntry->getDeleted() &&
+ strcmp(fileName, pEntry->getFileName()) == 0)
+ {
+ return pEntry;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+ int count = mEntries.size();
+
+ while (--count >= 0)
+ delete mEntries[count];
+
+ mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end. In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards. The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly. If the wrong value ends up in the EOCD
+ * area, we're hosed. This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+ status_t result = NO_ERROR;
+ unsigned char* buf = NULL;
+ off_t fileLength, seekStart;
+ long readAmount;
+ int i;
+
+ fseek(mZipFp, 0, SEEK_END);
+ fileLength = ftell(mZipFp);
+ rewind(mZipFp);
+
+ /* too small to be a ZIP archive? */
+ if (fileLength < EndOfCentralDir::kEOCDLen) {
+ LOGD("Length is %ld -- too small\n", (long)fileLength);
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+ if (buf == NULL) {
+ LOGD("Failure allocating %d bytes for EOCD search",
+ EndOfCentralDir::kMaxEOCDSearch);
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+ seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+ readAmount = EndOfCentralDir::kMaxEOCDSearch;
+ } else {
+ seekStart = 0;
+ readAmount = (long) fileLength;
+ }
+ if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+ LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* read the last part of the file into the buffer */
+ if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+ LOGD("short file? wanted %ld\n", readAmount);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* find the end-of-central-dir magic */
+ for (i = readAmount - 4; i >= 0; i--) {
+ if (buf[i] == 0x50 &&
+ ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+ {
+ LOGV("+++ Found EOCD at buf+%d\n", i);
+ break;
+ }
+ }
+ if (i < 0) {
+ LOGD("EOCD not found, not Zip\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /* extract eocd values */
+ result = mEOCD.readBuf(buf + i, readAmount - i);
+ if (result != NO_ERROR) {
+ LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+ goto bail;
+ }
+ //mEOCD.dump();
+
+ if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+ mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+ {
+ LOGD("Archive spanning not supported\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /*
+ * So far so good. "mCentralDirSize" is the size in bytes of the
+ * central directory, so we can just seek back that far to find it.
+ * We can also seek forward mCentralDirOffset bytes from the
+ * start of the file.
+ *
+ * We're not guaranteed to have the rest of the central dir in the
+ * buffer, nor are we guaranteed that the central dir will have any
+ * sort of convenient size. We need to skip to the start of it and
+ * read the header, then the other goodies.
+ *
+ * The only thing we really need right now is the file comment, which
+ * we're hoping to preserve.
+ */
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ LOGD("Failure seeking to central dir offset %ld\n",
+ mEOCD.mCentralDirOffset);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Loop through and read the central dir entries.
+ */
+ LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+ int entry;
+ for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+ ZipEntry* pEntry = new ZipEntry;
+
+ result = pEntry->initFromCDE(mZipFp);
+ if (result != NO_ERROR) {
+ LOGD("initFromCDE failed\n");
+ delete pEntry;
+ goto bail;
+ }
+
+ mEntries.add(pEntry);
+ }
+
+
+ /*
+ * If all went well, we should now be back at the EOCD.
+ */
+ {
+ unsigned char checkBuf[4];
+ if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+ LOGD("EOCD check read failed\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+ if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+ LOGD("EOCD read check failed\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ LOGV("+++ EOCD read check passed\n");
+ }
+
+bail:
+ delete[] buf;
+ return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position. The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written. Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result = NO_ERROR;
+ long lfhPosn, startPosn, endPosn, uncompressedLen;
+ FILE* inputFp = NULL;
+ unsigned long crc;
+ time_t modWhen;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ assert(compressionMethod == ZipEntry::kCompressDeflated ||
+ compressionMethod == ZipEntry::kCompressStored);
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ /* make sure it doesn't already exist */
+ if (getEntryByName(storageName) != NULL)
+ return ALREADY_EXISTS;
+
+ if (!data) {
+ inputFp = fopen(fileName, FILE_OPEN_RO);
+ if (inputFp == NULL)
+ return errnoToStatus(errno);
+ }
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ pEntry->initNew(storageName, NULL);
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH, even though it's still mostly blank. We need it
+ * as a place-holder. In theory the LFH isn't necessary, but in
+ * practice some utilities demand it.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+ startPosn = ftell(mZipFp);
+
+ /*
+ * Copy the data in, possibly compressing it as we go.
+ */
+ if (sourceType == ZipEntry::kCompressStored) {
+ if (compressionMethod == ZipEntry::kCompressDeflated) {
+ bool failed = false;
+ result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+ if (result != NO_ERROR) {
+ LOGD("compression failed, storing\n");
+ failed = true;
+ } else {
+ /*
+ * Make sure it has compressed "enough". This probably ought
+ * to be set through an API call, but I don't expect our
+ * criteria to change over time.
+ */
+ long src = inputFp ? ftell(inputFp) : size;
+ long dst = ftell(mZipFp) - startPosn;
+ if (dst + (dst / 10) > src) {
+ LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+ src, dst);
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ compressionMethod = ZipEntry::kCompressStored;
+ if (inputFp) rewind(inputFp);
+ fseek(mZipFp, startPosn, SEEK_SET);
+ /* fall through to kCompressStored case */
+ }
+ }
+ /* handle "no compression" request, or failed compression from above */
+ if (compressionMethod == ZipEntry::kCompressStored) {
+ if (inputFp) {
+ result = copyFpToFp(mZipFp, inputFp, &crc);
+ } else {
+ result = copyDataToFp(mZipFp, data, size, &crc);
+ }
+ if (result != NO_ERROR) {
+ // don't need to truncate; happens in CDE rewrite
+ LOGD("failed copying data in\n");
+ goto bail;
+ }
+ }
+
+ // currently seeked to end of file
+ uncompressedLen = inputFp ? ftell(inputFp) : size;
+ } else if (sourceType == ZipEntry::kCompressDeflated) {
+ /* we should support uncompressed-from-compressed, but it's not
+ * important right now */
+ assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+ bool scanResult;
+ int method;
+ long compressedLen;
+
+ scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+ &compressedLen, &crc);
+ if (!scanResult || method != ZipEntry::kCompressDeflated) {
+ LOGD("this isn't a deflated gzip file?");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+ if (result != NO_ERROR) {
+ LOGD("failed copying gzip data in\n");
+ goto bail;
+ }
+ } else {
+ assert(false);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * We could write the "Data Descriptor", but there doesn't seem to
+ * be any point since we're going to go back and write the LFH.
+ *
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp); // seeked to end of compressed data
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+ compressionMethod);
+ modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+ pEntry->setModWhen(modWhen);
+ pEntry->setLFHOffset(lfhPosn);
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Go back and write the LFH.
+ */
+ if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+bail:
+ if (inputFp != NULL)
+ fclose(inputFp);
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result;
+ long lfhPosn, endPosn;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ if (pEntry == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+ if (result != NO_ERROR)
+ goto bail;
+ if (padding != 0) {
+ result = pEntry->addPadding(padding);
+ if (result != NO_ERROR)
+ goto bail;
+ }
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH. Since we're not recompressing the data, we already
+ * have all of the fields filled out.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Copy the data over.
+ *
+ * If the "has data descriptor" flag is set, we want to copy the DD
+ * fields as well. This is a fixed-size area immediately following
+ * the data.
+ */
+ if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ off_t copyLen;
+ copyLen = pSourceEntry->getCompressedLen();
+ if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+ copyLen += ZipEntry::kDataDescriptorLen;
+
+ if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+ != NO_ERROR)
+ {
+ LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp);
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+ result = NO_ERROR;
+
+bail:
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (1) {
+ count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+ if (ferror(srcFp) || ferror(dstFp))
+ return errnoToStatus(errno);
+ if (count == 0)
+ break;
+
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+ if (size > 0) {
+ *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+ if (fwrite(data, 1, size, dstFp) != size) {
+ LOGD("fwrite %d bytes failed\n", (int) size);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (length) {
+ long readSize;
+
+ readSize = sizeof(tmpBuf);
+ if (readSize > length)
+ readSize = length;
+
+ count = fread(tmpBuf, 1, readSize, srcFp);
+ if ((long) count != readSize) { // error or unexpected EOF
+ LOGD("fread %d bytes failed\n", (int) readSize);
+ return UNKNOWN_ERROR;
+ }
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+
+ length -= readSize;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ status_t result = NO_ERROR;
+ const size_t kBufSize = 32768;
+ unsigned char* inBuf = NULL;
+ unsigned char* outBuf = NULL;
+ z_stream zstream;
+ bool atEof = false; // no feof() aviailable yet
+ unsigned long crc;
+ int zerr;
+
+ /*
+ * Create an input buffer and an output buffer.
+ */
+ inBuf = new unsigned char[kBufSize];
+ outBuf = new unsigned char[kBufSize];
+ if (inBuf == NULL || outBuf == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ zstream.data_type = Z_UNKNOWN;
+
+ zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zerr != Z_OK) {
+ result = UNKNOWN_ERROR;
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ crc = crc32(0L, Z_NULL, 0);
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ size_t getSize;
+ int flush;
+
+ /* only read if the input buffer is empty */
+ if (zstream.avail_in == 0 && !atEof) {
+ LOGV("+++ reading %d bytes\n", (int)kBufSize);
+ if (data) {
+ getSize = size > kBufSize ? kBufSize : size;
+ memcpy(inBuf, data, getSize);
+ data = ((const char*)data) + getSize;
+ size -= getSize;
+ } else {
+ getSize = fread(inBuf, 1, kBufSize, srcFp);
+ if (ferror(srcFp)) {
+ LOGD("deflate read failed (errno=%d)\n", errno);
+ goto z_bail;
+ }
+ }
+ if (getSize < kBufSize) {
+ LOGV("+++ got %d bytes, EOF reached\n",
+ (int)getSize);
+ atEof = true;
+ }
+
+ crc = crc32(crc, inBuf, getSize);
+
+ zstream.next_in = inBuf;
+ zstream.avail_in = getSize;
+ }
+
+ if (atEof)
+ flush = Z_FINISH; /* tell zlib that we're done */
+ else
+ flush = Z_NO_FLUSH; /* more to come! */
+
+ zerr = deflate(&zstream, flush);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+ result = UNKNOWN_ERROR;
+ goto z_bail;
+ }
+
+ /* write when we're full or when we're done */
+ if (zstream.avail_out == 0 ||
+ (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+ {
+ LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+ if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+ (size_t)(zstream.next_out - outBuf))
+ {
+ LOGD("write %d failed in deflate\n",
+ (int) (zstream.next_out - outBuf));
+ goto z_bail;
+ }
+
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ }
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ *pCRC32 = crc;
+
+z_bail:
+ deflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] inBuf;
+ delete[] outBuf;
+
+ return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+ /*
+ * Should verify that pEntry is actually part of this archive, and
+ * not some stray ZipEntry from a different file.
+ */
+
+ /* mark entry as deleted, and mark archive as dirty */
+ pEntry->setDeleted();
+ mNeedCDRewrite = true;
+ return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+ status_t result = NO_ERROR;
+ long eocdPosn;
+ int i, count;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+ if (!mNeedCDRewrite)
+ return NO_ERROR;
+
+ assert(mZipFp != NULL);
+
+ result = crunchArchive();
+ if (result != NO_ERROR)
+ return result;
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ count = mEntries.size();
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ pEntry->mCDE.write(mZipFp);
+ }
+
+ eocdPosn = ftell(mZipFp);
+ mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+ mEOCD.write(mZipFp);
+
+ /*
+ * If we had some stuff bloat up during compression and get replaced
+ * with plain files, or if we deleted some entries, there's a lot
+ * of wasted space at the end of the file. Remove it now.
+ */
+ if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+ LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+ // not fatal
+ }
+
+ /* should we clear the "newly added" flag in all entries now? */
+
+ mNeedCDRewrite = false;
+ return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+ status_t result = NO_ERROR;
+ int i, count;
+ long delCount, adjust;
+
+#if 0
+ printf("CONTENTS:\n");
+ for (i = 0; i < (int) mEntries.size(); i++) {
+ printf(" %d: lfhOff=%ld del=%d\n",
+ i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+ }
+ printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+ /*
+ * Roll through the set of files, shifting them as appropriate. We
+ * could probably get a slight performance improvement by sliding
+ * multiple files down at once (because we could use larger reads
+ * when operating on batches of small files), but it's not that useful.
+ */
+ count = mEntries.size();
+ delCount = adjust = 0;
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ long span;
+
+ if (pEntry->getLFHOffset() != 0) {
+ long nextOffset;
+
+ /* Get the length of this entry by finding the offset
+ * of the next entry. Directory entries don't have
+ * file offsets, so we need to find the next non-directory
+ * entry.
+ */
+ nextOffset = 0;
+ for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+ nextOffset = mEntries[ii]->getLFHOffset();
+ if (nextOffset == 0)
+ nextOffset = mEOCD.mCentralDirOffset;
+ span = nextOffset - pEntry->getLFHOffset();
+
+ assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+ } else {
+ /* This is a directory entry. It doesn't have
+ * any actual file contents, so there's no need to
+ * move anything.
+ */
+ span = 0;
+ }
+
+ //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+ // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+ if (pEntry->getDeleted()) {
+ adjust += span;
+ delCount++;
+
+ delete pEntry;
+ mEntries.removeAt(i);
+
+ /* adjust loop control */
+ count--;
+ i--;
+ } else if (span != 0 && adjust > 0) {
+ /* shuffle this entry back */
+ //printf("+++ Shuffling '%s' back %ld\n",
+ // pEntry->getFileName(), adjust);
+ result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+ pEntry->getLFHOffset(), span);
+ if (result != NO_ERROR) {
+ /* this is why you use a temp file */
+ LOGE("error during crunch - archive is toast\n");
+ return result;
+ }
+
+ pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+ }
+ }
+
+ /*
+ * Fix EOCD info. We have to wait until the end to do some of this
+ * because we use mCentralDirOffset to determine "span" for the
+ * last entry.
+ */
+ mEOCD.mCentralDirOffset -= adjust;
+ mEOCD.mNumEntries -= delCount;
+ mEOCD.mTotalNumEntries -= delCount;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+
+ assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+ assert(mEOCD.mNumEntries == count);
+
+ return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+ if (dst == src || n <= 0)
+ return NO_ERROR;
+
+ unsigned char readBuf[32768];
+
+ if (dst < src) {
+ /* shift stuff toward start of file; must read from start */
+ while (n != 0) {
+ size_t getSize = sizeof(readBuf);
+ if (getSize > n)
+ getSize = n;
+
+ if (fseek(fp, (long) src, SEEK_SET) != 0) {
+ LOGD("filemove src seek %ld failed\n", (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fread(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove read %ld off=%ld failed\n",
+ (long) getSize, (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+ LOGD("filemove dst seek %ld failed\n", (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove write %ld off=%ld failed\n",
+ (long) getSize, (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ src += getSize;
+ dst += getSize;
+ n -= getSize;
+ }
+ } else {
+ /* shift stuff toward end of file; must read from end */
+ assert(false); // write this someday, maybe
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ LOGD("HEY: fstat on fd %d failed\n", fd);
+ return (time_t) -1;
+ }
+
+ return sb.st_mtime;
+}
+
+
+#if 0 /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush(). The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+ if (!mReadOnly)
+ return INVALID_OPERATION;
+ assert(mZipFp != NULL);
+
+ int fd;
+ fd = dup(fileno(mZipFp));
+ if (fd < 0) {
+ LOGD("didn't work, errno=%d\n", errno);
+ }
+
+ return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+ return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+ size_t unlen = entry->getUncompressedLen();
+ size_t clen = entry->getCompressedLen();
+
+ void* buf = malloc(unlen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ fseek(mZipFp, 0, SEEK_SET);
+
+ off_t offset = entry->getFileOffset();
+ if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+ goto bail;
+ }
+
+ switch (entry->getCompressionMethod())
+ {
+ case ZipEntry::kCompressStored: {
+ ssize_t amt = fread(buf, 1, unlen, mZipFp);
+ if (amt != (ssize_t)unlen) {
+ goto bail;
+ }
+#if 0
+ printf("data...\n");
+ const unsigned char* p = (unsigned char*)buf;
+ const unsigned char* end = p+unlen;
+ for (int i=0; i<32 && p < end; i++) {
+ printf("0x%08x ", (int)(offset+(i*0x10)));
+ for (int j=0; j<0x10 && p < end; j++) {
+ printf(" %02x", *p);
+ p++;
+ }
+ printf("\n");
+ }
+#endif
+
+ }
+ break;
+ case ZipEntry::kCompressDeflated: {
+ if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+ goto bail;
+ }
+ }
+ break;
+ default:
+ goto bail;
+ }
+ return buf;
+
+bail:
+ free(buf);
+ return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+ /* don't allow re-use */
+ assert(mComment == NULL);
+
+ if (len < kEOCDLen) {
+ /* looks like ZIP file got truncated */
+ LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+ kEOCDLen, len);
+ return INVALID_OPERATION;
+ }
+
+ /* this should probably be an assert() */
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+ return UNKNOWN_ERROR;
+
+ mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+ mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+ mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+ mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+ mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+ mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+ mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+ // TODO: validate mCentralDirOffset
+
+ if (mCommentLen > 0) {
+ if (kEOCDLen + mCommentLen > len) {
+ LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+ kEOCDLen, mCommentLen, len);
+ return UNKNOWN_ERROR;
+ }
+ mComment = new unsigned char[mCommentLen];
+ memcpy(mComment, buf + kEOCDLen, mCommentLen);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+ unsigned char buf[kEOCDLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+ ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+ ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+ ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+ ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+ ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+ ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+ if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+ return UNKNOWN_ERROR;
+ if (mCommentLen > 0) {
+ assert(mComment != NULL);
+ if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+ LOGD(" EndOfCentralDir contents:\n");
+ LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+ mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+ LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+ mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/tools/aapt/ZipFile.h b/tools/aapt/ZipFile.h
new file mode 100644
index 0000000..dbbd072
--- /dev/null
+++ b/tools/aapt/ZipFile.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// General-purpose Zip archive access. This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+#include <stdio.h>
+
+#include "ZipEntry.h"
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes. Because we're only interested
+ * in using this for packaging, we don't worry about such things. Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+ ZipFile(void)
+ : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+ {}
+ ~ZipFile(void) {
+ if (!mReadOnly)
+ flush();
+ if (mZipFp != NULL)
+ fclose(mZipFp);
+ discardEntries();
+ }
+
+ /*
+ * Open a new or existing archive.
+ */
+ typedef enum {
+ kOpenReadOnly = 0x01,
+ kOpenReadWrite = 0x02,
+ kOpenCreate = 0x04, // create if it doesn't exist
+ kOpenTruncate = 0x08, // if it exists, empty it
+ };
+ status_t open(const char* zipFileName, int flags);
+
+ /*
+ * Add a file to the end of the archive. Specify whether you want the
+ * library to try to store it compressed.
+ *
+ * If "storageName" is specified, the archive will use that instead
+ * of "fileName".
+ *
+ * If there is already an entry with the same name, the call fails.
+ * Existing entries with the same name must be removed first.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const char* fileName, int compressionMethod,
+ ZipEntry** ppEntry)
+ {
+ return add(fileName, fileName, compressionMethod, ppEntry);
+ }
+ status_t add(const char* fileName, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add a file that is already compressed with gzip.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t addGzip(const char* fileName, const char* storageName,
+ ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressDeflated,
+ ZipEntry::kCompressDeflated, ppEntry);
+ }
+
+ /*
+ * Add a file from an in-memory data buffer.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const void* data, size_t size, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(NULL, data, size, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry);
+
+ /*
+ * Mark an entry as having been removed. It is not actually deleted
+ * from the archive or our internal data structures until flush() is
+ * called.
+ */
+ status_t remove(ZipEntry* pEntry);
+
+ /*
+ * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
+ */
+ status_t flush(void);
+
+ /*
+ * Expand the data into the buffer provided. The buffer must hold
+ * at least <uncompressed len> bytes. Variation expands directly
+ * to a file.
+ *
+ * Returns "false" if an error was encountered in the compressed data.
+ */
+ //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+ //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+ void* uncompress(const ZipEntry* pEntry);
+
+ /*
+ * Get an entry, by name. Returns NULL if not found.
+ *
+ * Does not return entries pending deletion.
+ */
+ ZipEntry* getEntryByName(const char* fileName) const;
+
+ /*
+ * Get the Nth entry in the archive.
+ *
+ * This will return an entry that is pending deletion.
+ */
+ int getNumEntries(void) const { return mEntries.size(); }
+ ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+ /* these are private and not defined */
+ ZipFile(const ZipFile& src);
+ ZipFile& operator=(const ZipFile& src);
+
+ class EndOfCentralDir {
+ public:
+ EndOfCentralDir(void) :
+ mDiskNumber(0),
+ mDiskWithCentralDir(0),
+ mNumEntries(0),
+ mTotalNumEntries(0),
+ mCentralDirSize(0),
+ mCentralDirOffset(0),
+ mCommentLen(0),
+ mComment(NULL)
+ {}
+ virtual ~EndOfCentralDir(void) {
+ delete[] mComment;
+ }
+
+ status_t readBuf(const unsigned char* buf, int len);
+ status_t write(FILE* fp);
+
+ //unsigned long mSignature;
+ unsigned short mDiskNumber;
+ unsigned short mDiskWithCentralDir;
+ unsigned short mNumEntries;
+ unsigned short mTotalNumEntries;
+ unsigned long mCentralDirSize;
+ unsigned long mCentralDirOffset; // offset from first disk
+ unsigned short mCommentLen;
+ unsigned char* mComment;
+
+ enum {
+ kSignature = 0x06054b50,
+ kEOCDLen = 22, // EndOfCentralDir len, excl. comment
+
+ kMaxCommentLen = 65535, // longest possible in ushort
+ kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+ };
+
+ void dump(void) const;
+ };
+
+
+ /* read all entries in the central dir */
+ status_t readCentralDir(void);
+
+ /* crunch deleted entries out */
+ status_t crunchArchive(void);
+
+ /* clean up mEntries */
+ void discardEntries(void);
+
+ /* common handler for all "add" functions */
+ status_t addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry);
+
+ /* copy all of "srcFp" into "dstFp" */
+ status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+ /* copy all of "data" into "dstFp" */
+ status_t copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+ /* copy some of "srcFp" into "dstFp" */
+ status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32);
+ /* like memmove(), but on parts of a single file */
+ status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+ /* compress all of "srcFp" into "dstFp", using Deflate */
+ status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+
+ /* get modification date from a file descriptor */
+ time_t getModTime(int fd);
+
+ /*
+ * We use stdio FILE*, which gives us buffering but makes dealing
+ * with files >2GB awkward. Until we support Zip64, we're fine.
+ */
+ FILE* mZipFp; // Zip file pointer
+
+ /* one of these per file */
+ EndOfCentralDir mEOCD;
+
+ /* did we open this read-only? */
+ bool mReadOnly;
+
+ /* set this when we trash the central dir */
+ bool mNeedCDRewrite;
+
+ /*
+ * One ZipEntry per entry in the zip file. I'm using pointers instead
+ * of objects because it's easier than making operator= work for the
+ * classes and sub-classes.
+ */
+ Vector<ZipEntry*> mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 85ca5da..752ef7c 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -845,23 +845,6 @@
fprintf(to, "package %s;\n", this->package.c_str());
}
- // gather the types for the import statements
- set<Type*> types;
- N = this->classes.size();
- for (i=0; i<N; i++) {
- Class* c = this->classes[i];
- c->GatherTypes(&types);
- }
-
- set<Type*>::iterator it;
- for (it=types.begin(); it!=types.end(); it++) {
- Type* t = *it;
- string pkg = t->Package();
- if (pkg.length() != 0 && pkg != this->package) {
- fprintf(to, "import %s;\n", t->ImportType().c_str());
- }
- }
-
N = this->classes.size();
for (i=0; i<N; i++) {
Class* c = this->classes[i];
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 622b691..0f18132 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,6 +1,7 @@
#include "generate_java.h"
#include "AST.h"
#include "Type.h"
+#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -133,7 +134,7 @@
Method* m = new Method;
m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->Name();
+ m->comment += interfaceType->QualifiedName();
m->comment += " interface,\n";
m->comment += " * generating a proxy if needed.\n */";
m->modifiers = PUBLIC | STATIC;
@@ -323,7 +324,7 @@
transactCodeName += method->name.data;
char transactCodeValue[50];
- sprintf(transactCodeValue, "(IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+ sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
Field* transactCode = new Field(STATIC | FINAL,
new Variable(INT_TYPE, transactCodeName));
@@ -517,7 +518,7 @@
new LiteralExpression("Stub." + transactCodeName),
_data, _reply ? _reply : NULL_VALUE,
new LiteralExpression(
- oneway ? "IBinder.FLAG_ONEWAY" : "0"));
+ oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
tryStatement->statements->Add(call);
// throw back exceptions.
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index e9bf0f7..d88d988 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,6 +1,7 @@
#ifndef DEVICE_TOOLS_AIDL_H
#define DEVICE_TOOLS_AIDL_H
+#include <string.h>
#include <string>
#include <vector>
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 42e4dfa..3b66188 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -240,13 +240,6 @@
return null;
}
- public static synchronized PluginList getPluginList() {
- return null;
- }
-
- public void refreshPlugins(boolean reloadOpenPages) {
- }
-
public View getZoomControls() {
return null;
}
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 fd77d51..e941b7f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -990,6 +990,10 @@
// pass for now.
}
+ public void setWallpaperPosition(IBinder window, float x, float y) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
@@ -1017,12 +1021,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.
}
@@ -1043,6 +1047,11 @@
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void dispatchWallpaperOffsets(float x, float y) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 1c644ed..ae11231 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -6,7 +6,10 @@
#include <sstream>
#include <sys/types.h>
#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/wait.h>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 2533f0a..184bfe0a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -3,6 +3,7 @@
#include <stdarg.h>
#include <cstdio>
#include <set>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/XMLHandler.h b/tools/localize/XMLHandler.h
index 1130710..324385f 100644
--- a/tools/localize/XMLHandler.h
+++ b/tools/localize/XMLHandler.h
@@ -3,6 +3,7 @@
#include "SourcePos.h"
+#include <algorithm>
#include <string>
#include <vector>
#include <map>
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index 293e50e..775ce2f 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -8,6 +8,9 @@
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <cstdio>
#include "log.h"
using namespace android;
diff --git a/tools/localize/file_utils.h b/tools/localize/file_utils.h
index 3b3fa21..7706587 100644
--- a/tools/localize/file_utils.h
+++ b/tools/localize/file_utils.h
@@ -4,6 +4,7 @@
#include "ValuesFile.h"
#include "Configuration.h"
#include <string>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/localize.cpp b/tools/localize/localize.cpp
index c0d84cc..68c03b6 100644
--- a/tools/localize/localize.cpp
+++ b/tools/localize/localize.cpp
@@ -15,6 +15,7 @@
#include <sstream>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
using namespace std;
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 678cad8..1d0ac9a 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
#include "XLIFFFile.h"
#include "ValuesFile.h"
#include "localize.h"
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index e4ab562..6fe2629 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
#include "merge_res_and_xliff.h"
#include <stdio.h>
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index fa328e8..73dbb6f 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -58,7 +58,7 @@
int getNumAllowedChannels();
- boolean setNumAllowedChannels(int numChannels);
+ boolean setNumAllowedChannels(int numChannels, boolean persist);
int[] getValidChannelCounts();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 74f4284..d8a03a9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -565,14 +565,15 @@
* for some reason.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
+ * @param persist {@code true} if you want this remembered
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is out of range.
*
* @hide pending API council
*/
- public boolean setNumAllowedChannels(int numChannels) {
+ public boolean setNumAllowedChannels(int numChannels, boolean persist) {
try {
- return mService.setNumAllowedChannels(numChannels);
+ return mService.setNumAllowedChannels(numChannels, persist);
} catch (RemoteException e) {
return false;
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 0799f5f..c3c519f 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -79,6 +79,8 @@
public native static int getRssiCommand();
+ public native static int getRssiApproxCommand();
+
public native static int getLinkSpeedCommand();
public native static String getMacAddressCommand();
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 3aa31bf..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;
/**
@@ -183,6 +185,10 @@
private boolean mUseStaticIp = false;
private int mReconnectCount;
+ // used to store the (non-persisted) num determined during device boot
+ // (from mcc or other phone info) before the driver is started.
+ private int mNumAllowedChannels = 0;
+
// Variables relating to the 'available networks' notification
/**
@@ -238,7 +244,6 @@
private SettingsObserver mSettingsObserver;
private boolean mIsScanModeActive;
- private boolean mIsScanModeSetDueToAHiddenNetwork;
private boolean mEnableRssiPolling;
// Wi-Fi run states:
@@ -311,7 +316,6 @@
mScanResults = new ArrayList<ScanResult>();
// Allocate DHCP info object once, and fill it in on each request
mDhcpInfo = new DhcpInfo();
- mIsScanModeSetDueToAHiddenNetwork = false;
mRunState = RUN_STATE_STARTING;
// Setting is in seconds
@@ -379,6 +383,14 @@
}
/**
+ * Return the name of our WLAN network interface.
+ * @return the name of our interface.
+ */
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ /**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
@@ -576,9 +588,12 @@
try {
return setNumAllowedChannels(
Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
} catch (Settings.SettingNotFoundException e) {
- // if setting doesn't exist, stick with the driver default
+ if (mNumAllowedChannels != 0) {
+ WifiNative.setNumAllowedChannelsCommand(mNumAllowedChannels);
+ }
+ // otherwise, use the driver default
}
return true;
}
@@ -592,6 +607,7 @@
* {@code numChannels} is outside the valid range.
*/
public synchronized boolean setNumAllowedChannels(int numChannels) {
+ mNumAllowedChannels = numChannels;
return WifiNative.setNumAllowedChannelsCommand(numChannels);
}
@@ -631,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;
}
@@ -790,7 +806,7 @@
WifiNative.closeSupplicantConnection();
}
if (died) {
- resetInterface();
+ resetInterface(false);
}
// When supplicant dies, kill the DHCP thread
if (mDhcpTarget != null) {
@@ -1023,17 +1039,12 @@
* On receiving the first scan results after connecting to
* the supplicant, switch scan mode over to passive.
*/
- if (!mIsScanModeSetDueToAHiddenNetwork) {
- // This is the only place at the moment where we set
- // the scan mode NOT due to a hidden network. This is
- // what the second parameter value (false) stands for.
- setScanMode(false, false);
- }
+ setScanMode(false);
break;
case EVENT_POLL_INTERVAL:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
- requestPolledInfo(mWifiInfo);
+ requestPolledInfo(mWifiInfo, true);
checkPollTimer();
}
break;
@@ -1164,9 +1175,7 @@
return disabledNetwork;
}
- public synchronized void setScanMode(
- boolean isScanModeActive, boolean setDueToAHiddenNetwork) {
- mIsScanModeSetDueToAHiddenNetwork = setDueToAHiddenNetwork;
+ public synchronized void setScanMode(boolean isScanModeActive) {
if (mIsScanModeActive != isScanModeActive) {
WifiNative.setScanModeCommand(mIsScanModeActive = isScanModeActive);
}
@@ -1206,7 +1215,7 @@
cancelDisconnect();
}
mDisconnectExpected = false;
- resetInterface();
+ resetInterface(true);
setDetailedState(newState);
sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);
@@ -1219,7 +1228,7 @@
* Resets the Wi-Fi interface by clearing any state, resetting any sockets
* using the interface, stopping DHCP, and disabling the interface.
*/
- public void resetInterface() {
+ public void resetInterface(boolean reenable) {
mHaveIpAddress = false;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(0);
@@ -1240,6 +1249,9 @@
}
NetworkUtils.disableInterface(mInterfaceName);
+ if (reenable) {
+ NetworkUtils.enableInterface(mInterfaceName);
+ }
}
/**
@@ -1278,7 +1290,7 @@
*/
public WifiInfo requestConnectionInfo() {
requestConnectionStatus(mWifiInfo);
- requestPolledInfo(mWifiInfo);
+ requestPolledInfo(mWifiInfo, false);
return mWifiInfo;
}
@@ -1333,10 +1345,14 @@
* Get the dynamic information that is not reported via events.
* @param info the object into which the information should be captured.
*/
- private synchronized void requestPolledInfo(WifiInfo info)
+ private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
{
int newRssi = WifiNative.getRssiCommand();
- if (newRssi != -1 && -200 < newRssi && newRssi < 100) { // screen out invalid values
+ if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
+ /* some implementations avoid negative values by adding 256
+ * so we need to adjust for that here.
+ */
+ if (newRssi > 0) newRssi -= 256;
info.setRssi(newRssi);
/*
* Rather then sending the raw RSSI out every time it
@@ -1453,6 +1469,7 @@
public synchronized boolean restart() {
if (mRunState == RUN_STATE_STOPPED) {
mRunState = RUN_STATE_STARTING;
+ resetInterface(true);
return WifiNative.startDriverCommand();
} else if (mRunState == RUN_STATE_STOPPING) {
mRunState = RUN_STATE_STARTING;
@@ -1879,7 +1896,7 @@
oDns2 != mDhcpInfo.dns2));
if (changed) {
- resetInterface();
+ resetInterface(true);
configureInterface();
if (mUseStaticIp) {
mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);