summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2009-06-19 17:41:14 -0700
committerMathias Agopian <mathias@google.com>2009-06-19 17:41:14 -0700
commitf73bbd042367b65780316d2335784686dedd0459 (patch)
tree913a9ea96c37d617789914ec83f81ed0611d4d68
parent6edf5af578c1ab1fcd44b7c08ca371456e4b7430 (diff)
parentaba6af9277b34c739b83d3d2d908724c3f7ec1b4 (diff)
downloadframeworks_base-f73bbd042367b65780316d2335784686dedd0459.zip
frameworks_base-f73bbd042367b65780316d2335784686dedd0459.tar.gz
frameworks_base-f73bbd042367b65780316d2335784686dedd0459.tar.bz2
Merge commit 'goog/master' into merge_master
-rw-r--r--Android.mk7
-rw-r--r--api/current.xml480
-rw-r--r--cmds/backup/backup.cpp29
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java75
-rw-r--r--cmds/keystore/commands.c170
-rw-r--r--cmds/keystore/keystore.c100
-rw-r--r--cmds/keystore/keystore.h37
-rw-r--r--core/java/android/app/Activity.java25
-rw-r--r--core/java/android/app/ActivityManagerNative.java3
-rw-r--r--core/java/android/app/ActivityThread.java30
-rw-r--r--core/java/android/app/ApplicationContext.java35
-rw-r--r--core/java/android/app/ApplicationErrorReport.java8
-rw-r--r--core/java/android/app/ApplicationThreadNative.java1
-rw-r--r--core/java/android/app/BackupAgent.java26
-rw-r--r--core/java/android/app/FullBackupAgent.java3
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/IApplicationThread.java1
-rwxr-xr-xcore/java/android/app/IIntentReceiver.aidl33
-rw-r--r--core/java/android/app/IIntentSender.aidl27
-rw-r--r--core/java/android/app/Instrumentation.java10
-rw-r--r--core/java/android/app/PendingIntent.java20
-rw-r--r--core/java/android/app/SearchDialog.java95
-rw-r--r--core/java/android/app/SearchManager.java22
-rw-r--r--core/java/android/backup/BackupDataInput.java20
-rw-r--r--core/java/android/backup/BackupDataInputStream.java63
-rw-r--r--core/java/android/backup/BackupDataOutput.java5
-rw-r--r--core/java/android/backup/FileRestoreHelper.java41
-rw-r--r--core/java/android/backup/RestoreHelper.java13
-rw-r--r--core/java/android/backup/RestoreHelperBase.java82
-rw-r--r--core/java/android/backup/RestoreHelperDispatcher.java78
-rw-r--r--core/java/android/backup/RestoreSet.java4
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java25
-rw-r--r--core/java/android/bluetooth/BluetoothInputStream.java2
-rw-r--r--core/java/android/bluetooth/HeadsetBase.java16
-rw-r--r--core/java/android/bluetooth/IBluetoothHeadset.aidl1
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java176
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--core/java/android/content/ContextWrapper.java6
-rwxr-xr-xcore/java/android/content/IIntentReceiver.aidl33
-rw-r--r--core/java/android/content/IIntentSender.aidl (renamed from core/java/android/backup/RestoreHelperDistributor.java)16
-rw-r--r--core/java/android/content/ISyncAdapter.aidl7
-rw-r--r--core/java/android/content/Intent.java397
-rw-r--r--core/java/android/content/IntentSender.aidl19
-rw-r--r--core/java/android/content/IntentSender.java255
-rw-r--r--core/java/android/content/SyncAdapter.java4
-rw-r--r--core/java/android/content/SyncAdapterNew.java135
-rw-r--r--core/java/android/content/SyncManager.java15
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java19
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl16
-rw-r--r--core/java/android/content/pm/PackageManager.java32
-rw-r--r--core/java/android/content/pm/PackageParser.java50
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java3
-rw-r--r--core/java/android/content/res/Resources.java31
-rwxr-xr-xcore/java/android/gesture/GestureOverlayView.java36
-rw-r--r--core/java/android/os/MemoryFile.java17
-rw-r--r--core/java/android/preference/PreferenceScreen.java12
-rw-r--r--core/java/android/provider/Browser.java10
-rw-r--r--core/java/android/provider/Contacts.java162
-rw-r--r--core/java/android/provider/ContactsContract.java391
-rw-r--r--core/java/android/provider/Settings.java55
-rw-r--r--core/java/android/server/BluetoothDeviceService.java2
-rwxr-xr-xcore/java/android/speech/tts/ITts.aidl2
-rwxr-xr-xcore/java/android/speech/tts/TextToSpeech.java94
-rw-r--r--core/java/android/test/InstrumentationTestCase.java24
-rw-r--r--core/java/android/text/format/DateUtils.java6
-rw-r--r--core/java/android/util/DisplayMetrics.java12
-rw-r--r--core/java/android/util/LongSparseArray.java342
-rw-r--r--core/java/android/view/View.java6
-rw-r--r--core/java/android/webkit/ByteArrayBuilder.java15
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java15
-rw-r--r--core/java/android/webkit/LoadListener.java36
-rw-r--r--core/java/android/webkit/WebStorage.java31
-rw-r--r--core/java/android/webkit/WebView.java89
-rw-r--r--core/java/android/webkit/WebViewCore.java41
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java77
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/com/android/internal/backup/GoogleTransport.java50
-rw-r--r--core/java/com/android/internal/backup/IBackupTransport.aidl9
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java61
-rw-r--r--core/jni/Android.mk7
-rw-r--r--core/jni/AndroidRuntime.cpp73
-rw-r--r--core/jni/android/graphics/Paint.cpp2
-rw-r--r--core/jni/android_backup_BackupDataInput.cpp47
-rw-r--r--core/jni/android_backup_RestoreHelperBase.cpp94
-rwxr-xr-x[-rw-r--r--]core/jni/android_location_GpsLocationProvider.cpp8
-rw-r--r--core/jni/android_os_MemoryFile.cpp12
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp1
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp1
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp33
-rw-r--r--core/res/res/drawable/call_contact.pngbin0 -> 1025 bytes
-rw-r--r--core/res/res/drawable/create_contact.pngbin0 -> 1132 bytes
-rw-r--r--core/res/res/drawable/search_dropdown_background_apps.9.pngbin412 -> 3058 bytes
-rw-r--r--core/res/res/layout/recent_apps_dialog.xml112
-rw-r--r--core/res/res/layout/recent_apps_icon.xml39
-rw-r--r--core/res/res/values-ar-rEG/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-bg-rBG/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ca-rES/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-cs-rCZ/donottranslate-cldr.xml31
-rw-r--r--core/res/res/values-cs/donottranslate-cldr.xml31
-rw-r--r--core/res/res/values-da-rDK/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-de-rAT/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-de-rCH/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-de-rDE/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-de-rLI/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-de/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-el-rGR/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rAU/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rCA/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rGB/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rIE/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rIN/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rNZ/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rSG/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rUS/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-en-rZA/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-es-rES/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-es-rUS/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-es/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fi-rFI/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fr-rBE/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fr-rCA/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fr-rCH/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fr-rFR/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-fr/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-he-rIL/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-hi-rIN/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-hu-rHU/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-id-rID/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-it-rCH/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-it-rIT/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-it/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ja-rJP/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ja/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ko-rKR/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ko/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-lt-rLT/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-lv-rLV/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-nb/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-nl-rBE/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-nl-rNL/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-nl/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-pl-rPL/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-pl/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-pt-rBR/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-pt-rPT/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-pt/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ro-rRO/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ru-rRU/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-ru/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-sk-rSK/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-sl-rSI/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-sr-rRS/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-sv-rSE/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-th-rTH/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-tr-rTR/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-uk-rUA/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-vi-rVN/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-zh-rCN/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values-zh-rTW/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values/donottranslate-cldr.xml1
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java14
-rw-r--r--graphics/java/android/graphics/Canvas.java6
-rw-r--r--include/tts/TtsEngine.h18
-rw-r--r--include/utils/BackupHelpers.h63
-rw-r--r--include/utils/ResourceTypes.h2
-rw-r--r--keystore/java/android/security/Keystore.java124
-rw-r--r--libs/rs/RenderScriptEnv.h80
-rw-r--r--libs/rs/java/Film/Android.mk25
-rw-r--r--libs/rs/java/Film/AndroidManifest.xml13
-rw-r--r--libs/rs/java/Film/res/raw/filmimage.c110
-rw-r--r--libs/rs/java/Film/res/raw/filmstrip.c131
-rw-r--r--libs/rs/java/Film/src/com/android/film/Film.java90
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmRS.java242
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmStripMesh.java255
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmView.java82
-rw-r--r--libs/rs/java/Fountain/res/raw/fountain.c77
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java4
-rw-r--r--libs/rs/java/RenderScript/android/renderscript/Matrix.java6
-rw-r--r--libs/rs/java/RenderScript/android/renderscript/RenderScript.java15
-rw-r--r--libs/rs/java/Rollo/res/raw/rollo.c1
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java43
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java7
-rw-r--r--libs/rs/jni/RenderScript_jni.cpp27
-rw-r--r--libs/rs/rs.spec16
-rw-r--r--libs/rs/rsContext.cpp80
-rw-r--r--libs/rs/rsContext.h21
-rw-r--r--libs/rs/rsLocklessFifo.cpp97
-rw-r--r--libs/rs/rsLocklessFifo.h22
-rw-r--r--libs/rs/rsMatrix.cpp22
-rw-r--r--libs/rs/rsMatrix.h3
-rw-r--r--libs/rs/rsProgramFragment.cpp5
-rw-r--r--libs/rs/rsProgramFragment.h3
-rw-r--r--libs/rs/rsProgramFragmentStore.cpp6
-rw-r--r--libs/rs/rsProgramFragmentStore.h2
-rw-r--r--libs/rs/rsProgramVertex.cpp57
-rw-r--r--libs/rs/rsProgramVertex.h10
-rw-r--r--libs/rs/rsScript.h1
-rw-r--r--libs/rs/rsScriptC.cpp233
-rw-r--r--libs/rs/rsScriptC.h6
-rw-r--r--libs/rs/rsThreadIO.cpp5
-rw-r--r--libs/rs/rsThreadIO.h2
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp11
-rw-r--r--libs/utils/BackupData.cpp196
-rw-r--r--libs/utils/BackupHelpers.cpp215
-rw-r--r--libs/utils/ResourceTypes.cpp87
-rwxr-xr-x[-rw-r--r--]location/java/com/android/internal/location/GpsLocationProvider.java70
-rw-r--r--packages/SettingsProvider/AndroidManifest.xml2
-rw-r--r--packages/SettingsProvider/res/values/strings.xml22
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java10
-rw-r--r--packages/SubscribedFeedsProvider/AndroidManifest.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values/strings.xml21
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp14
-rwxr-xr-xpackages/TtsService/src/android/tts/SynthProxy.java7
-rwxr-xr-xpackages/TtsService/src/android/tts/TtsService.java87
-rw-r--r--packages/VpnServices/AndroidManifest.xml2
-rwxr-xr-xpackages/VpnServices/res/values/strings.xml3
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java7
-rw-r--r--services/java/com/android/server/BackupManagerService.java307
-rw-r--r--services/java/com/android/server/EntropyService.java101
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java292
-rw-r--r--services/java/com/android/server/PackageManagerService.java199
-rw-r--r--services/java/com/android/server/RandomBlock.java100
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java189
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java2
-rw-r--r--services/java/com/android/server/am/HistoryRecord.java6
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java4
-rw-r--r--services/java/com/android/server/am/ReceiverList.java2
-rwxr-xr-xservices/java/com/android/server/am/UsageStatsService.java127
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java17
-rw-r--r--telephony/java/android/telephony/SmsManager.java52
-rw-r--r--telephony/java/android/telephony/SmsMessage.java138
-rw-r--r--telephony/java/com/android/internal/telephony/GsmAlphabet.java46
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java6
-rw-r--r--telephony/java/com/android/internal/telephony/SmsMessageBase.java32
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java9
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java33
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java113
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/UserData.java17
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java37
-rw-r--r--test-runner/android/test/mock/MockContext.java6
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java11
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java2
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java3
-rwxr-xr-xtests/DumpRenderTree/assets/run_layout_tests.py2
-rw-r--r--tests/backup/src/com/android/backuptest/BackupTestActivity.java64
-rw-r--r--tests/backup/src/com/android/backuptest/BackupTestAgent.java27
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java134
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java85
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Command.cpp27
-rw-r--r--tools/aapt/Main.cpp6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java254
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java7
255 files changed, 7798 insertions, 2412 deletions
diff --git a/Android.mk b/Android.mk
index e10ec80..58b149e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -73,10 +73,8 @@ LOCAL_SRC_FILES += \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
- core/java/android/app/IBackupAgent.aidl \
+ core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
- core/java/android/app/IIntentReceiver.aidl \
- core/java/android/app/IIntentSender.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/ISearchManager.aidl \
core/java/android/app/ISearchManagerCallback.aidl \
@@ -92,6 +90,8 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothDevice.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/content/IContentService.aidl \
+ core/java/android/content/IIntentReceiver.aidl \
+ core/java/android/content/IIntentSender.aidl \
core/java/android/content/ISyncAdapter.aidl \
core/java/android/content/ISyncContext.aidl \
core/java/android/content/ISyncStatusObserver.aidl \
@@ -203,6 +203,7 @@ aidl_files := \
frameworks/base/core/java/android/app/PendingIntent.aidl \
frameworks/base/core/java/android/content/ComponentName.aidl \
frameworks/base/core/java/android/content/Intent.aidl \
+ frameworks/base/core/java/android/content/IntentSender.aidl \
frameworks/base/core/java/android/content/SyncStats.aidl \
frameworks/base/core/java/android/content/res/Configuration.aidl \
frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \
diff --git a/api/current.xml b/api/current.xml
index c436b2d..3174f09 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -25161,6 +25161,17 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getIntentSender"
+ return="android.content.IntentSender"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getService"
return="android.app.PendingIntent"
abstract="false"
@@ -30524,6 +30535,17 @@
visibility="public"
>
</method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getAssets"
return="android.content.res.AssetManager"
abstract="true"
@@ -31887,6 +31909,17 @@
visibility="public"
>
</method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getAssets"
return="android.content.res.AssetManager"
abstract="false"
@@ -32882,6 +32915,70 @@
</exception>
</method>
</interface>
+<interface name="IIntentReceiver"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="performReceive"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="data" type="java.lang.String">
+</parameter>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+<parameter name="ordered" type="boolean">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<interface name="IIntentSender"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="send"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resolvedType" type="java.lang.String">
+</parameter>
+<parameter name="finishedReceiver" type="android.content.IIntentReceiver">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -33364,7 +33461,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="uri" type="java.lang.String">
@@ -33415,6 +33512,17 @@
<parameter name="defaultValue" type="long">
</parameter>
</method>
+<method name="getPackage"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getParcelableArrayExtra"
return="android.os.Parcelable[]"
abstract="false"
@@ -33614,6 +33722,23 @@
<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
</exception>
</method>
+<method name="parseUri"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="java.lang.String">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="URISyntaxException" type="java.net.URISyntaxException">
+</exception>
+</method>
<method name="putExtra"
return="android.content.Intent"
abstract="false"
@@ -34287,6 +34412,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="setPackage"
+ return="android.content.Intent"
+ 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="setType"
return="android.content.Intent"
abstract="false"
@@ -34307,9 +34445,22 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="toUri"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="flags" type="int">
+</parameter>
</method>
<method name="writeToParcel"
return="void"
@@ -34953,6 +35104,17 @@
visibility="public"
>
</field>
+<field name="ACTION_POWER_USAGE_SUMMARY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.POWER_USAGE_SUMMARY&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_PROVIDER_CHANGED"
type="java.lang.String"
transient="false"
@@ -35063,6 +35225,17 @@
visibility="public"
>
</field>
+<field name="ACTION_SEND_MULTIPLE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.SEND_MULTIPLE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_SET_WALLPAPER"
type="java.lang.String"
transient="false"
@@ -35700,6 +35873,17 @@
visibility="public"
>
</field>
+<field name="FILL_IN_PACKAGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_ACTIVITY_BROUGHT_TO_FRONT"
type="int"
transient="false"
@@ -35909,6 +36093,17 @@
visibility="public"
>
</field>
+<field name="URI_INTENT_SCHEME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Intent.FilterComparison"
extends="java.lang.Object"
@@ -36923,6 +37118,190 @@
</parameter>
</constructor>
</class>
+<class name="IntentSender"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="IntentSender"
+ type="android.content.IntentSender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="target" type="android.content.IIntentSender">
+</parameter>
+</constructor>
+<constructor name="IntentSender"
+ type="android.content.IntentSender"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="target" type="android.os.IBinder">
+</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="readIntentSenderOrNullFromParcel"
+ return="android.content.IntentSender"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</method>
+<method name="sendIntent"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="onFinished" type="android.content.IntentSender.OnFinished">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
+<method name="writeIntentSenderOrNullToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sender" type="android.content.IntentSender">
+</parameter>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="IntentSender.OnFinished"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onSendFinished"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="IntentSender" type="android.content.IntentSender">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="java.lang.String">
+</parameter>
+<parameter name="resultExtras" type="android.os.Bundle">
+</parameter>
+</method>
+</interface>
+<class name="IntentSender.SendIntentException"
+ extends="android.util.AndroidException"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="IntentSender.SendIntentException"
+ type="android.content.IntentSender.SendIntentException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="IntentSender.SendIntentException"
+ type="android.content.IntentSender.SendIntentException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="IntentSender.SendIntentException"
+ type="android.content.IntentSender.SendIntentException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Exception">
+</parameter>
+</constructor>
+</class>
<class name="MutableContextWrapper"
extends="android.content.ContextWrapper"
abstract="false"
@@ -38215,6 +38594,17 @@
visibility="public"
>
</field>
+<field name="FLAG_SUPPORTS_LARGE_SCREENS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_SYSTEM"
type="int"
transient="false"
@@ -38288,16 +38678,6 @@
visibility="public"
>
</field>
-<field name="expandable"
- type="boolean"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="flags"
type="int"
transient="false"
@@ -40029,23 +40409,6 @@
<parameter name="flags" type="int">
</parameter>
</method>
-<method name="resolveActivity"
- return="android.content.pm.ResolveInfo"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
<method name="resolveContentProvider"
return="android.content.pm.ProviderInfo"
abstract="true"
@@ -40187,17 +40550,6 @@
visibility="public"
>
</field>
-<field name="GET_EXPANDABLE"
- type="int"
- transient="false"
- volatile="false"
- value="131072"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="GET_GIDS"
type="int"
transient="false"
@@ -109012,6 +109364,17 @@
visibility="public"
>
</field>
+<field name="TTS_DEFAULT_COUNTRY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;tts_default_country&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TTS_DEFAULT_LANG"
type="java.lang.String"
transient="false"
@@ -109056,6 +109419,17 @@
visibility="public"
>
</field>
+<field name="TTS_DEFAULT_VARIANT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;tts_default_variant&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TTS_USE_DEFAULTS"
type="java.lang.String"
transient="false"
@@ -117589,6 +117963,17 @@
visibility="public"
>
</method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getAssets"
return="android.content.res.AssetManager"
abstract="false"
@@ -118976,23 +119361,6 @@
</parameter>
<parameter name="flags" type="int">
</parameter>
-<parameter name="packageName" type="java.lang.String">
-</parameter>
-</method>
-<method name="resolveActivity"
- return="android.content.pm.ResolveInfo"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-<parameter name="flags" type="int">
-</parameter>
</method>
<method name="resolveContentProvider"
return="android.content.pm.ProviderInfo"
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index 22dd486..d4e669b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -64,22 +64,14 @@ perform_list(const char* filename)
}
BackupDataReader reader(fd);
+ bool done;
int type;
- while (reader.ReadNextHeader(&type) == 0) {
+ while (reader.ReadNextHeader(&done, &type) == 0) {
+ if (done) {
+ break;
+ }
switch (type) {
- case BACKUP_HEADER_APP_V1:
- {
- String8 packageName;
- int cookie;
- err = reader.ReadAppHeader(&packageName, &cookie);
- if (err == 0) {
- printf("App header: %s 0x%08x (%d)\n", packageName.string(), cookie, cookie);
- } else {
- printf("Error reading app header\n");
- }
- break;
- }
case BACKUP_HEADER_ENTITY_V1:
{
String8 key;
@@ -92,17 +84,6 @@ perform_list(const char* filename)
}
break;
}
- case BACKUP_FOOTER_APP_V1:
- {
- int cookie;
- err = reader.ReadAppFooter(&cookie);
- if (err == 0) {
- printf(" App footer: 0x%08x (%d)\n", cookie, cookie);
- } else {
- printf(" Error reading entity header\n");
- }
- break;
- }
default:
{
printf("Unknown chunk type: 0x%08x\n", type);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 467cac1..841e3df 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -36,9 +36,14 @@ public final class Bmgr {
private String mCurArgData;
public static void main(String[] args) {
- new Bmgr().run(args);
+ try {
+ new Bmgr().run(args);
+ } catch (Exception e) {
+ System.err.println("Exception caught:");
+ e.printStackTrace();
+ }
}
-
+
public void run(String[] args) {
boolean validCommand = false;
if (args.length < 1) {
@@ -70,6 +75,19 @@ public final class Bmgr {
doList();
return;
}
+
+ if ("restore".equals(op)) {
+ doRestore();
+ return;
+ }
+
+ if ("transport".equals(op)) {
+ doTransport();
+ return;
+ }
+
+ System.err.println("Unknown command");
+ showUsage();
}
private void doRun() {
@@ -103,6 +121,19 @@ public final class Bmgr {
}
}
+ private void doTransport() {
+ try {
+ int which = Integer.parseInt(nextArg());
+ int old = mBmgr.selectBackupTransport(which);
+ System.out.println("Selected transport " + which + " (formerly " + old + ")");
+ } catch (NumberFormatException e) {
+ showUsage();
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private void doList() {
String arg = nextArg(); // sets, transports, packages set#
if ("transports".equals(arg)) {
@@ -114,6 +145,10 @@ public final class Bmgr {
try {
int curTransport = mBmgr.getCurrentTransport();
mRestore = mBmgr.beginRestoreSession(curTransport);
+ if (mRestore == null) {
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ return;
+ }
if ("sets".equals(arg)) {
doListRestoreSets();
@@ -127,13 +162,12 @@ public final class Bmgr {
}
private void doListTransports() {
-
}
private void doListRestoreSets() {
try {
RestoreSet[] sets = mRestore.getAvailableRestoreSets();
- if (sets.length == 0) {
+ if (sets == null || sets.length == 0) {
System.out.println("No restore sets available");
} else {
for (RestoreSet s : sets) {
@@ -146,6 +180,37 @@ public final class Bmgr {
}
}
+ private void doRestore() {
+ int token;
+ try {
+ token = Integer.parseInt(nextArg());
+ } catch (NumberFormatException e) {
+ showUsage();
+ return;
+ }
+
+ try {
+ int curTransport = mBmgr.getCurrentTransport();
+ mRestore = mBmgr.beginRestoreSession(curTransport);
+ if (mRestore == null) {
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ return;
+ }
+ RestoreSet[] sets = mRestore.getAvailableRestoreSets();
+ for (RestoreSet s : sets) {
+ if (s.token == token) {
+ System.out.println("Scheduling restore: " + s.name);
+ mRestore.performRestore(token);
+ break;
+ }
+ }
+ mRestore.endRestoreSession();
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -161,7 +226,7 @@ public final class Bmgr {
System.err.println(" bmgr list sets");
System.err.println(" #bmgr list transports");
System.err.println(" #bmgr transport which#");
- System.err.println(" #bmgr restore set#");
+ System.err.println(" bmgr restore token#");
System.err.println(" bmgr run");
}
} \ No newline at end of file
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
index e53cece..17dd060 100644
--- a/cmds/keystore/commands.c
+++ b/cmds/keystore/commands.c
@@ -1,5 +1,5 @@
/*
-** Copyright 2008, The Android Open Source Project
+** 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.
@@ -30,7 +30,8 @@ static DIR *open_keystore(const char *dir)
return d;
}
-static int list_files(const char *dir, char reply[REPLY_MAX]) {
+static int list_files(const char *dir, char reply[REPLY_MAX])
+{
struct dirent *de;
DIR *d;
@@ -39,7 +40,9 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) {
}
reply[0]=0;
while ((de = readdir(d))) {
- if (de->d_type != DT_REG) continue;
+ if (de->d_type != DT_DIR) continue;
+ if ((strcmp(DOT, de->d_name) == 0) ||
+ (strcmp(DOTDOT, de->d_name) == 0)) continue;
if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
LOGE("reply is too long(too many files under '%s'\n", dir);
@@ -50,31 +53,25 @@ static int list_files(const char *dir, char reply[REPLY_MAX]) {
return 0;
}
-static int copy_keyfile(const char *keystore, const char *srcfile) {
- int srcfd, dstfd;
- int length;
- char buf[2048];
- char dstfile[KEYNAME_LENGTH];
- const char *filename = strrchr(srcfile, '/');
+static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
+ int srcfd = -1, dstfd;
+ char buf[REPLY_MAX];
- strlcpy(dstfile, keystore, KEYNAME_LENGTH);
- strlcat(dstfile, "/", KEYNAME_LENGTH);
- if (strlcat(dstfile, filename ? filename + 1 : srcfile,
- KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
- LOGE("keyname is too long '%s'\n", srcfile);
- return -1;
- }
-
- if ((srcfd = open(srcfile, O_RDONLY)) == -1) {
- LOGE("Cannot open the original file '%s'\n", srcfile);
+ if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
+ LOGE("Cannot open the original file '%s'\n", src);
return -1;
}
if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
LOGE("Cannot open the destination file '%s'\n", dstfile);
return -1;
}
- while((length = read(srcfd, buf, 2048)) > 0) {
- write(dstfd, buf, length);
+ if (src_type == IS_FILE) {
+ int length;
+ while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
+ write(dstfd, buf, length);
+ }
+ } else {
+ write(dstfd, src, strlen(src));
}
close(srcfd);
close(dstfd);
@@ -82,60 +79,149 @@ static int copy_keyfile(const char *keystore, const char *srcfile) {
return 0;
}
-static int install_key(const char *dir, const char *keyfile)
+static int install_key(const char *path, const char *certname, const char *src,
+ int src_is_file, char *dstfile)
{
struct dirent *de;
+ char fullpath[KEYNAME_LENGTH];
DIR *d;
- if ((d = open_keystore(dir)) == NULL) {
+ if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
+ >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", certname);
+ return -1;
+ }
+
+ if ((d = open_keystore(fullpath)) == NULL) {
+ LOGE("Can not open the keystore '%s'\n", fullpath);
+ return -1;
+ }
+ closedir(d);
+ if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", certname);
return -1;
}
- return copy_keyfile(dir, keyfile);
+ return copy_keyfile(src, src_is_file, fullpath);
}
-static int remove_key(const char *dir, const char *keyfile)
+static int get_key(const char *path, const char *keyname, const char *file,
+ char reply[REPLY_MAX])
+{
+ struct dirent *de;
+ char filename[KEYNAME_LENGTH];
+ int fd;
+
+ if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
+ >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", keyname);
+ return -1;
+ }
+
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ return -1;
+ }
+ close(fd);
+ strlcpy(reply, filename, REPLY_MAX);
+ return 0;
+}
+
+static int remove_key(const char *dir, const char *key)
{
char dstfile[KEYNAME_LENGTH];
+ char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
+ CA_CERTIFICATE };
+ int i, count = 0;
+
+ for ( i = 0 ; i < 4 ; i++) {
+ if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
+ >= KEYNAME_LENGTH) {
+ LOGE("keyname is too long '%s'\n", key);
+ return -1;
+ }
+ if (unlink(dstfile) == 0) count++;
+ }
- strlcpy(dstfile, dir, KEYNAME_LENGTH);
- strlcat(dstfile, "/", KEYNAME_LENGTH);
- if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
- LOGE("keyname is too long '%s'\n", keyfile);
+ if (count == 0) {
+ LOGE("can not clean up '%s' keys or not exist\n", key);
return -1;
}
- if (unlink(dstfile)) {
- LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno));
+
+ snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
+ if (rmdir(dstfile)) {
+ LOGE("can not clean up '%s' directory\n", key);
return -1;
}
return 0;
}
-int list_certs(char reply[REPLY_MAX])
+int list_user_certs(char reply[REPLY_MAX])
{
return list_files(CERTS_DIR, reply);
}
-int list_userkeys(char reply[REPLY_MAX])
+int list_ca_certs(char reply[REPLY_MAX])
{
- return list_files(USERKEYS_DIR, reply);
+ return list_files(CACERTS_DIR, reply);
}
-int install_cert(const char *certfile)
+int install_user_cert(const char *keyname, const char *cert, const char *key)
{
- return install_key(CERTS_DIR, certfile);
+ if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
+ return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
+ }
+ return -1;
}
-int install_userkey(const char *keyfile)
+int install_ca_cert(const char *keyname, const char *certfile)
{
- return install_key(USERKEYS_DIR, keyfile);
+ return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
+}
+
+int install_p12_cert(const char *keyname, const char *certfile)
+{
+ return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
+}
+
+int add_ca_cert(const char *keyname, const char *certificate)
+{
+ return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
+ CA_CERTIFICATE);
+}
+
+int add_user_cert(const char *keyname, const char *certificate)
+{
+ return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
+ USER_CERTIFICATE);
+}
+
+int add_user_key(const char *keyname, const char *key)
+{
+ return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
+}
+
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
+{
+ return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
+}
+
+int get_user_cert(const char *keyname, char reply[REPLY_MAX])
+{
+ return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
+}
+
+int get_user_key(const char *keyname, char reply[REPLY_MAX])
+{
+ if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
+ return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
+ return 0;
}
-int remove_cert(const char *certfile)
+int remove_user_cert(const char *key)
{
- return remove_key(CERTS_DIR, certfile);
+ return remove_key(CERTS_DIR, key);
}
-int remove_userkey(const char *keyfile)
+int remove_ca_cert(const char *key)
{
- return remove_key(USERKEYS_DIR, keyfile);
+ return remove_key(CACERTS_DIR, key);
}
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 5193b3d..df8d832 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -16,37 +16,89 @@
#include "keystore.h"
+static inline int has_whitespace(char *name)
+{
+ if((strrchr(name, ' ') != NULL)) {
+ LOGE("'%s' contains whitespace character\n", name);
+ return 1;
+ }
+ return 0;
+}
+
+static int do_list_user_certs(char **arg, char reply[REPLY_MAX])
+{
+ return list_user_certs(reply);
+}
+
+static int do_list_ca_certs(char **arg, char reply[REPLY_MAX])
+{
+ return list_ca_certs(reply);
+}
+
+static int do_install_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ if (has_whitespace(arg[0])) return -1;
+ /* copy the certificate and key to keystore */
+ return install_user_cert(arg[0], arg[1], arg[2]);
+}
-static int do_list_certs(char **arg, char reply[REPLY_MAX])
+static int do_install_p12_cert(char **arg, char reply[REPLY_MAX])
{
- return list_certs(reply);
+ if (has_whitespace(arg[0])) return -1;
+ return install_p12_cert(arg[0], arg[1]);
}
-static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
+static int do_install_ca_cert(char **arg, char reply[REPLY_MAX])
{
- return list_userkeys(reply);
+ if (has_whitespace(arg[0])) return -1;
+ /* copy the certificate and key to keystore */
+ return install_ca_cert(arg[0], arg[1]);
}
-static int do_install_cert(char **arg, char reply[REPLY_MAX])
+static int do_add_ca_cert(char **arg, char reply[REPLY_MAX])
{
- return install_cert(arg[0]); /* move the certificate to keystore */
+ if (has_whitespace(arg[0])) return -1;
+ return add_ca_cert(arg[0], arg[1]);
}
-static int do_remove_cert(char **arg, char reply[REPLY_MAX])
+static int do_add_user_cert(char **arg, char reply[REPLY_MAX])
{
- return remove_cert(arg[0]); /* certificate */
+ if (has_whitespace(arg[0])) return -1;
+ return add_user_cert(arg[0], arg[1]);
}
-static int do_install_userkey(char **arg, char reply[REPLY_MAX])
+static int do_add_user_key(char **arg, char reply[REPLY_MAX])
{
- return install_userkey(arg[0]); /* move the certificate to keystore */
+ if (has_whitespace(arg[0])) return -1;
+ return add_user_key(arg[0], arg[1]);
}
-static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
+static int do_get_ca_cert(char **arg, char reply[REPLY_MAX])
{
- return remove_userkey(arg[0]); /* userkey */
+ return get_ca_cert(arg[0], reply);
}
+static int do_get_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ return get_user_cert(arg[0], reply);
+}
+
+static int do_get_user_key(char **arg, char reply[REPLY_MAX])
+{
+ return get_user_key(arg[0], reply);
+}
+
+static int do_remove_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ return remove_user_cert(arg[0]);
+}
+
+static int do_remove_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+ return remove_ca_cert(arg[0]);
+}
+
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -55,12 +107,19 @@ struct cmdinfo {
struct cmdinfo cmds[] = {
- { "listcerts", 0, do_list_certs },
- { "listuserkeys", 0, do_list_userkeys },
- { "installcert", 1, do_install_cert },
- { "removecert", 1, do_remove_cert },
- { "installuserkey", 1, do_install_userkey },
- { "removeuserkey", 1, do_remove_userkey },
+ { "listcacerts", 0, do_list_ca_certs },
+ { "listusercerts", 0, do_list_user_certs },
+ { "installusercert", 3, do_install_user_cert },
+ { "installcacert", 2, do_install_ca_cert },
+ { "installp12cert", 2, do_install_p12_cert },
+ { "addusercert", 2, do_add_user_cert },
+ { "adduserkey", 2, do_add_user_key },
+ { "addcacert", 2, do_add_ca_cert },
+ { "getusercert", 1, do_get_user_cert },
+ { "getuserkey", 1, do_get_user_key },
+ { "getcacert", 1, do_get_ca_cert },
+ { "removecacert", 1, do_remove_ca_cert },
+ { "removeusercert", 1, do_remove_user_cert },
};
static int readx(int s, void *_buf, int count)
@@ -121,7 +180,7 @@ static int execute(int s, char cmd[BUFFER_MAX])
/* n is number of args (not counting arg[0]) */
arg[0] = cmd;
while (*cmd) {
- if (isspace(*cmd)) {
+ if (*cmd == CMD_DELIMITER) {
*cmd++ = 0;
n++;
arg[n] = cmd;
@@ -167,6 +226,7 @@ int shell_command(const int argc, const char **argv)
int fd, i;
short ret;
unsigned short count;
+ char delimiter[2] = { CMD_DELIMITER, 0 };
char buf[BUFFER_MAX]="";
fd = socket_local_client(SOCKET_PATH,
@@ -177,7 +237,7 @@ int shell_command(const int argc, const char **argv)
exit(1);
}
for(i = 0; i < argc; i++) {
- if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+ if (i > 0) strlcat(buf, delimiter, BUFFER_MAX);
if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
fprintf(stderr, "Arguments are too long\n");
exit(1);
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
index 35acf0b9..b9cb185 100644
--- a/cmds/keystore/keystore.h
+++ b/cmds/keystore/keystore.h
@@ -40,18 +40,35 @@
/* path of the keystore */
#define KEYSTORE_DIR_PREFIX "/data/misc/keystore"
-#define CERTS_DIR KEYSTORE_DIR_PREFIX "/certs"
-#define USERKEYS_DIR KEYSTORE_DIR_PREFIX "/userkeys"
+#define CERTS_DIR KEYSTORE_DIR_PREFIX "/keys"
+#define CACERTS_DIR KEYSTORE_DIR_PREFIX "/cacerts"
+#define CA_CERTIFICATE "ca.crt"
+#define USER_CERTIFICATE "user.crt"
+#define USER_P12_CERT "user.p12"
+#define USER_KEY "user.key"
+#define DOT "."
+#define DOTDOT ".."
-#define BUFFER_MAX 1024 /* input buffer for commands */
+#define BUFFER_MAX 4096 /* input buffer for commands */
#define TOKEN_MAX 8 /* max number of arguments in buffer */
-#define REPLY_MAX 1024 /* largest reply allowed */
+#define REPLY_MAX 4096 /* largest reply allowed */
+#define CMD_DELIMITER '\t'
#define KEYNAME_LENGTH 128
+#define IS_CONTENT 0
+#define IS_FILE 1
+
/* commands.c */
-int list_certs(char reply[REPLY_MAX]);
-int list_userkeys(char reply[REPLY_MAX]);
-int install_cert(const char *certfile);
-int install_userkey(const char *keyfile);
-int remove_cert(const char *certfile);
-int remove_userkey(const char *keyfile);
+int list_ca_certs(char reply[REPLY_MAX]);
+int list_user_certs(char reply[REPLY_MAX]);
+int install_user_cert(const char *certname, const char *cert, const char *key);
+int install_ca_cert(const char *certname, const char *cert);
+int install_p12_cert(const char *certname, const char *cert);
+int add_ca_cert(const char *certname, const char *content);
+int add_user_cert(const char *certname, const char *content);
+int add_user_key(const char *keyname, const char *content);
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_key(const char *keyname, char reply[REPLY_MAX]);
+int remove_user_cert(const char *certname);
+int remove_ca_cert(const char *certname);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7fb3449..ca9632a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IIntentSender;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -863,13 +864,26 @@ public class Activity extends ContextThemeWrapper
final Integer dialogId = ids[i];
Bundle dialogState = b.getBundle(savedDialogKeyFor(dialogId));
if (dialogState != null) {
- final Dialog dialog = onCreateDialog(dialogId);
- dialog.onRestoreInstanceState(dialogState);
+ // Calling onRestoreInstanceState() below will invoke dispatchOnCreate
+ // so tell createDialog() not to do it, otherwise we get an exception
+ final Dialog dialog = createDialog(dialogId, false);
mManagedDialogs.put(dialogId, dialog);
+ onPrepareDialog(dialogId, dialog);
+ dialog.onRestoreInstanceState(dialogState);
}
}
}
+ private Dialog createDialog(Integer dialogId, boolean dispatchOnCreate) {
+ final Dialog dialog = onCreateDialog(dialogId);
+ if (dialog == null) {
+ throw new IllegalArgumentException("Activity#onCreateDialog did "
+ + "not create a dialog for id " + dialogId);
+ }
+ if (dispatchOnCreate) dialog.dispatchOnCreate(null);
+ return dialog;
+ }
+
private String savedDialogKeyFor(int key) {
return SAVED_DIALOG_KEY_PREFIX + key;
}
@@ -2418,12 +2432,7 @@ public class Activity extends ContextThemeWrapper
}
Dialog dialog = mManagedDialogs.get(id);
if (dialog == null) {
- dialog = onCreateDialog(id);
- if (dialog == null) {
- throw new IllegalArgumentException("Activity#onCreateDialog did "
- + "not create a dialog for id " + id);
- }
- dialog.dispatchOnCreate(null);
+ dialog = createDialog(id, true);
mManagedDialogs.put(id, dialog);
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3d3d7d5..b6f855a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -17,9 +17,10 @@
package android.app;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentSender;
+import android.content.IIntentReceiver;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d08fc11..98bd45a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -23,6 +23,7 @@ import android.content.ContentProvider;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
+import android.content.IIntentReceiver;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -31,6 +32,7 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.PackageParser.Component;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -185,7 +187,7 @@ public final class ActivityThread {
try {
appInfo = getPackageManager().getApplicationInfo(
pkgInfo.getPackageName(),
- PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE);
+ PackageManager.GET_SUPPORTS_DENSITIES);
} catch (RemoteException e) {
throw new AssertionError(e);
}
@@ -285,6 +287,10 @@ public final class ActivityThread {
return mPackageName;
}
+ public ApplicationInfo getApplicationInfo() {
+ return mApplicationInfo;
+ }
+
public boolean isSecurityViolation() {
return mSecurityViolation;
}
@@ -2082,6 +2088,10 @@ public final class ActivityThread {
return mInitialApplication;
}
+ public String getProcessName() {
+ return mBoundApplication.processName;
+ }
+
public ApplicationContext getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
@@ -3216,7 +3226,7 @@ public final class ActivityThread {
r.activity.getComponentName().getClassName());
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString()
+ "Activity " + safeToComponentShortString(r.intent)
+ " did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
@@ -3225,7 +3235,7 @@ public final class ActivityThread {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3240,7 +3250,7 @@ public final class ActivityThread {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3265,7 +3275,7 @@ public final class ActivityThread {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain child activities "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3276,7 +3286,7 @@ public final class ActivityThread {
r.activity.onDestroy();
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString() +
+ "Activity " + safeToComponentShortString(r.intent) +
" did not call through to super.onDestroy()");
}
if (r.window != null) {
@@ -3287,8 +3297,7 @@ public final class ActivityThread {
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
- "Unable to destroy activity "
- + r.intent.getComponent().toShortString()
+ "Unable to destroy activity " + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3298,6 +3307,11 @@ public final class ActivityThread {
return r;
}
+ private static String safeToComponentShortString(Intent intent) {
+ ComponentName component = intent.getComponent();
+ return component == null ? "[Unknown]" : component.toShortString();
+ }
+
private final void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityRecord r = performDestroyActivity(token, finishing,
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index c261acb..1666588 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -32,6 +32,8 @@ import android.content.ContextWrapper;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentReceiver;
+import android.content.IntentSender;
import android.content.ReceiverCallNotAllowedException;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
@@ -284,6 +286,14 @@ class ApplicationContext extends Context {
}
@Override
+ public ApplicationInfo getApplicationInfo() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getApplicationInfo();
+ }
+ throw new RuntimeException("Not supported in system context");
+ }
+
+ @Override
public String getPackageResourcePath() {
if (mPackageInfo != null) {
return mPackageInfo.getResDir();
@@ -1533,14 +1543,16 @@ class ApplicationContext extends Context {
// overall package (such as if it has multiple launcher entries).
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(Intent.CATEGORY_INFO);
- ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0, packageName);
+ intentToResolve.setPackage(packageName);
+ ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
// Otherwise, try to find a main launcher activity.
if (resolveInfo == null) {
// reuse the intent instance
intentToResolve.removeCategory(Intent.CATEGORY_INFO);
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
- resolveInfo = resolveActivity(intentToResolve, 0, packageName);
+ intentToResolve.setPackage(packageName);
+ resolveInfo = resolveActivity(intentToResolve, 0);
}
if (resolveInfo == null) {
return null;
@@ -1788,19 +1800,6 @@ class ApplicationContext extends Context {
}
@Override
- public ResolveInfo resolveActivity(Intent intent, int flags, String packageName) {
- try {
- return mPM.resolveIntentForPackage(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags,
- packageName);
- } catch (RemoteException e) {
- throw new RuntimeException("Package manager has died", e);
- }
- }
-
- @Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
int flags) {
try {
@@ -2373,11 +2372,11 @@ class ApplicationContext extends Context {
// Should never happen!
}
}
-
+
@Override
- public void freeStorage(long idealStorageSize, PendingIntent opFinishedIntent) {
+ public void freeStorage(long freeStorageSize, IntentSender pi) {
try {
- mPM.freeStorage(idealStorageSize, opFinishedIntent);
+ mPM.freeStorage(freeStorageSize, pi);
} catch (RemoteException e) {
// Should never happen!
}
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 0c8f95d..6b17236 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -151,6 +151,11 @@ public class ApplicationErrorReport implements Parcelable {
public String exceptionClassName;
/**
+ * Message stored in the exception.
+ */
+ public String exceptionMessage;
+
+ /**
* File which the exception was thrown from.
*/
public String throwFileName;
@@ -181,6 +186,7 @@ public class ApplicationErrorReport implements Parcelable {
*/
public CrashInfo(Parcel in) {
exceptionClassName = in.readString();
+ exceptionMessage = in.readString();
throwFileName = in.readString();
throwClassName = in.readString();
throwMethodName = in.readString();
@@ -192,6 +198,7 @@ public class ApplicationErrorReport implements Parcelable {
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(exceptionClassName);
+ dest.writeString(exceptionMessage);
dest.writeString(throwFileName);
dest.writeString(throwClassName);
dest.writeString(throwMethodName);
@@ -203,6 +210,7 @@ public class ApplicationErrorReport implements Parcelable {
*/
public void dump(Printer pw, String prefix) {
pw.println(prefix + "exceptionClassName: " + exceptionClassName);
+ pw.println(prefix + "exceptionMessage: " + exceptionMessage);
pw.println(prefix + "throwFileName: " + throwFileName);
pw.println(prefix + "throwClassName: " + throwClassName);
pw.println(prefix + "throwMethodName: " + throwMethodName);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 6750d12..4b64c94 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -18,6 +18,7 @@ package android.app;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.IIntentReceiver;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
diff --git a/core/java/android/app/BackupAgent.java b/core/java/android/app/BackupAgent.java
index 997bfdc..85c001c 100644
--- a/core/java/android/app/BackupAgent.java
+++ b/core/java/android/app/BackupAgent.java
@@ -17,6 +17,7 @@
package android.app;
import android.app.IBackupAgent;
+import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.content.Context;
import android.content.ContextWrapper;
@@ -25,6 +26,8 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
+import java.io.IOException;
+
/**
* This is the central interface between an application and Android's
* settings backup mechanism.
@@ -32,6 +35,8 @@ import android.util.Log;
* @hide pending API solidification
*/
public abstract class BackupAgent extends ContextWrapper {
+ private static final String TAG = "BackupAgent";
+
public BackupAgent() {
super(null);
}
@@ -77,8 +82,8 @@ public abstract class BackupAgent extends ContextWrapper {
* file. The application should record the final backup state
* here after restoring its data from dataFd.
*/
- public abstract void onRestore(ParcelFileDescriptor /* TODO: BackupDataInput */ data,
- ParcelFileDescriptor newState);
+ public abstract void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
+ throws IOException;
// ----- Core implementation -----
@@ -107,13 +112,11 @@ public abstract class BackupAgent extends ContextWrapper {
ParcelFileDescriptor newState) throws RemoteException {
// !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v(TAG, "doBackup() invoked");
- BackupDataOutput output = new BackupDataOutput(BackupAgent.this,
- data.getFileDescriptor());
+ BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
try {
BackupAgent.this.onBackup(oldState, output, newState);
} catch (RuntimeException ex) {
- Log.d("BackupAgent", "onBackup ("
- + BackupAgent.this.getClass().getName() + ") threw", ex);
+ Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw ex;
}
}
@@ -122,7 +125,16 @@ public abstract class BackupAgent extends ContextWrapper {
ParcelFileDescriptor newState) throws RemoteException {
// !!! TODO - real implementation; for now just invoke the callbacks directly
Log.v(TAG, "doRestore() invoked");
- BackupAgent.this.onRestore(data, newState);
+ BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
+ try {
+ BackupAgent.this.onRestore(input, newState);
+ } catch (IOException ex) {
+ Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
+ throw new RuntimeException(ex);
+ } catch (RuntimeException ex) {
+ Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
+ throw ex;
+ }
}
}
}
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
index bf5cb5d..89becf4 100644
--- a/core/java/android/app/FullBackupAgent.java
+++ b/core/java/android/app/FullBackupAgent.java
@@ -1,5 +1,6 @@
package android.app;
+import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.FileBackupHelper;
import android.os.ParcelFileDescriptor;
@@ -52,6 +53,6 @@ public class FullBackupAgent extends BackupAgent {
}
@Override
- public void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) {
+ public void onRestore(BackupDataInput data, ParcelFileDescriptor newState) {
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c948aec..66bc85b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -21,6 +21,8 @@ import android.content.ContentProviderNative;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentSender;
+import android.content.IIntentReceiver;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index bca1fea..029c650 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -18,6 +18,7 @@ package android.app;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.IIntentReceiver;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
diff --git a/core/java/android/app/IIntentReceiver.aidl b/core/java/android/app/IIntentReceiver.aidl
deleted file mode 100755
index 5f5d0eb..0000000
--- a/core/java/android/app/IIntentReceiver.aidl
+++ /dev/null
@@ -1,33 +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.
-*/
-package android.app;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * System private API for dispatching intent broadcasts. This is given to the
- * activity manager as part of registering for an intent broadcasts, and is
- * called when it receives intents.
- *
- * {@hide}
- */
-oneway interface IIntentReceiver {
- void performReceive(in Intent intent, int resultCode,
- String data, in Bundle extras, boolean ordered);
-}
-
diff --git a/core/java/android/app/IIntentSender.aidl b/core/java/android/app/IIntentSender.aidl
deleted file mode 100644
index 53e135a..0000000
--- a/core/java/android/app/IIntentSender.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* //device/java/android/android/app/IActivityPendingResult.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.app;
-
-import android.app.IIntentReceiver;
-import android.content.Intent;
-
-/** @hide */
-interface IIntentSender {
- int send(int code, in Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver);
-}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f6a28b2..e31f4f8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -446,13 +446,13 @@ public class Instrumentation {
if (ai == null) {
throw new RuntimeException("Unable to resolve activity for: " + intent);
}
- if (!ai.applicationInfo.processName.equals(
- getTargetContext().getPackageName())) {
+ String myProc = mThread.getProcessName();
+ if (!ai.processName.equals(myProc)) {
// todo: if this intent is ambiguous, look here to see if
// there is a single match that is in our package.
- throw new RuntimeException("Intent resolved to different package "
- + ai.applicationInfo.packageName + ": "
- + intent);
+ throw new RuntimeException("Intent in process "
+ + myProc + " resolved to different process "
+ + ai.processName + ": " + intent);
}
intent.setComponent(new ComponentName(
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cb660c7..f9c38f9 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -18,6 +18,9 @@ package android.app;
import android.content.Context;
import android.content.Intent;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.Handler;
@@ -105,7 +108,7 @@ public final class PendingIntent implements Parcelable {
public CanceledException(Exception cause) {
super(cause);
}
- };
+ }
/**
* Callback interface for discovering when a send operation has
@@ -270,6 +273,21 @@ public final class PendingIntent implements Parcelable {
return null;
}
+ private class IntentSenderWrapper extends IntentSender {
+ protected IntentSenderWrapper(IIntentSender target) {
+ super(target);
+ }
+ }
+ /**
+ * Retrieve a IntentSender object that wraps the existing sender of the PendingIntent
+ *
+ * @return Returns a IntentSender object that wraps the sender of PendingIntent
+ *
+ */
+ public IntentSender getIntentSender() {
+ return new IntentSenderWrapper(mTarget);
+ }
+
/**
* Cancel a currently active PendingIntent. Only the original application
* owning an PendingIntent can cancel it.
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9141c4c..3a3a983 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -35,11 +35,6 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -139,9 +134,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private SuggestionsAdapter mSuggestionsAdapter;
// Whether to rewrite queries when selecting suggestions
- // TODO: This is disabled because of problems with persistent selections
- // causing non-user-initiated rewrites.
- private static final boolean REWRITE_QUERIES = false;
+ private static final boolean REWRITE_QUERIES = true;
// The query entered by the user. This is not changed when selecting a suggestion
// that modifies the contents of the text field. But if the user then edits
@@ -153,15 +146,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private final WeakHashMap<String, Drawable> mOutsideDrawablesCache =
new WeakHashMap<String, Drawable>();
- // Objects we keep around for requesting location updates when the dialog is started
- // (and canceling them when the dialog is stopped). We don't actually make use of the
- // updates ourselves here, so the LocationListener is just a dummy which doesn't do
- // anything. We only do this here so that other suggest providers which wish to provide
- // location-based suggestions are more likely to get a good fresh location.
- private LocationManager mLocationManager;
- private LocationProvider mLocationProvider;
- private LocationListener mDummyLocationListener;
-
/**
* Constructor - fires it up and makes it look like the search UI.
*
@@ -240,37 +224,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- mLocationManager =
- (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
-
- if (mLocationManager != null) {
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_COARSE);
-
- String providerName = mLocationManager.getBestProvider(criteria, true);
-
- if (providerName != null) {
- mLocationProvider = mLocationManager.getProvider(providerName);
- }
-
- // Just a dumb listener that doesn't do anything - requesting location updates here
- // is only intended to give location-based suggestion providers the best chance
- // of getting a good fresh location.
- mDummyLocationListener = new LocationListener() {
- public void onLocationChanged(Location location) {
- }
-
- public void onProviderDisabled(String provider) {
- }
-
- public void onProviderEnabled(String provider) {
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
- };
- }
}
/**
@@ -423,8 +376,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// receive broadcasts
getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
-
- startLocationUpdates();
}
/**
@@ -437,8 +388,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
public void onStop() {
super.onStop();
- stopLocationUpdates();
-
// stop receiving broadcasts (throws exception if none registered)
try {
getContext().unregisterReceiver(mBroadcastReceiver);
@@ -456,26 +405,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mUserQuery = null;
mPreviousComponents = null;
}
-
- /**
- * Asks the LocationManager for location updates so that it goes and gets a fresh location
- * if needed.
- */
- private void startLocationUpdates() {
- if (mLocationManager != null && mLocationProvider != null) {
- mLocationManager.requestLocationUpdates(mLocationProvider.getName(),
- 0, 0, mDummyLocationListener, getContext().getMainLooper());
- }
- }
-
- /**
- * Makes sure to stop listening for location updates to save battery.
- */
- private void stopLocationUpdates() {
- mLocationManager.removeUpdates(mDummyLocationListener);
- }
-
/**
* Sets the search dialog to the 'working' state, which shows a working spinner in the
* right hand size of the text field.
@@ -1168,7 +1098,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*/
protected void launchQuerySearch(int actionKey, String actionMsg) {
String query = mSearchAutoComplete.getText().toString();
- Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null,
+ Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
actionKey, actionMsg);
launchIntent(intent);
}
@@ -1238,8 +1168,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// logic for falling back on the searchable default
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
- cv.put(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
- intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
+ cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
+ intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY));
// ensure the icons will work for global search
cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
@@ -1467,11 +1397,14 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
Uri dataUri = (data == null) ? null : Uri.parse(data);
- String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
+ String componentName = getColumnString(
+ c, SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME);
String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
+ String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
- return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
+ return createIntent(action, dataUri, extraData, query, componentName, actionKey,
+ actionMsg);
} catch (RuntimeException e ) {
int rowNum;
try { // be really paranoid now
@@ -1490,16 +1423,17 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*
* @param action Intent action.
* @param data Intent data, or <code>null</code>.
- * @param query Intent query, or <code>null</code>.
* @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>.
+ * @param query Intent query, or <code>null</code>.
+ * @param componentName Data for {@link SearchManager#COMPONENT_NAME_KEY} or <code>null</code>.
* @param actionKey The key code of the action key that was pressed,
* or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
* @param actionMsg The message for the action key that was pressed,
* or <code>null</code> if none.
* @return The intent.
*/
- private Intent createIntent(String action, Uri data, String query, String extraData,
- int actionKey, String actionMsg) {
+ private Intent createIntent(String action, Uri data, String extraData, String query,
+ String componentName, int actionKey, String actionMsg) {
// Now build the Intent
Intent intent = new Intent(action);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -1512,6 +1446,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (extraData != null) {
intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
}
+ if (componentName != null) {
+ intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName);
+ }
if (mAppSearchData != null) {
intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 1ddd20a..eb80400 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1165,6 +1165,14 @@ public class SearchManager
public final static String ACTION_KEY = "action_key";
/**
+ * Intent component name key: This key will be used for the extra populated by the
+ * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
+ *
+ * {@hide}
+ */
+ public final static String COMPONENT_NAME_KEY = "intent_component_name_key";
+
+ /**
* Intent extra data key: This key will be used for the extra populated by the
* {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
*
@@ -1364,14 +1372,24 @@ public class SearchManager
*/
public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
/**
+ * Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
+ * this element exists at the given row, this is the data that will be used when
+ * forming the suggestion's intent. If not provided, the Intent's extra data field will be null.
+ * This column allows suggestions to provide additional arbitrary data which will be included as
+ * an extra under the key EXTRA_DATA_KEY.
+ *
+ * @hide Pending API council approval.
+ */
+ public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ /**
* Column name for suggestions cursor. <i>Optional.</i> This column allows suggestions
* to provide additional arbitrary data which will be included as an extra under the key
- * {@link #EXTRA_DATA_KEY}. For use by the global search system only - if other providers
+ * {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
* attempt to use this column, the value will be overwritten by global search.
*
* @hide
*/
- public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ public final static String SUGGEST_COLUMN_INTENT_COMPONENT_NAME = "suggest_intent_component";
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, then "/" and this value will be appended to the data
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 609dd90..69c206c 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -82,9 +82,9 @@ public class BackupDataInput {
}
}
- public int readEntityData(byte[] data, int size) throws IOException {
+ public int readEntityData(byte[] data, int offset, int size) throws IOException {
if (mHeaderReady) {
- int result = readEntityData_native(mBackupReader, data, size);
+ int result = readEntityData_native(mBackupReader, data, offset, size);
if (result >= 0) {
return result;
} else {
@@ -95,9 +95,23 @@ public class BackupDataInput {
}
}
+ 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));
+ }
+ } else {
+ throw new IllegalStateException("mHeaderReady=false");
+ }
+ }
+
private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupReader);
private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
- private native int readEntityData_native(int mBackupReader, byte[] data, int size);
+ private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size);
+ private native int skipEntityData_native(int mBackupReader);
}
diff --git a/core/java/android/backup/BackupDataInputStream.java b/core/java/android/backup/BackupDataInputStream.java
new file mode 100644
index 0000000..b705c4c
--- /dev/null
+++ b/core/java/android/backup/BackupDataInputStream.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.backup;
+
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/** @hide */
+public class BackupDataInputStream extends InputStream {
+
+ String key;
+ int dataSize;
+
+ BackupDataInput mData;
+ byte[] mOneByte;
+
+ BackupDataInputStream(BackupDataInput data) {
+ mData = data;
+ }
+
+ public int read() throws IOException {
+ byte[] one = mOneByte;
+ if (mOneByte == null) {
+ one = mOneByte = new byte[1];
+ }
+ mData.readEntityData(one, 0, 1);
+ return one[0];
+ }
+
+ public int read(byte[] b, int offset, int size) throws IOException {
+ return mData.readEntityData(b, offset, size);
+ }
+
+ public int read(byte[] b) throws IOException {
+ return mData.readEntityData(b, 0, b.length);
+ }
+
+ public String getKey() {
+ return this.key;
+ }
+
+ public int size() {
+ return this.dataSize;
+ }
+}
+
+
diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java
index 1348d81..05e667e 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -24,13 +24,11 @@ import java.io.IOException;
/** @hide */
public class BackupDataOutput {
int mBackupWriter;
- private Context mContext;
public static final int OP_UPDATE = 1;
public static final int OP_DELETE = 2;
- public BackupDataOutput(Context context, FileDescriptor fd) {
- mContext = context;
+ public BackupDataOutput(FileDescriptor fd) {
if (fd == null) throw new NullPointerException();
mBackupWriter = ctor(fd);
if (mBackupWriter == 0) {
@@ -38,6 +36,7 @@ public class BackupDataOutput {
}
}
+ // A dataSize of -1 indicates that the record under this key should be deleted
public int writeEntityHeader(String key, int dataSize) throws IOException {
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
diff --git a/core/java/android/backup/FileRestoreHelper.java b/core/java/android/backup/FileRestoreHelper.java
new file mode 100644
index 0000000..b7e3625
--- /dev/null
+++ b/core/java/android/backup/FileRestoreHelper.java
@@ -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.
+ */
+
+package android.backup;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.File;
+
+/** @hide */
+public class FileRestoreHelper extends RestoreHelperBase implements RestoreHelper {
+ private static final String TAG = "FileRestoreHelper";
+
+ File mFilesDir;
+
+ public FileRestoreHelper(Context context) {
+ super(context);
+ mFilesDir = context.getFilesDir();
+ }
+
+ public void restoreEntity(BackupDataInputStream data) {
+ Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size()); // TODO: turn this off before ship
+ File f = new File(mFilesDir, data.getKey());
+ writeFile(f, data);
+ }
+}
+
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
index ebd9906..e47869c 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/RestoreHelper.java
@@ -16,8 +16,19 @@
package android.backup;
+import android.os.ParcelFileDescriptor;
+
+import java.io.InputStream;
+
/** @hide */
public interface RestoreHelper {
- public void performRestore();
+ /**
+ * Called by RestoreHelperDispatcher to dispatch one entity of data.
+ * <p class=note>
+ * Do not close the <code>data</code> stream. Do not read more than
+ * <code>dataSize</code> bytes from <code>data</code>.
+ */
+ public void restoreEntity(BackupDataInputStream data);
+ public void writeSnapshot(ParcelFileDescriptor fd);
}
diff --git a/core/java/android/backup/RestoreHelperBase.java b/core/java/android/backup/RestoreHelperBase.java
new file mode 100644
index 0000000..93a8fef
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperBase.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.backup;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+
+class RestoreHelperBase {
+ private static final String TAG = "RestoreHelperBase";
+
+ int mPtr;
+ Context mContext;
+ boolean mExceptionLogged;
+
+ RestoreHelperBase(Context context) {
+ mPtr = ctor();
+ mContext = context;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ dtor(mPtr);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ void writeFile(File f, InputStream in) {
+ if (!(in instanceof BackupDataInputStream)) {
+ throw new IllegalStateException("input stream must be a BackupDataInputStream");
+ }
+ int result = -1;
+
+ // Create the enclosing directory.
+ File parent = f.getParentFile();
+ parent.mkdirs();
+
+ result = writeFile_native(mPtr, f.getAbsolutePath(),
+ ((BackupDataInputStream)in).mData.mBackupReader);
+ if (result != 0) {
+ // Bail on this entity. Only log one failure per helper object.
+ if (!mExceptionLogged) {
+ Log.e(TAG, "Failed restoring file '" + f + "' for app '"
+ + mContext.getPackageName() + "\' result=0x"
+ + Integer.toHexString(result));
+ mExceptionLogged = true;
+ }
+ }
+ }
+
+ public void writeSnapshot(ParcelFileDescriptor fd) {
+ int result = writeSnapshot_native(mPtr, fd.getFileDescriptor());
+ // TODO: Do something with the error.
+ }
+
+ private static native int ctor();
+ private static native void dtor(int ptr);
+ private static native int writeFile_native(int ptr, String filename, int backupReader);
+ private static native int writeSnapshot_native(int ptr, FileDescriptor fd);
+}
+
+
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
new file mode 100644
index 0000000..4861775
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperDispatcher.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.backup;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/** @hide */
+public class RestoreHelperDispatcher {
+ private static final String TAG = "RestoreHelperDispatcher";
+
+ HashMap<String,RestoreHelper> mHelpers = new HashMap<String,RestoreHelper>();
+
+ public void addHelper(String keyPrefix, RestoreHelper helper) {
+ mHelpers.put(keyPrefix, helper);
+ }
+
+ public void dispatch(BackupDataInput input, ParcelFileDescriptor newState) throws IOException {
+ boolean alreadyComplained = false;
+
+ BackupDataInputStream stream = new BackupDataInputStream(input);
+ while (input.readNextHeader()) {
+
+ String rawKey = input.getKey();
+ int pos = rawKey.indexOf(':');
+ if (pos > 0) {
+ String prefix = rawKey.substring(0, pos);
+ RestoreHelper helper = mHelpers.get(prefix);
+ if (helper != null) {
+ stream.dataSize = input.getDataSize();
+ stream.key = rawKey.substring(pos+1);
+ helper.restoreEntity(stream);
+ } else {
+ if (!alreadyComplained) {
+ Log.w(TAG, "Couldn't find helper for: '" + rawKey + "'");
+ alreadyComplained = true;
+ }
+ }
+ } else {
+ if (!alreadyComplained) {
+ Log.w(TAG, "Entity with no prefix: '" + rawKey + "'");
+ alreadyComplained = true;
+ }
+ }
+ input.skipEntityData(); // In case they didn't consume the data.
+ }
+
+ if (mHelpers.size() > 1) {
+ throw new RuntimeException("RestoreHelperDispatcher won't get your your"
+ + " data in the right order yet.");
+ }
+
+ // Write out the state files
+ for (RestoreHelper helper: mHelpers.values()) {
+ // TODO: Write a header for the state
+ helper.writeSnapshot(newState);
+ }
+ }
+}
+
diff --git a/core/java/android/backup/RestoreSet.java b/core/java/android/backup/RestoreSet.java
index 7f09af3..96a99ae 100644
--- a/core/java/android/backup/RestoreSet.java
+++ b/core/java/android/backup/RestoreSet.java
@@ -46,11 +46,11 @@ public class RestoreSet implements Parcelable {
public int token;
- RestoreSet() {
+ public RestoreSet() {
// Leave everything zero / null
}
- RestoreSet(String _name, String _dev, int _token) {
+ public RestoreSet(String _name, String _dev, int _token) {
name = _name;
device = _dev;
token = _token;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index e198435..fe1e09a 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -332,6 +332,31 @@ public class BluetoothHeadset {
}
/**
+ * Get battery usage hint for Bluetooth Headset service.
+ * This is a monotonically increasing integer. Wraps to 0 at
+ * Integer.MAX_INT, and at boot.
+ * Current implementation returns the number of AT commands handled since
+ * boot. This is a good indicator for spammy headset/handsfree units that
+ * can keep the device awake by polling for cellular status updates. As a
+ * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
+ * @return monotonically increasing battery usage hint, or a negative error
+ * code on error
+ * @hide
+ */
+ public int getBatteryUsageHint() {
+ if (DBG) log("getBatteryUsageHint()");
+ if (mService != null) {
+ try {
+ return mService.getBatteryUsageHint();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return -1;
+ }
+
+ /**
* Check class bits for possible HSP or HFP support.
* This is a simple heuristic that tries to guess if a device with the
* given class bits might support HSP or HFP. It is not accurate for all
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
index e6f501c..c060f32 100644
--- a/core/java/android/bluetooth/BluetoothInputStream.java
+++ b/core/java/android/bluetooth/BluetoothInputStream.java
@@ -59,7 +59,7 @@ import java.io.InputStream;
byte b[] = new byte[1];
int ret = mSocket.readNative(b, 0, 1);
if (ret == 1) {
- return (int)b[0];
+ return (int)b[0] & 0xff;
} else {
return -1;
}
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index f31e7a2..f987ffd 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -40,6 +40,8 @@ public class HeadsetBase {
public static final int DIRECTION_INCOMING = 1;
public static final int DIRECTION_OUTGOING = 2;
+ private static int sAtInputCount = 0; /* TODO: Consider not using a static variable */
+
private final BluetoothDevice mBluetooth;
private final String mAddress;
private final int mRfcommChannel;
@@ -109,6 +111,14 @@ public class HeadsetBase {
acquireWakeLock();
long timestamp;
+ synchronized(HeadsetBase.class) {
+ if (sAtInputCount == Integer.MAX_VALUE) {
+ sAtInputCount = 0;
+ } else {
+ sAtInputCount++;
+ }
+ }
+
if (DBG) timestamp = System.currentTimeMillis();
AtCommandResult result = mAtParser.process(input);
if (DBG) Log.d(TAG, "Processing " + input + " took " +
@@ -279,7 +289,11 @@ public class HeadsetBase {
}
}
- private void log(String msg) {
+ public static int getAtInputCount() {
+ return sAtInputCount;
+ }
+
+ private static void log(String msg) {
Log.d(TAG, msg);
}
}
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 582d4e3..5f42fd6 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -31,4 +31,5 @@ interface IBluetoothHeadset {
boolean stopVoiceRecognition();
boolean setPriority(in String address, int priority);
int getPriority(in String address);
+ int getBatteryUsageHint();
}
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/Context.java b/core/java/android/content/Context.java
index 4ccbf18..6c8bafc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
@@ -233,6 +234,9 @@ public abstract class Context {
/** Return the name of this application's package. */
public abstract String getPackageName();
+ /** Return the full application info for this context's package. */
+ public abstract ApplicationInfo getApplicationInfo();
+
/**
* {@hide}
* Return the full path to this context's resource files. This is the ZIP files
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 262204e..7513b3b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
@@ -120,6 +121,11 @@ public class ContextWrapper extends Context {
}
@Override
+ public ApplicationInfo getApplicationInfo() {
+ return mBase.getApplicationInfo();
+ }
+
+ @Override
public String getPackageResourcePath() {
return mBase.getPackageResourcePath();
}
diff --git a/core/java/android/content/IIntentReceiver.aidl b/core/java/android/content/IIntentReceiver.aidl
new file mode 100755
index 0000000..443db2d
--- /dev/null
+++ b/core/java/android/content/IIntentReceiver.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.content;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * System private API for dispatching intent broadcasts. This is given to the
+ * activity manager as part of registering for an intent broadcasts, and is
+ * called when it receives intents.
+ *
+ * {@hide}
+ */
+oneway interface IIntentReceiver {
+ void performReceive(in Intent intent, int resultCode,
+ String data, in Bundle extras, boolean ordered);
+}
+
diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/content/IIntentSender.aidl
index 555ca79..b7da472 100644
--- a/core/java/android/backup/RestoreHelperDistributor.java
+++ b/core/java/android/content/IIntentSender.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package android.backup;
+package android.content;
-import java.util.HashMap;
+import android.content.IIntentReceiver;
+import android.content.Intent;
/** @hide */
-public class RestoreHelperDistributor {
- HashMap<String,RestoreHelper> mHelpers;
-
- public void addHelper(String keyPrefix, RestoreHelper helper) {
- mHelpers.put(keyPrefix, helper);
- }
+interface IIntentSender {
+ int send(int code, in Intent intent, String resolvedType,
+ IIntentReceiver finishedReceiver);
}
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index d228605..4660527 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -31,14 +31,17 @@ oneway interface ISyncAdapter {
*
* @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, in Account 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 0e6be0a..33e769e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -240,35 +240,35 @@ import java.util.Set;
*
* &lt;activity class=".NotesList" android:label="@string/title_notes_list"&gt;
* &lt;intent-filter&gt;
- * &lt;action android:value="android.intent.action.MAIN" /&gt;
- * &lt;category android:value="android.intent.category.LAUNCHER" /&gt;
+ * &lt;action android:name="android.intent.action.MAIN" /&gt;
+ * &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
* &lt;/intent-filter&gt;
* &lt;intent-filter&gt;
- * &lt;action android:value="android.intent.action.VIEW" /&gt;
- * &lt;action android:value="android.intent.action.EDIT" /&gt;
- * &lt;action android:value="android.intent.action.PICK" /&gt;
- * &lt;category android:value="android.intent.category.DEFAULT" /&gt;
- * &lt;type android:value="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="android.intent.action.VIEW" /&gt;
+ * &lt;action android:name="android.intent.action.EDIT" /&gt;
+ * &lt;action android:name="android.intent.action.PICK" /&gt;
+ * &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;
* &lt;intent-filter&gt;
- * &lt;action android:value="android.intent.action.GET_CONTENT" /&gt;
- * &lt;category android:value="android.intent.category.DEFAULT" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="android.intent.action.GET_CONTENT" /&gt;
+ * &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;
* &lt;/activity&gt;
*
* &lt;activity class=".NoteEditor" android:label="@string/title_note"&gt;
* &lt;intent-filter android:label="@string/resolve_edit"&gt;
- * &lt;action android:value="android.intent.action.VIEW" /&gt;
- * &lt;action android:value="android.intent.action.EDIT" /&gt;
- * &lt;category android:value="android.intent.category.DEFAULT" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="android.intent.action.VIEW" /&gt;
+ * &lt;action android:name="android.intent.action.EDIT" /&gt;
+ * &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;
*
* &lt;intent-filter&gt;
- * &lt;action android:value="android.intent.action.INSERT" /&gt;
- * &lt;category android:value="android.intent.category.DEFAULT" /&gt;
- * &lt;type android:value="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="android.intent.action.INSERT" /&gt;
+ * &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;
*
* &lt;/activity&gt;
@@ -276,11 +276,11 @@ import java.util.Set;
* &lt;activity class=".TitleEditor" android:label="@string/title_edit_title"
* android:theme="@android:style/Theme.Dialog"&gt;
* &lt;intent-filter android:label="@string/resolve_title"&gt;
- * &lt;action android:value="<i>com.android.notepad.action.EDIT_TITLE</i>" /&gt;
- * &lt;category android:value="android.intent.category.DEFAULT" /&gt;
- * &lt;category android:value="android.intent.category.ALTERNATIVE" /&gt;
- * &lt;category android:value="android.intent.category.SELECTED_ALTERNATIVE" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="<i>com.android.notepad.action.EDIT_TITLE</i>" /&gt;
+ * &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+ * &lt;category android:name="android.intent.category.ALTERNATIVE" /&gt;
+ * &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;
* &lt;/activity&gt;
*
@@ -294,8 +294,8 @@ import java.util.Set;
* <ol>
* <li><pre>
* &lt;intent-filter&gt;
- * &lt;action android:value="{@link #ACTION_MAIN android.intent.action.MAIN}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_LAUNCHER android.intent.category.LAUNCHER}" /&gt;
+ * &lt;action android:name="{@link #ACTION_MAIN android.intent.action.MAIN}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_LAUNCHER android.intent.category.LAUNCHER}" /&gt;
* &lt;/intent-filter&gt;</pre>
* <p>This provides a top-level entry into the NotePad application: the standard
* MAIN action is a main entry point (not requiring any other information in
@@ -303,11 +303,11 @@ import java.util.Set;
* listed in the application launcher.</p>
* <li><pre>
* &lt;intent-filter&gt;
- * &lt;action android:value="{@link #ACTION_VIEW android.intent.action.VIEW}" /&gt;
- * &lt;action android:value="{@link #ACTION_EDIT android.intent.action.EDIT}" /&gt;
- * &lt;action android:value="{@link #ACTION_PICK android.intent.action.PICK}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
- * &lt;type android:value="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="{@link #ACTION_VIEW android.intent.action.VIEW}" /&gt;
+ * &lt;action android:name="{@link #ACTION_EDIT android.intent.action.EDIT}" /&gt;
+ * &lt;action android:name="{@link #ACTION_PICK android.intent.action.PICK}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
+ * &lt;data mimeType:name="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;</pre>
* <p>This declares the things that the activity can do on a directory of
* notes. The type being supported is given with the &lt;type&gt; tag, where
@@ -322,9 +322,9 @@ import java.util.Set;
* activity when its component name is not explicitly specified.</p>
* <li><pre>
* &lt;intent-filter&gt;
- * &lt;action android:value="{@link #ACTION_GET_CONTENT android.intent.action.GET_CONTENT}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="{@link #ACTION_GET_CONTENT android.intent.action.GET_CONTENT}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;</pre>
* <p>This filter describes the ability return to the caller a note selected by
* the user without needing to know where it came from. The data type
@@ -371,10 +371,10 @@ import java.util.Set;
* <ol>
* <li><pre>
* &lt;intent-filter android:label="@string/resolve_edit"&gt;
- * &lt;action android:value="{@link #ACTION_VIEW android.intent.action.VIEW}" /&gt;
- * &lt;action android:value="{@link #ACTION_EDIT android.intent.action.EDIT}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="{@link #ACTION_VIEW android.intent.action.VIEW}" /&gt;
+ * &lt;action android:name="{@link #ACTION_EDIT android.intent.action.EDIT}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;</pre>
* <p>The first, primary, purpose of this activity is to let the user interact
* with a single note, as decribed by the MIME type
@@ -384,9 +384,9 @@ import java.util.Set;
* specifying its component.</p>
* <li><pre>
* &lt;intent-filter&gt;
- * &lt;action android:value="{@link #ACTION_INSERT android.intent.action.INSERT}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
- * &lt;type android:value="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="{@link #ACTION_INSERT android.intent.action.INSERT}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.dir/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;</pre>
* <p>The secondary use of this activity is to insert a new note entry into
* an existing directory of notes. This is used when the user creates a new
@@ -422,11 +422,11 @@ import java.util.Set;
*
* <pre>
* &lt;intent-filter android:label="@string/resolve_title"&gt;
- * &lt;action android:value="<i>com.android.notepad.action.EDIT_TITLE</i>" /&gt;
- * &lt;category android:value="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_ALTERNATIVE android.intent.category.ALTERNATIVE}" /&gt;
- * &lt;category android:value="{@link #CATEGORY_SELECTED_ALTERNATIVE android.intent.category.SELECTED_ALTERNATIVE}" /&gt;
- * &lt;type android:value="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
+ * &lt;action android:name="<i>com.android.notepad.action.EDIT_TITLE</i>" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_DEFAULT android.intent.category.DEFAULT}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_ALTERNATIVE android.intent.category.ALTERNATIVE}" /&gt;
+ * &lt;category android:name="{@link #CATEGORY_SELECTED_ALTERNATIVE android.intent.category.SELECTED_ALTERNATIVE}" /&gt;
+ * &lt;data android:mimeType="vnd.android.cursor.item/<i>vnd.google.note</i>" /&gt;
* &lt;/intent-filter&gt;</pre>
*
* <p>In the single intent template here, we
@@ -509,8 +509,8 @@ import java.util.Set;
* <li> {@link #ACTION_UID_REMOVED}
* <li> {@link #ACTION_BATTERY_CHANGED}
* <li> {@link #ACTION_POWER_CONNECTED}
- * <li> {@link #ACTION_POWER_DISCONNECTED}
- * <li> {@link #ACTION_SHUTDOWN}
+ * <li> {@link #ACTION_POWER_DISCONNECTED}
+ * <li> {@link #ACTION_SHUTDOWN}
* </ul>
*
* <h3>Standard Categories</h3>
@@ -915,6 +915,23 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SEND = "android.intent.action.SEND";
/**
+ * Activity Action: Deliver multiple data to someone else.
+ * <p>
+ * Like ACTION_SEND, except the data is multiple.
+ * <p>
+ * Input: {@link #getType} is the MIME type of the data being sent.
+ * get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link
+ * #EXTRA_STREAM} field, containing the data to be sent.
+ * <p>
+ * Optional standard extras, which may be interpreted by some recipients as
+ * appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
+ * {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}.
+ * <p>
+ * Output: nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
+ /**
* Activity Action: Handle an incoming phone call.
* <p>Input: nothing.
* <p>Output: nothing.
@@ -1059,6 +1076,15 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
+
+ /**
+ * Activity Action: Show power usage information to the user.
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
@@ -1277,11 +1303,11 @@ public class Intent implements Parcelable {
* This is intended for applications that wish to register specifically to this notification.
* Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
* stay active to receive this notification. This action can be used to implement actions
- * that wait until power is available to trigger.
+ * that wait until power is available to trigger.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_POWER_DISCONNECTED =
- "android.intent.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
@@ -1290,7 +1316,7 @@ public class Intent implements Parcelable {
* to handle this, since the forground activity will be paused as well.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
+ public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
/**
* Broadcast Action: Indicates low memory condition on the device
*/
@@ -1807,23 +1833,23 @@ public class Intent implements Parcelable {
* delivered.
*/
public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
-
+
/**
* Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
* the bug report.
- *
+ *
* @hide
*/
public static final String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
/**
- * Used as a string extra field when sending an intent to PackageInstaller to install a
+ * Used as a string extra field when sending an intent to PackageInstaller to install a
* package. Specifies the installer package name; this package will receive the
* {@link #ACTION_APP_ERROR} intent.
- *
+ *
* @hide
*/
- public static final String EXTRA_INSTALLER_PACKAGE_NAME
+ public static final String EXTRA_INSTALLER_PACKAGE_NAME
= "android.intent.extra.INSTALLER_PACKAGE_NAME";
/**
@@ -2063,10 +2089,25 @@ public class Intent implements Parcelable {
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000;
// ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // toUri() and parseUri() options.
+
+ /**
+ * Flag for use with {@link #toUri} and {@link #parseUri}: the URI string
+ * always has the "intent:" scheme. This syntax can be used when you want
+ * to later disambiguate between URIs that are intended to describe an
+ * Intent vs. all others that should be treated as raw URIs. When used
+ * with {@link #parseUri}, any other scheme will result in a generic
+ * VIEW action for that raw URI.
+ */
+ public static final int URI_INTENT_SCHEME = 1<<0;
+
+ // ---------------------------------------------------------------------
private String mAction;
private Uri mData;
private String mType;
+ private String mPackage;
private ComponentName mComponent;
private int mFlags;
private HashSet<String> mCategories;
@@ -2087,6 +2128,7 @@ public class Intent implements Parcelable {
this.mAction = o.mAction;
this.mData = o.mData;
this.mType = o.mType;
+ this.mPackage = o.mPackage;
this.mComponent = o.mComponent;
this.mFlags = o.mFlags;
if (o.mCategories != null) {
@@ -2106,6 +2148,7 @@ public class Intent implements Parcelable {
this.mAction = o.mAction;
this.mData = o.mData;
this.mType = o.mType;
+ this.mPackage = o.mPackage;
this.mComponent = o.mComponent;
if (o.mCategories != null) {
this.mCategories = new HashSet<String>(o.mCategories);
@@ -2206,23 +2249,50 @@ public class Intent implements Parcelable {
}
/**
+ * Call {@link #parseUri} with 0 flags.
+ * @deprecated Use {@link #parseUri} instead.
+ */
+ @Deprecated
+ public static Intent getIntent(String uri) throws URISyntaxException {
+ return parseUri(uri, 0);
+ }
+
+ /**
* Create an intent from a URI. This URI may encode the action,
- * category, and other intent fields, if it was returned by toURI(). If
- * the Intent was not generate by toURI(), its data will be the entire URI
- * and its action will be ACTION_VIEW.
+ * category, and other intent fields, if it was returned by
+ * {@link #toUri}.. If the Intent was not generate by toUri(), its data
+ * will be the entire URI and its action will be ACTION_VIEW.
*
* <p>The URI given here must not be relative -- that is, it must include
* the scheme and full path.
*
* @param uri The URI to turn into an Intent.
+ * @param flags Additional processing flags. Either 0 or
*
* @return Intent The newly created Intent object.
*
- * @see #toURI
+ * @throws URISyntaxException Throws URISyntaxError if the basic URI syntax
+ * it bad (as parsed by the Uri class) or the Intent data within the
+ * URI is invalid.
+ *
+ * @see #toUri
*/
- public static Intent getIntent(String uri) throws URISyntaxException {
+ public static Intent parseUri(String uri, int flags) throws URISyntaxException {
int i = 0;
try {
+ // Validate intent scheme for if requested.
+ if ((flags&URI_INTENT_SCHEME) != 0) {
+ if (!uri.startsWith("intent:")) {
+ Intent intent = new Intent(ACTION_VIEW);
+ try {
+ intent.setData(Uri.parse(uri));
+ } catch (IllegalArgumentException e) {
+ throw new URISyntaxException(uri, e.getMessage());
+ }
+ return intent;
+ }
+ }
+
// simple case
i = uri.lastIndexOf("#");
if (i == -1) return new Intent(ACTION_VIEW, Uri.parse(uri));
@@ -2234,16 +2304,15 @@ public class Intent implements Parcelable {
Intent intent = new Intent(ACTION_VIEW);
// fetch data part, if present
- if (i > 0) {
- intent.mData = Uri.parse(uri.substring(0, i));
- }
+ String data = i >= 0 ? uri.substring(0, i) : null;
+ String scheme = null;
i += "#Intent;".length();
// loop over contents of Intent, all name=value;
while (!uri.startsWith("end", i)) {
int eq = uri.indexOf('=', i);
int semi = uri.indexOf(';', eq);
- String value = uri.substring(eq + 1, semi);
+ String value = Uri.decode(uri.substring(eq + 1, semi));
// action
if (uri.startsWith("action=", i)) {
@@ -2265,15 +2334,24 @@ public class Intent implements Parcelable {
intent.mFlags = Integer.decode(value).intValue();
}
+ // package
+ else if (uri.startsWith("package=", i)) {
+ intent.mPackage = value;
+ }
+
// component
else if (uri.startsWith("component=", i)) {
intent.mComponent = ComponentName.unflattenFromString(value);
}
+ // scheme
+ else if (uri.startsWith("scheme=", i)) {
+ scheme = value;
+ }
+
// extra
else {
String key = Uri.decode(uri.substring(i + 2, eq));
- value = Uri.decode(value);
// create Bundle if it doesn't already exist
if (intent.mExtras == null) intent.mExtras = new Bundle();
Bundle b = intent.mExtras;
@@ -2294,6 +2372,23 @@ public class Intent implements Parcelable {
i = semi + 1;
}
+ if (data != null) {
+ if (data.startsWith("intent:")) {
+ data = data.substring(7);
+ if (scheme != null) {
+ data = scheme + ':' + data;
+ }
+ }
+
+ if (data.length() > 0) {
+ try {
+ intent.mData = Uri.parse(data);
+ } catch (IllegalArgumentException e) {
+ throw new URISyntaxException(uri, e.getMessage());
+ }
+ }
+ }
+
return intent;
} catch (IndexOutOfBoundsException e) {
@@ -3107,6 +3202,20 @@ public class Intent implements Parcelable {
}
/**
+ * Retrieve the application package name this Intent is limited to. When
+ * resolving an Intent, if non-null this limits the resolution to only
+ * components in the given application package.
+ *
+ * @return The name of the application package for the Intent.
+ *
+ * @see #resolveActivity
+ * @see #setPackage
+ */
+ public String getPackage() {
+ return mPackage;
+ }
+
+ /**
* Retrieve the concrete component associated with the intent. When receiving
* an intent, this is the component that was found to best handle it (that is,
* yourself) and will always be non-null; in all other cases it will be
@@ -3141,6 +3250,9 @@ public class Intent implements Parcelable {
* <p>If {@link #addCategory} has added any categories, the activity must
* handle ALL of the categories specified.
*
+ * <p>If {@link #getPackage} is non-NULL, only activity components in
+ * that application package will be considered.
+ *
* <p>If there are no activities that satisfy all of these conditions, a
* null string is returned.
*
@@ -3262,7 +3374,7 @@ public class Intent implements Parcelable {
* only specify a type and not data, for example to indicate the type of
* data to return. This method automatically clears any data that was
* previously set by {@link #setData}.
- *
+ *
* <p><em>Note: MIME type matching in the Android framework is
* case-sensitive, unlike formal RFC MIME types. As a result,
* you should always write your MIME types with lower case letters,
@@ -4112,6 +4224,27 @@ public class Intent implements Parcelable {
}
/**
+ * (Usually optional) Set an explicit application package name that limits
+ * the components this Intent will resolve to. If left to the default
+ * value of null, all components in all applications will considered.
+ * If non-null, the Intent can only match the components in the given
+ * application package.
+ *
+ * @param packageName The name of the application package to handle the
+ * intent, or null to allow any application package.
+ *
+ * @return Returns the same Intent object, for chaining multiple calls
+ * into a single statement.
+ *
+ * @see #getPackage
+ * @see #resolveActivity
+ */
+ public Intent setPackage(String packageName) {
+ mPackage = packageName;
+ return this;
+ }
+
+ /**
* (Usually optional) Explicitly set the component to handle the intent.
* If left with the default value of null, the system will determine the
* appropriate class to use based on the other fields (action, data,
@@ -4223,6 +4356,12 @@ public class Intent implements Parcelable {
public static final int FILL_IN_COMPONENT = 1<<3;
/**
+ * Use with {@link #fillIn} to allow the current package value to be
+ * overwritten, even if it is already set.
+ */
+ public static final int FILL_IN_PACKAGE = 1<<4;
+
+ /**
* Copy the contents of <var>other</var> in to this object, but only
* where fields are not defined by this object. For purposes of a field
* being defined, the following pieces of data in the Intent are
@@ -4233,14 +4372,15 @@ public class Intent implements Parcelable {
* <li> data URI and MIME type, as set by {@link #setData(Uri)},
* {@link #setType(String)}, or {@link #setDataAndType(Uri, String)}.
* <li> categories, as set by {@link #addCategory}.
+ * <li> package, as set by {@link #setPackage}.
* <li> component, as set by {@link #setComponent(ComponentName)} or
* related methods.
* <li> each top-level name in the associated extras.
* </ul>
*
* <p>In addition, you can use the {@link #FILL_IN_ACTION},
- * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, and
- * {@link #FILL_IN_COMPONENT} to override the restriction where the
+ * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
+ * and {@link #FILL_IN_COMPONENT} to override the restriction where the
* corresponding field will not be replaced if it is already set.
*
* <p>For example, consider Intent A with {data="foo", categories="bar"}
@@ -4256,32 +4396,39 @@ public class Intent implements Parcelable {
* @param flags Options to control which fields can be filled in.
*
* @return Returns a bit mask of {@link #FILL_IN_ACTION},
- * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, and
- * {@link #FILL_IN_COMPONENT} indicating which fields were changed.
+ * {@link #FILL_IN_DATA}, {@link #FILL_IN_CATEGORIES}, {@link #FILL_IN_PACKAGE},
+ * and {@link #FILL_IN_COMPONENT} indicating which fields were changed.
*/
public int fillIn(Intent other, int flags) {
int changes = 0;
- if ((mAction == null && other.mAction == null)
- || (flags&FILL_IN_ACTION) != 0) {
+ if (other.mAction != null
+ && (mAction == null || (flags&FILL_IN_ACTION) != 0)) {
mAction = other.mAction;
changes |= FILL_IN_ACTION;
}
- if ((mData == null && mType == null &&
- (other.mData != null || other.mType != null))
- || (flags&FILL_IN_DATA) != 0) {
+ if ((other.mData != null || other.mType != null)
+ && ((mData == null && mType == null)
+ || (flags&FILL_IN_DATA) != 0)) {
mData = other.mData;
mType = other.mType;
changes |= FILL_IN_DATA;
}
- if ((mCategories == null && other.mCategories == null)
- || (flags&FILL_IN_CATEGORIES) != 0) {
+ if (other.mCategories != null
+ && (mCategories == null || (flags&FILL_IN_CATEGORIES) != 0)) {
if (other.mCategories != null) {
mCategories = new HashSet<String>(other.mCategories);
}
changes |= FILL_IN_CATEGORIES;
}
- if ((mComponent == null && other.mComponent == null)
- || (flags&FILL_IN_COMPONENT) != 0) {
+ if (other.mPackage != null
+ && (mPackage == null || (flags&FILL_IN_PACKAGE) != 0)) {
+ mPackage = other.mPackage;
+ changes |= FILL_IN_PACKAGE;
+ }
+ // Component is special: it can -only- be set if explicitly allowed,
+ // since otherwise the sender could force the intent somewhere the
+ // originator didn't intend.
+ if (other.mComponent != null && (flags&FILL_IN_COMPONENT) != 0) {
mComponent = other.mComponent;
changes |= FILL_IN_COMPONENT;
}
@@ -4396,6 +4543,17 @@ public class Intent implements Parcelable {
}
}
}
+ if (mPackage != other.mPackage) {
+ if (mPackage != null) {
+ if (!mPackage.equals(other.mPackage)) {
+ return false;
+ }
+ } else {
+ if (!other.mPackage.equals(mPackage)) {
+ return false;
+ }
+ }
+ }
if (mComponent != other.mComponent) {
if (mComponent != null) {
if (!mComponent.equals(other.mComponent)) {
@@ -4441,6 +4599,9 @@ public class Intent implements Parcelable {
if (mType != null) {
code += mType.hashCode();
}
+ if (mPackage != null) {
+ code += mPackage.hashCode();
+ }
if (mComponent != null) {
code += mComponent.hashCode();
}
@@ -4467,7 +4628,7 @@ public class Intent implements Parcelable {
toShortString(b, comp, extras);
return b.toString();
}
-
+
/** @hide */
public void toShortString(StringBuilder b, boolean comp, boolean extras) {
boolean first = true;
@@ -4511,6 +4672,13 @@ public class Intent implements Parcelable {
first = false;
b.append("flg=0x").append(Integer.toHexString(mFlags));
}
+ if (mPackage != null) {
+ if (!first) {
+ b.append(' ');
+ }
+ first = false;
+ b.append("pkg=").append(mPackage);
+ }
if (comp && mComponent != null) {
if (!first) {
b.append(' ');
@@ -4527,28 +4695,87 @@ public class Intent implements Parcelable {
}
}
+ /**
+ * Call {@link #toUri} with 0 flags.
+ * @deprecated Use {@link #toUri} instead.
+ */
+ @Deprecated
public String toURI() {
+ return toUri(0);
+ }
+
+ /**
+ * Convert this Intent into a String holding a URI representation of it.
+ * The returned URI string has been properly URI encoded, so it can be
+ * used with {@link Uri#parse Uri.parse(String)}. The URI contains the
+ * Intent's data as the base URI, with an additional fragment describing
+ * the action, categories, type, flags, package, component, and extras.
+ *
+ * <p>You can convert the returned string back to an Intent with
+ * {@link #getIntent}.
+ *
+ * @param flags Additional operating flags. Either 0 or
+ * {@link #URI_INTENT_SCHEME}.
+ *
+ * @return Returns a URI encoding URI string describing the entire contents
+ * of the Intent.
+ */
+ public String toUri(int flags) {
StringBuilder uri = new StringBuilder(128);
- if (mData != null) uri.append(mData.toString());
+ String scheme = null;
+ if (mData != null) {
+ String data = mData.toString();
+ if ((flags&URI_INTENT_SCHEME) != 0) {
+ final int N = data.length();
+ for (int i=0; i<N; i++) {
+ char c = data.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || c == '.' || c == '-') {
+ continue;
+ }
+ if (c == ':' && i > 0) {
+ // Valid scheme.
+ scheme = data.substring(0, i);
+ uri.append("intent:");
+ data = data.substring(i+1);
+ break;
+ }
+
+ // No scheme.
+ break;
+ }
+ }
+ uri.append(data);
+
+ } else if ((flags&URI_INTENT_SCHEME) != 0) {
+ uri.append("intent:");
+ }
uri.append("#Intent;");
+ if (scheme != null) {
+ uri.append("scheme=").append(scheme).append(';');
+ }
if (mAction != null) {
- uri.append("action=").append(mAction).append(';');
+ uri.append("action=").append(Uri.encode(mAction)).append(';');
}
if (mCategories != null) {
for (String category : mCategories) {
- uri.append("category=").append(category).append(';');
+ uri.append("category=").append(Uri.encode(category)).append(';');
}
}
if (mType != null) {
- uri.append("type=").append(mType).append(';');
+ uri.append("type=").append(Uri.encode(mType, "/")).append(';');
}
if (mFlags != 0) {
uri.append("launchFlags=0x").append(Integer.toHexString(mFlags)).append(';');
}
+ if (mPackage != null) {
+ uri.append("package=").append(Uri.encode(mPackage)).append(';');
+ }
if (mComponent != null) {
- uri.append("component=").append(mComponent.flattenToShortString()).append(';');
+ uri.append("component=").append(Uri.encode(
+ mComponent.flattenToShortString(), "/")).append(';');
}
if (mExtras != null) {
for (String key : mExtras.keySet()) {
@@ -4590,6 +4817,7 @@ public class Intent implements Parcelable {
Uri.writeToParcel(out, mData);
out.writeString(mType);
out.writeInt(mFlags);
+ out.writeString(mPackage);
ComponentName.writeToParcel(mComponent, out);
if (mCategories != null) {
@@ -4623,6 +4851,7 @@ public class Intent implements Parcelable {
mData = Uri.CREATOR.createFromParcel(in);
mType = in.readString();
mFlags = in.readInt();
+ mPackage = in.readString();
mComponent = ComponentName.readFromParcel(in);
int N = in.readInt();
diff --git a/core/java/android/content/IntentSender.aidl b/core/java/android/content/IntentSender.aidl
new file mode 100644
index 0000000..741bc8c
--- /dev/null
+++ b/core/java/android/content/IntentSender.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content;
+
+parcelable IntentSender;
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
new file mode 100644
index 0000000..4da49d9
--- /dev/null
+++ b/core/java/android/content/IntentSender.java
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+package android.content;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IIntentSender;
+import android.content.IIntentReceiver;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AndroidException;
+
+
+/**
+ * A description of an Intent and target action to perform with it.
+ * The returned object can be
+ * handed to other applications so that they can perform the action you
+ * described on your behalf at a later time.
+ *
+ * <p>By giving a IntentSender to another application,
+ * you are granting it the right to perform the operation you have specified
+ * as if the other application was yourself (with the same permissions and
+ * identity). As such, you should be careful about how you build the IntentSender:
+ * often, for example, the base Intent you supply will have the component
+ * name explicitly set to one of your own components, to ensure it is ultimately
+ * sent there and nowhere else.
+ *
+ * <p>A IntentSender itself is simply a reference to a token maintained by
+ * the system describing the original data used to retrieve it. This means
+ * that, even if its owning application's process is killed, the
+ * IntentSender itself will remain usable from other processes that
+ * have been given it. If the creating application later re-retrieves the
+ * same kind of IntentSender (same operation, same Intent action, data,
+ * categories, and components, and same flags), it will receive a IntentSender
+ * representing the same token if that is still valid.
+ *
+ */
+public class IntentSender implements Parcelable {
+ private final IIntentSender mTarget;
+
+ /**
+ * Exception thrown when trying to send through a PendingIntent that
+ * has been canceled or is otherwise no longer able to execute the request.
+ */
+ public static class SendIntentException extends AndroidException {
+ public SendIntentException() {
+ }
+
+ public SendIntentException(String name) {
+ super(name);
+ }
+
+ public SendIntentException(Exception cause) {
+ super(cause);
+ }
+ }
+
+ /**
+ * Callback interface for discovering when a send operation has
+ * completed. Primarily for use with a IntentSender that is
+ * performing a broadcast, this provides the same information as
+ * calling {@link Context#sendOrderedBroadcast(Intent, String,
+ * android.content.BroadcastReceiver, Handler, int, String, Bundle)
+ * Context.sendBroadcast()} with a final BroadcastReceiver.
+ */
+ public interface OnFinished {
+ /**
+ * Called when a send operation as completed.
+ *
+ * @param IntentSender The IntentSender this operation was sent through.
+ * @param intent The original Intent that was sent.
+ * @param resultCode The final result code determined by the send.
+ * @param resultData The final data collected by a broadcast.
+ * @param resultExtras The final extras collected by a broadcast.
+ */
+ void onSendFinished(IntentSender IntentSender, Intent intent,
+ int resultCode, String resultData, Bundle resultExtras);
+ }
+
+ private static class FinishedDispatcher extends IIntentReceiver.Stub
+ implements Runnable {
+ private final IntentSender mIntentSender;
+ private final OnFinished mWho;
+ private final Handler mHandler;
+ private Intent mIntent;
+ private int mResultCode;
+ private String mResultData;
+ private Bundle mResultExtras;
+ FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler) {
+ mIntentSender = pi;
+ mWho = who;
+ mHandler = handler;
+ }
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean serialized) {
+ mIntent = intent;
+ mResultCode = resultCode;
+ mResultData = data;
+ mResultExtras = extras;
+ if (mHandler == null) {
+ run();
+ } else {
+ mHandler.post(this);
+ }
+ }
+ public void run() {
+ mWho.onSendFinished(mIntentSender, mIntent, mResultCode,
+ mResultData, mResultExtras);
+ }
+ }
+
+ /**
+ * Perform the operation associated with this IntentSender, allowing the
+ * caller to specify information about the Intent to use and be notified
+ * when the send has completed.
+ *
+ * @param context The Context of the caller. This may be null if
+ * <var>intent</var> is also null.
+ * @param code Result code to supply back to the IntentSender's target.
+ * @param intent Additional Intent data. See {@link Intent#fillIn
+ * Intent.fillIn()} for information on how this is applied to the
+ * original Intent. Use null to not modify the original Intent.
+ * @param onFinished The object to call back on when the send has
+ * completed, or null for no callback.
+ * @param handler Handler identifying the thread on which the callback
+ * should happen. If null, the callback will happen from the thread
+ * pool of the process.
+ *
+ *
+ * @throws SendIntentException Throws CanceledIntentException if the IntentSender
+ * is no longer allowing more intents to be sent through it.
+ */
+ public void sendIntent(Context context, int code, Intent intent,
+ OnFinished onFinished, Handler handler) throws SendIntentException {
+ try {
+ String resolvedType = intent != null ?
+ intent.resolveTypeIfNeeded(context.getContentResolver())
+ : null;
+ int res = mTarget.send(code, intent, resolvedType,
+ onFinished != null
+ ? new FinishedDispatcher(this, onFinished, handler)
+ : null);
+ if (res < 0) {
+ throw new SendIntentException();
+ }
+ } catch (RemoteException e) {
+ throw new SendIntentException();
+ }
+ }
+
+ /**
+ * Comparison operator on two IntentSender objects, such that true
+ * is returned then they both represent the same operation from the
+ * same package.
+ */
+ @Override
+ public boolean equals(Object otherObj) {
+ if (otherObj instanceof IntentSender) {
+ return mTarget.asBinder().equals(((IntentSender)otherObj)
+ .mTarget.asBinder());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mTarget.asBinder().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("IntentSender{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(": ");
+ sb.append(mTarget != null ? mTarget.asBinder() : null);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeStrongBinder(mTarget.asBinder());
+ }
+
+ public static final Parcelable.Creator<IntentSender> CREATOR
+ = new Parcelable.Creator<IntentSender>() {
+ public IntentSender createFromParcel(Parcel in) {
+ IBinder target = in.readStrongBinder();
+ return target != null ? new IntentSender(target) : null;
+ }
+
+ public IntentSender[] newArray(int size) {
+ return new IntentSender[size];
+ }
+ };
+
+ /**
+ * Convenience function for writing either a IntentSender or null pointer to
+ * a Parcel. You must use this with {@link #readIntentSenderOrNullFromParcel}
+ * for later reading it.
+ *
+ * @param sender The IntentSender to write, or null.
+ * @param out Where to write the IntentSender.
+ */
+ public static void writeIntentSenderOrNullToParcel(IntentSender sender,
+ Parcel out) {
+ out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
+ : null);
+ }
+
+ /**
+ * Convenience function for reading either a Messenger or null pointer from
+ * a Parcel. You must have previously written the Messenger with
+ * {@link #writeIntentSenderOrNullToParcel}.
+ *
+ * @param in The Parcel containing the written Messenger.
+ *
+ * @return Returns the Messenger read from the Parcel, or null if null had
+ * been written.
+ */
+ public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
+ IBinder b = in.readStrongBinder();
+ return b != null ? new IntentSender(b) : null;
+ }
+
+ protected IntentSender(IIntentSender target) {
+ mTarget = target;
+ }
+
+ protected IntentSender(IBinder target) {
+ mTarget = IIntentSender.Stub.asInterface(target);
+ }
+}
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index c658fb7..1d5ade1 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -30,12 +30,12 @@ public abstract class SyncAdapter {
public static final int LOG_SYNC_DETAILS = 2743;
class Transport extends ISyncAdapter.Stub {
- public void startSync(ISyncContext syncContext, Account 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();
}
}
diff --git a/core/java/android/content/SyncAdapterNew.java b/core/java/android/content/SyncAdapterNew.java
deleted file mode 100644
index 5b23395..0000000
--- a/core/java/android/content/SyncAdapterNew.java
+++ /dev/null
@@ -1,135 +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.
- */
-
-package android.content;
-
-import android.os.*;
-import android.os.Process;
-import android.accounts.Account;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @hide
- */
-public abstract class SyncAdapterNew {
- private static final String TAG = "SyncAdapter";
- private final Context mContext;
- private final String mAuthority;
-
- /** Kernel event log tag. Also listed in data/etc/event-log-tags. */
- public static final int LOG_SYNC_DETAILS = 2743;
-
- public SyncAdapterNew(Context context, String authority) {
- mContext = context;
- mAuthority = authority;
- }
-
- class Transport extends ISyncAdapter.Stub {
- private final AtomicInteger mNumSyncStarts = new AtomicInteger(0);
- private volatile Thread mSyncThread;
-
- public void startSync(ISyncContext syncContext, Account account, Bundle extras) {
- boolean alreadyInProgress;
- synchronized (this) {
- if (mSyncThread == null) {
- mSyncThread = new Thread(
- new SyncRunnable(new SyncContext(syncContext), account, extras),
- "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet());
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- mSyncThread.start();
- alreadyInProgress = false;
- } else {
- alreadyInProgress = true;
- }
- }
-
- if (alreadyInProgress) {
- try {
- syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
- } catch (RemoteException e) {
- // don't care if the caller is no longer around
- }
- }
- }
-
- public void cancelSync() {
- synchronized (this) {
- if (mSyncThread != null) {
- mSyncThread.interrupt();
- }
- }
- }
-
- private class SyncRunnable implements Runnable {
- private final SyncContext mSyncContext;
- private final Account mAccount;
- private final Bundle mExtras;
-
- private SyncRunnable(SyncContext syncContext, Account account, Bundle extras) {
- mSyncContext = syncContext;
- mAccount = account;
- mExtras = extras;
- }
-
- public void run() {
- if (isCanceled()) {
- return;
- }
-
- SyncResult syncResult = new SyncResult();
- ContentProviderClient provider = mAuthority != null
- ? mContext.getContentResolver().acquireContentProviderClient(mAuthority)
- : null;
- try {
- SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult);
- } finally {
- if (provider != null) {
- provider.release();
- }
- if (!isCanceled()) {
- mSyncContext.onFinished(syncResult);
- }
- mSyncThread = null;
- }
- }
-
- private boolean isCanceled() {
- return Thread.currentThread().isInterrupted();
- }
- }
- }
-
- Transport mTransport = new Transport();
-
- /**
- * Get the Transport object.
- */
- public final ISyncAdapter getISyncAdapter() {
- return mTransport;
- }
-
- /**
- * 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
- */
- public abstract void performSync(Account account, Bundle extras,
- ContentProviderClient provider, SyncResult syncResult);
-} \ No newline at end of file
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index cba02aa..c7954a5 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -33,8 +33,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.RegisteredServicesCache;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -50,10 +48,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.provider.Sync;
import android.provider.Settings;
-import android.provider.Sync.History;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Config;
@@ -77,8 +72,6 @@ import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Random;
-import java.util.Observer;
-import java.util.Observable;
import java.util.Set;
/**
@@ -1435,7 +1428,7 @@ class SyncManager implements OnAccountsUpdatedListener {
// outstanding
if (mActiveSyncContext.mSyncAdapter != null) {
try {
- mActiveSyncContext.mSyncAdapter.cancelSync();
+ mActiveSyncContext.mSyncAdapter.cancelSync(mActiveSyncContext);
} catch (RemoteException e) {
// we don't need to retry this in this case
}
@@ -1678,8 +1671,8 @@ class SyncManager implements OnAccountsUpdatedListener {
mActiveSyncContext.mSyncAdapter = syncAdapter;
final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation;
try {
- syncAdapter.startSync(mActiveSyncContext, syncOperation.account,
- syncOperation.extras);
+ syncAdapter.startSync(mActiveSyncContext, syncOperation.authority,
+ syncOperation.account, syncOperation.extras);
} catch (RemoteException remoteExc) {
if (Config.LOGD) {
Log.d(TAG, "runStateIdle: caught a RemoteException, rescheduling", remoteExc);
@@ -1742,7 +1735,7 @@ class SyncManager implements OnAccountsUpdatedListener {
}
if (activeSyncContext.mSyncAdapter != null) {
try {
- activeSyncContext.mSyncAdapter.cancelSync();
+ activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
} catch (RemoteException e) {
// we don't need to retry this in this case
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f10dd53..2a2cf93 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -137,6 +137,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_TEST_ONLY = 1<<8;
/**
+ * Value for {@link #flags}: true when the application's window can be
+ * expanded over default window size in target density (320x480 for
+ * 1.0 density, 480x720 for 1.5 density etc)
+ */
+ public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<9;
+
+ /**
* Value for {@link #flags}: this is false if the application has set
* its android:allowBackup to false, true otherwise.
*
@@ -201,12 +208,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int[] supportsDensities;
/**
- * True when the application's window can be expanded over default window
- * size in target density (320x480 for 1.0 density, 480x720 for 1.5 density etc)
- */
- public boolean expandable = false;
-
- /**
* The minimum SDK version this application targets. It may run on earilier
* versions, but it knows how to work with any new behavior added at this
* version. Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
@@ -240,7 +241,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
pw.println(prefix + "supportsDensities=" + supportsDensities);
- pw.println(prefix + "expandable=" + expandable);
super.dumpBack(pw, prefix);
}
@@ -288,7 +288,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
supportsDensities = orig.supportsDensities;
- expandable = orig.expandable;
}
@@ -321,7 +320,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
dest.writeIntArray(supportsDensities);
- dest.writeInt(expandable ? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -353,7 +351,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
backupAgentName = source.readString();
descriptionRes = source.readInt();
supportsDensities = source.createIntArray();
- expandable = source.readInt() != 0;
}
/**
@@ -383,7 +380,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* @hide
*/
public void disableCompatibilityMode() {
- expandable = true;
+ flags |= FLAG_SUPPORTS_LARGE_SCREENS;
supportsDensities = ANY_DENSITIES_ARRAY;
}
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9eca4a5..68f8417 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -34,7 +34,7 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
-import android.app.PendingIntent;
+import android.content.IntentSender;
/**
* See {@link PackageManager} for documentation on most of the APIs
@@ -81,9 +81,6 @@ interface IPackageManager {
ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags);
- ResolveInfo resolveIntentForPackage(in Intent intent, String resolvedType, int flags,
- String packageName);
-
List<ResolveInfo> queryIntentActivities(in Intent intent,
String resolvedType, int flags);
@@ -238,12 +235,12 @@ interface IPackageManager {
* and the current free storage is YY,
* if XX is less than YY, just return. if not free XX-YY number
* of bytes if possible.
- * @param opFinishedIntent PendingIntent call back used to
+ * @param pi IntentSender call back used to
* notify when the operation is completed.May be null
* to indicate that no call back is desired.
*/
void freeStorage(in long freeStorageSize,
- in PendingIntent opFinishedIntent);
+ in IntentSender pi);
/**
* Delete all the cache files in an applications cache directory
@@ -280,4 +277,11 @@ interface IPackageManager {
boolean isSafeMode();
void systemReady();
boolean hasSystemUidErrors();
+
+ /**
+ * Ask the package manager to perform dex-opt (if needed) on the given
+ * package, if it already hasn't done mode. Only does this if running
+ * in the special development "no pre-dexopt" mode.
+ */
+ boolean performDexOpt(String packageName);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 88eccf7..3250a87 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,12 +16,11 @@
package android.content.pm;
-
-import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -180,12 +179,6 @@ public abstract class PackageManager {
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
/**
- * {@link ApplicationInfo} flag: return the
- * {link ApplicationInfo#expandable} boolean flag of the package.
- */
- public static final int GET_EXPANDABLE = 0x00020000;
-
- /**
* Permission check result: this is returned by {@link #checkPermission}
* if the permission has been granted to the given package.
*/
@@ -985,23 +978,6 @@ public abstract class PackageManager {
public abstract ResolveInfo resolveActivity(Intent intent, int flags);
/**
- * Resolve the intent restricted to a package.
- * {@see #resolveActivity}
- *
- * @param intent An intent containing all of the desired specification
- * (action, data, type, category, and/or component).
- * @param flags Additional option flags. The most important is
- * MATCH_DEFAULT_ONLY, to limit the resolution to only
- * those activities that support the CATEGORY_DEFAULT.
- * @param packageName Restrict the intent resolution to this package.
- *
- * @return Returns a ResolveInfo containing the final activity intent that
- * was determined to be the best action. Returns null if no
- * matching activity was found.
- */
- public abstract ResolveInfo resolveActivity(Intent intent, int flags, String packageName);
-
- /**
* Retrieve all activities that can be performed for the given intent.
*
* @param intent The desired intent as per resolveActivity().
@@ -1520,7 +1496,7 @@ public abstract class PackageManager {
* @hide
*/
public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
-
+
/**
* Free storage by deleting LRU sorted list of cache files across
* all applications. If the currently available free storage
@@ -1538,13 +1514,13 @@ public abstract class PackageManager {
* and the current free storage is YY,
* if XX is less than YY, just return. if not free XX-YY number
* of bytes if possible.
- * @param opFinishedIntent PendingIntent call back used to
+ * @param pi IntentSender call back used to
* notify when the operation is completed.May be null
* to indicate that no call back is desired.
*
* @hide
*/
- public abstract void freeStorage(long freeStorageSize, PendingIntent opFinishedIntent);
+ public abstract void freeStorage(long freeStorageSize, IntentSender pi);
/**
* Retrieve the size information for a package.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab8559c..ab9518e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -777,7 +777,7 @@ public class PackageParser {
targetCode = minCode = val.string.toString();
} else {
// If it's not a string, it's an integer.
- minVers = val.data;
+ targetVers = minVers = val.data;
}
}
@@ -798,6 +798,25 @@ public class PackageParser {
sa.recycle();
+ if (minCode != null) {
+ if (!minCode.equals(mSdkCodename)) {
+ if (mSdkCodename != null) {
+ outError[0] = "Requires development platform " + minCode
+ + " (current platform is " + mSdkCodename + ")";
+ } else {
+ outError[0] = "Requires development platform " + minCode
+ + " but this is a release platform.";
+ }
+ mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+ return null;
+ }
+ } else if (minVers > mSdkVersion) {
+ outError[0] = "Requires newer sdk version #" + minVers
+ + " (current version is #" + mSdkVersion + ")";
+ mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+ return null;
+ }
+
if (targetCode != null) {
if (!targetCode.equals(mSdkCodename)) {
if (mSdkCodename != null) {
@@ -817,13 +836,6 @@ public class PackageParser {
pkg.applicationInfo.targetSdkVersion = targetVers;
}
- if (minVers > mSdkVersion) {
- outError[0] = "Requires newer sdk version #" + minVers
- + " (current version is #" + mSdkVersion + ")";
- mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
- return null;
- }
-
if (maxVers < mSdkVersion) {
outError[0] = "Requires older sdk version #" + maxVers
+ " (current version is #" + mSdkVersion + ")";
@@ -865,7 +877,7 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("expandable")) {
- pkg.expandable = true;
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
XmlUtils.skipCurrentTag(parser);
} else {
Log.w(TAG, "Bad element under <manifest>: "
@@ -2262,9 +2274,6 @@ public class PackageParser {
public final ArrayList<Integer> supportsDensityList = new ArrayList<Integer>();
public int[] supportsDensities = null;
- // If the application's window is expandable.
- public boolean expandable;
-
// If this is a 3rd party app, this is the path of the zip file.
public String mPath;
@@ -2287,6 +2296,17 @@ public class PackageParser {
// preferred up order.
public int mPreferredOrder = 0;
+ // For use by package manager service to keep track of which apps
+ // have been installed with forward locking.
+ public boolean mForwardLocked;
+
+ // For use by the package manager to keep track of the path to the
+ // file an app came from.
+ public String mScanPath;
+
+ // For use by package manager to keep track of where it has done dexopt.
+ public boolean mDidDexOpt;
+
// Additional data supplied by callers.
public Object mExtras;
@@ -2439,9 +2459,6 @@ public class PackageParser {
&& p.supportsDensities != null) {
return true;
}
- if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
- return true;
- }
return false;
}
@@ -2462,9 +2479,6 @@ public class PackageParser {
if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
ai.supportsDensities = p.supportsDensities;
}
- if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
- ai.expandable = p.expandable;
- }
return ai;
}
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 836de39..680fef8 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -69,7 +69,8 @@ public class CompatibilityInfo {
public final boolean mScalingRequired;
public CompatibilityInfo(ApplicationInfo appInfo) {
- mExpandable = mConfiguredExpandable = appInfo.expandable;
+ mExpandable = mConfiguredExpandable =
+ (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
float packageDensityScale = -1.0f;
if (appInfo.supportsDensities != null) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2f63820..71dbd38 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,11 +22,9 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.app.ActivityThread.PackageInfo;
import android.content.pm.ApplicationInfo;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.SystemProperties;
@@ -35,6 +33,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.util.LongSparseArray;
import java.io.IOException;
import java.io.InputStream;
@@ -59,19 +58,19 @@ public class Resources {
// Information about preloaded resources. Note that they are not
// protected by a lock, because while preloading in zygote we are all
// single-threaded, and after that these are immutable.
- private static final SparseArray<Drawable.ConstantState> sPreloadedDrawables
- = new SparseArray<Drawable.ConstantState>();
+ private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables
+ = new LongSparseArray<Drawable.ConstantState>();
private static final SparseArray<ColorStateList> mPreloadedColorStateLists
= new SparseArray<ColorStateList>();
private static boolean mPreloaded;
- private final SparseArray<Drawable.ConstantState> mPreloadedDrawables;
+ private final LongSparseArray<Drawable.ConstantState> mPreloadedDrawables;
/*package*/ final TypedValue mTmpValue = new TypedValue();
// These are protected by the mTmpValue lock.
- private final SparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
- = new SparseArray<WeakReference<Drawable.ConstantState> >();
+ private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
+ = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache
= new SparseArray<WeakReference<ColorStateList> >();
private boolean mPreloading;
@@ -89,20 +88,20 @@ public class Resources {
private final CompatibilityInfo mCompatibilityInfo;
- private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
+ private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
@Override
- public void put(int k, Object o) {
+ public void put(long k, Object o) {
throw new UnsupportedOperationException();
}
@Override
- public void append(int k, Object o) {
+ public void append(long k, Object o) {
throw new UnsupportedOperationException();
}
};
@SuppressWarnings("unchecked")
- private static <T> SparseArray<T> emptySparseArray() {
- return (SparseArray<T>) EMPTY_ARRAY;
+ private static <T> LongSparseArray<T> emptySparseArray() {
+ return (LongSparseArray<T>) EMPTY_ARRAY;
}
/**
@@ -1315,14 +1314,14 @@ public class Resources {
configChanges, cs.getChangingConfigurations())) {
if (DEBUG_CONFIG) {
Log.d(TAG, "FLUSHING #0x"
- + Integer.toHexString(mDrawableCache.keyAt(i))
+ + Long.toHexString(mDrawableCache.keyAt(i))
+ " / " + cs + " with changes: 0x"
+ Integer.toHexString(cs.getChangingConfigurations()));
}
mDrawableCache.setValueAt(i, null);
} else if (DEBUG_CONFIG) {
Log.d(TAG, "(Keeping #0x"
- + Integer.toHexString(mDrawableCache.keyAt(i))
+ + Long.toHexString(mDrawableCache.keyAt(i))
+ " / " + cs + " with changes: 0x"
+ Integer.toHexString(cs.getChangingConfigurations())
+ ")");
@@ -1653,7 +1652,7 @@ public class Resources {
}
}
- final int key = (value.assetCookie << 24) | value.data;
+ final long key = (((long) value.assetCookie) << 32) | value.data;
Drawable dr = getCachedDrawable(key);
if (dr != null) {
@@ -1733,7 +1732,7 @@ public class Resources {
return dr;
}
- private Drawable getCachedDrawable(int key) {
+ private Drawable getCachedDrawable(long key) {
synchronized (mTmpValue) {
WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
if (wr != null) { // we have the key
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index fd6d850..5bfdcc4 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -84,6 +84,7 @@ public class GestureOverlayView extends FrameLayout {
private final Rect mInvalidRect = new Rect();
private final Path mPath = new Path();
+ private boolean mGestureVisible = true;
private float mX;
private float mY;
@@ -274,14 +275,6 @@ public class GestureOverlayView extends FrameLayout {
return mCurrentGesture;
}
- public long getFadeOffset() {
- return mFadeOffset;
- }
-
- public void setFadeOffset(long fadeOffset) {
- mFadeOffset = fadeOffset;
- }
-
public void setGesture(Gesture gesture) {
if (mCurrentGesture != null) {
clear(false);
@@ -304,6 +297,31 @@ public class GestureOverlayView extends FrameLayout {
invalidate();
}
+ public Path getGesturePath() {
+ return mPath;
+ }
+
+ public Path getGesturePath(Path path) {
+ path.set(mPath);
+ return path;
+ }
+
+ public boolean isGestureVisible() {
+ return mGestureVisible;
+ }
+
+ public void setGestureVisible(boolean visible) {
+ mGestureVisible = visible;
+ }
+
+ public long getFadeOffset() {
+ return mFadeOffset;
+ }
+
+ public void setFadeOffset(long fadeOffset) {
+ mFadeOffset = fadeOffset;
+ }
+
public void addOnGestureListener(OnGestureListener listener) {
mOnGestureListeners.add(listener);
}
@@ -372,7 +390,7 @@ public class GestureOverlayView extends FrameLayout {
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mCurrentGesture != null) {
+ if (mCurrentGesture != null && mGestureVisible) {
canvas.drawPath(mPath, mGesturePaint);
}
}
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 @@ public class MemoryFile
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 @@ public class MemoryFile
* @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/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index 5353b53..6ea2528 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -22,6 +22,7 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Adapter;
@@ -147,13 +148,20 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
ListView listView = new ListView(context);
bind(listView);
- Dialog dialog = mDialog = new Dialog(context, com.android.internal.R.style.Theme_NoTitleBar);
+ // Set the title bar if title is available, else no title bar
+ final CharSequence title = getTitle();
+ Dialog dialog = mDialog = new Dialog(context, !TextUtils.isEmpty(title)
+ ? com.android.internal.R.style.Theme_NoTitleBar
+ : com.android.internal.R.style.Theme);
dialog.setContentView(listView);
+ if (!TextUtils.isEmpty(title)) {
+ dialog.setTitle(title);
+ }
dialog.setOnDismissListener(this);
if (state != null) {
dialog.onRestoreInstanceState(state);
}
-
+
// Add the screen to the list of preferences screens opened as dialogs
getPreferenceManager().addPreferencesScreen(dialog);
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 9c8c537..94254de 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -96,7 +96,7 @@ public class Browser {
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 };
/* these indices dependent on HISTORY_PROJECTION */
public static final int HISTORY_PROJECTION_ID_INDEX = 0;
@@ -106,6 +106,10 @@ public class Browser {
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;
/* columns needed to determine whether to truncate history */
public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] {
@@ -486,6 +490,10 @@ public class Browser {
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";
}
public static class SearchColumns implements BaseColumns {
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 0829cfb..5f84e57 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -40,7 +40,7 @@ import java.io.InputStream;
*/
public class Contacts {
private static final String TAG = "Contacts";
-
+
public static final String AUTHORITY = "contacts";
/**
@@ -191,7 +191,7 @@ public class Contacts {
* <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.
@@ -206,7 +206,7 @@ public class Contacts {
* @hide Used only in Contacts application for now.
*/
public static final String SORT_STRING = "sort_string";
-
+
/**
* Notes about the person.
* <P>Type: TEXT</P>
@@ -248,7 +248,7 @@ public class Contacts {
* 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";
}
/**
@@ -287,14 +287,14 @@ public class Contacts {
* 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.
@@ -379,13 +379,13 @@ public class Contacts {
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
@@ -409,13 +409,13 @@ public class Contacts {
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
@@ -427,14 +427,14 @@ public class Contacts {
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
@@ -472,7 +472,7 @@ public class Contacts {
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.
@@ -739,7 +739,7 @@ public class Contacts {
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 {
@@ -759,7 +759,7 @@ public class Contacts {
CharSequence label) {
return getDisplayLabel(context, type, label, null);
}
-
+
/**
* The content:// style URL for this table
*/
@@ -984,7 +984,7 @@ public class Contacts {
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.
@@ -1197,7 +1197,7 @@ public class Contacts {
/**
* 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
*/
@@ -1205,17 +1205,17 @@ public class Contacts {
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;
@@ -1455,28 +1455,27 @@ public class Contacts {
* 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
@@ -1502,7 +1501,7 @@ public class Contacts {
* 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
@@ -1511,9 +1510,8 @@ public class Contacts {
* <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
@@ -1522,7 +1520,7 @@ public class Contacts {
* Type: STRING
*/
public static final String EXTRA_CREATE_DESCRIPTION =
- "com.android.contacts.action.CREATE_DESCRIPTION";
+ ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
/**
* Intents related to the Contacts app UI.
@@ -1531,43 +1529,42 @@ public class Contacts {
/**
* 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
@@ -1575,15 +1572,15 @@ public class Contacts {
* 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>
@@ -1592,15 +1589,15 @@ public class Contacts {
* <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;
}
/**
@@ -1609,170 +1606,179 @@ public class Contacts {
*/
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
index b9c9236..48dc3ae 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
@@ -179,6 +180,21 @@ public final class ContactsContract {
*/
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} and {@link Presence}, filtered to include only starred aggregates
+ * and the most frequently contacted aggregates.
+ */
+ 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 aggregate 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");
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of
@@ -266,7 +282,8 @@ public final class ContactsContract {
*
* @hide
*/
- public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI, "filter_email");
+ 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
@@ -948,7 +965,8 @@ public final class ContactsContract {
/**
* Constants for the contact aggregation exceptions table, which contains
- * aggregation rules overriding those used by automatic aggregation.
+ * 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 {
/**
@@ -974,26 +992,39 @@ public final class ContactsContract {
"vnd.android.cursor.item/aggregation_exception";
/**
- * The type of exception: {@link #TYPE_NEVER_MATCH} or {@link #TYPE_ALWAYS_MATCH}.
+ * 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";
- public static final int TYPE_NEVER_MATCH = 0;
- public static final int TYPE_ALWAYS_MATCH = 1;
+ /**
+ * Allows the provider to automatically decide whether the aggregate should include
+ * a particular contact or not.
+ */
+ public static final int TYPE_AUTOMATIC = 0;
+
+ /**
+ * Makes sure that the specified contact is included in the specified aggregate.
+ */
+ public static final int TYPE_KEEP_IN = 1;
+
+ /**
+ * Makes sure that the specified contact is NOT included in the specified aggregate.
+ */
+ public static final int TYPE_KEEP_OUT = 2;
/**
- * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of one of
- * the contacts that the rule applies to.
+ * A reference to the {@link Aggregates#_ID} of the aggregate that the rule applies to.
*/
- public static final String CONTACT_ID1 = "contact_id1";
+ public static final String AGGREGATE_ID = "aggregate_id";
/**
- * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the other
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the
* contact that the rule applies to.
*/
- public static final String CONTACT_ID2 = "contact_id2";
+ public static final String CONTACT_ID = "contact_id";
}
private interface RestrictionExceptionsColumns {
@@ -1042,4 +1073,344 @@ public final class ContactsContract {
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
"restriction_exceptions");
}
+
+ /**
+ * 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";
+
+ /**
+ * 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 Contacts.ContactMethods#encodePredefinedImProtocol}
+ * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</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/Settings.java b/core/java/android/provider/Settings.java
index 03c7f28..5aa2174 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1976,6 +1976,16 @@ public final class Settings {
public static final String TTS_DEFAULT_LANG = "tts_default_lang";
/**
+ * Default text-to-speech country.
+ */
+ public static final String TTS_DEFAULT_COUNTRY = "tts_default_country";
+
+ /**
+ * Default text-to-speech locale variant.
+ */
+ public static final String TTS_DEFAULT_VARIANT = "tts_default_variant";
+
+ /**
* Whether to notify the user of open networks.
* <p>
* If not connected and the scan results have an open network, we will
@@ -2180,6 +2190,14 @@ public final class Settings {
public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
/**
+ * Flag for allowing service provider to use location information to improve products and
+ * services.
+ * Type: int ( 0 = disallow, 1 = allow )
+ * @hide
+ */
+ public static final String USE_LOCATION_FOR_SERVICES = "use_location";
+
+ /**
* Helper method for determining if a location provider is enabled.
* @param cr the content resolver to use
* @param provider the location provider to query
@@ -2623,26 +2641,6 @@ public final class Settings {
"gtalk_wifi_max_heartbeat_ping_interval_ms";
/**
- * The minimum interval for how frequently we send heartbeat pings to the GTalk server.
- */
- public static final String GTALK_SERVICE_MIN_HEARTBEAT_INTERVAL_MS =
- "gtalk_min_heartbeat_ping_interval_ms";
-
- /**
- * The scale down factor used by adaptive heartbeat logic (to scale down the heartbeat
- * interval) when the previous interval fails to get a response from the server.
- */
- public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_SCALER =
- "gtalk_adaptive_heartbeat_scaler";
-
- /**
- * The trigger for adaptively scaling down the heartbeat interval. This is the number of
- * consecutive times we failed to get a server response for sending the heartbeat ping.
- */
- public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_TRIGGER =
- "gtalk_adaptive_heartbeat_trigger";
-
- /**
* How long we wait to receive a heartbeat ping acknowledgement (or another packet)
* from the GTalk server, before deeming the connection dead.
*/
@@ -2695,6 +2693,15 @@ public final class Settings {
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";
+
+ /**
* Enable use of ssl session caching.
* 'db' - save each session in a (per process) database
* 'file' - save each session in a (per process) file
@@ -2791,6 +2798,13 @@ public final class Settings {
public static final String VENDING_TAB_2_TITLE = "vending_tab_2_title";
/**
+ * Frequency in milliseconds at which we should request MCS heartbeats
+ * from the Vending Machine client.
+ */
+ public static final String VENDING_HEARTBEAT_FREQUENCY_MS =
+ "vending_heartbeat_frequency_ms";
+
+ /**
* URL that points to the legal terms of service to display in Settings.
* <p>
* This should be a https URL. For a pretty user-friendly URL, use
@@ -3094,6 +3108,7 @@ public final class Settings {
* Flag for allowing service provider to use location information to improve products and
* services.
* Type: int ( 0 = disallow, 1 = allow )
+ * @deprecated
*/
public static final String USE_LOCATION_FOR_SERVICES = "use_location";
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 36c432b..dcaede2 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -1039,6 +1039,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
break;
}
pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
+ pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
+
headset.close();
}
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
index 739a8e4..02211fd 100755
--- a/core/java/android/speech/tts/ITts.aidl
+++ b/core/java/android/speech/tts/ITts.aidl
@@ -39,7 +39,7 @@ interface ITts {
void addSpeechFile(in String text, in String filename);
- void setLanguage(in String language);
+ void setLanguage(in String language, in String country, in String variant);
boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 2c0c09e..9fc143d 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -22,13 +22,12 @@ 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.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.HashMap;
+import java.util.Locale;
/**
*
@@ -36,7 +35,7 @@ import java.util.HashMap;
*
* {@hide}
*/
-//TODO #TTS# review + complete javadoc
+//TODO #TTS# review + complete javadoc + add links to constants
public class TextToSpeech {
/**
@@ -52,9 +51,18 @@ public class TextToSpeech {
*/
public static final int TTS_ERROR_MISSING_RESOURCE = -2;
+ /**
+ * Queue mode where all entries in the playback queue (media to be played
+ * and text to be synthesized) are dropped and replaced by the new entry.
+ */
+ public static final int TTS_QUEUE_FLUSH = 0;
+ /**
+ * Queue mode where the new entry is added at the end of the playback queue.
+ */
+ public static final int TTS_QUEUE_ADD = 1;
/**
- * Called when the TTS has initialized
+ * Called when the TTS has initialized.
*
* The InitListener must implement the onInit function. onInit is passed a
* status code indicating the result of the TTS initialization.
@@ -73,9 +81,31 @@ public class TextToSpeech {
}
/**
- * Connection needed for the TTS
+ * Internal constants for the TTS functionality
+ *
+ * {@hide}
+ */
+ public class Engine {
+ // default values for a TTS engine when settings are not found in the provider
+ public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+ public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+ public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
+ public static final String FALLBACK_TTS_DEFAULT_LANG = "eng";
+ public static final String FALLBACK_TTS_DEFAULT_COUNTRY = "";
+ public static final String FALLBACK_TTS_DEFAULT_VARIANT = "";
+
+ // return codes for a TTS engine's check data activity
+ public static final int CHECK_VOICE_DATA_PASS = 1;
+ public static final int CHECK_VOICE_DATA_FAIL = 0;
+ public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
+ public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
+ public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
+ }
+
+ /**
+ * Connection needed for the TTS.
*/
- private ServiceConnection serviceConnection;
+ private ServiceConnection mServiceConnection;
private ITts mITts = null;
private Context mContext = null;
@@ -104,8 +134,7 @@ public class TextToSpeech {
}
- public void setOnSpeechCompletedListener(
- final OnSpeechCompletedListener listener) {
+ public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) {
synchronized(mSpeechCompListenerLock) {
mSpeechCompListener = listener;
}
@@ -126,7 +155,7 @@ public class TextToSpeech {
mStarted = false;
// Initialize the TTS, run the callback after the binding is successful
- serviceConnection = new ServiceConnection() {
+ mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized(mStartLock) {
mITts = ITts.Stub.asInterface(service);
@@ -176,7 +205,7 @@ public class TextToSpeech {
Intent intent = new Intent("android.intent.action.USE_TTS");
intent.addCategory("android.intent.category.TTS");
- mContext.bindService(intent, serviceConnection,
+ mContext.bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE);
// TODO handle case where the binding works (should always work) but
// the plugin fails
@@ -190,7 +219,7 @@ public class TextToSpeech {
*/
public void shutdown() {
try {
- mContext.unbindService(serviceConnection);
+ mContext.unbindService(mServiceConnection);
} catch (IllegalArgumentException e) {
// Do nothing and fail silently since an error here indicates that
// binding never succeeded in the first place.
@@ -291,8 +320,8 @@ public class TextToSpeech {
* @param text
* The string of text to be spoken.
* @param queueMode
- * The queuing strategy to use. Use 0 for no queuing, and 1 for
- * queuing.
+ * The queuing strategy to use.
+ * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* @param params
* The hashmap of speech parameters to be used.
*/
@@ -329,12 +358,11 @@ public class TextToSpeech {
* @param earcon
* The earcon that should be played
* @param queueMode
- * 0 for no queue (interrupts all previous utterances), 1 for
- * queued
+ * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* @param params
* The hashmap of parameters to be used.
*/
- public void playEarcon(String earcon, int queueMode,
+ public void playEarcon(String earcon, int queueMode,
HashMap<String,String> params) {
synchronized (mStartLock) {
if (!mStarted) {
@@ -358,8 +386,8 @@ public class TextToSpeech {
}
}
}
-
-
+
+
public void playSilence(long durationInMs, int queueMode) {
// TODO implement, already present in TTS service
}
@@ -429,20 +457,22 @@ public class TextToSpeech {
* Note that the speech rate is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified
* speech rate, but there is no guarantee.
- *
- * Currently, this will change the speech rate for the espeak engine, but it
- * has no effect on any pre-recorded speech.
+ * This has no effect on any pre-recorded speech.
*
* @param speechRate
- * The speech rate for the TTS engine.
+ * The speech rate for the TTS engine. 1 is the normal speed,
+ * lower values slow down the speech (0.5 is half the normal speech rate),
+ * greater values accelerate it (2 is twice the normal speech rate).
*/
- public void setSpeechRate(int speechRate) {
+ public void setSpeechRate(float speechRate) {
synchronized (mStartLock) {
if (!mStarted) {
return;
}
try {
- mITts.setSpeechRate(speechRate);
+ if (speechRate > 0) {
+ mITts.setSpeechRate((int)(speechRate*100));
+ }
} catch (RemoteException e) {
// TTS died; restart it.
mStarted = false;
@@ -457,24 +487,18 @@ public class TextToSpeech {
*
* Note that the language is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified
- * language, but there is no guarantee.
- *
- * Currently, this will change the language for the espeak engine, but it
- * has no effect on any pre-recorded speech.
+ * language as represented by the Locale, but there is no guarantee.
*
- * @param language
- * The language to be used. The languages are specified by their
- * IETF language tags as defined by BCP 47. This is the same
- * standard used for the lang attribute in HTML. See:
- * http://en.wikipedia.org/wiki/IETF_language_tag
+ * @param loc
+ * The locale describing the language to be used.
*/
- public void setLanguage(String language) {
+ public void setLanguage(Locale loc) {
synchronized (mStartLock) {
if (!mStarted) {
return;
}
try {
- mITts.setLanguage(language);
+ mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant());
} catch (RemoteException e) {
// TTS died; restart it.
mStarted = false;
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 470ab0d..2145d7c 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -241,7 +241,13 @@ public class InstrumentationTestCase extends TestCase {
try {
final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
final int keyCode = keyCodeField.getInt(null);
- instrumentation.sendKeyDownUpSync(keyCode);
+ try {
+ instrumentation.sendKeyDownUpSync(keyCode);
+ } catch (SecurityException e) {
+ // Ignore security exceptions that are now thrown
+ // when trying to send to another app, to retain
+ // compatibility with existing tests.
+ }
} catch (NoSuchFieldException e) {
Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
break;
@@ -266,7 +272,13 @@ public class InstrumentationTestCase extends TestCase {
final Instrumentation instrumentation = getInstrumentation();
for (int i = 0; i < count; i++) {
- instrumentation.sendKeyDownUpSync(keys[i]);
+ try {
+ instrumentation.sendKeyDownUpSync(keys[i]);
+ } catch (SecurityException e) {
+ // Ignore security exceptions that are now thrown
+ // when trying to send to another app, to retain
+ // compatibility with existing tests.
+ }
}
instrumentation.waitForIdleSync();
@@ -292,7 +304,13 @@ public class InstrumentationTestCase extends TestCase {
final int keyCount = keys[i];
final int keyCode = keys[i + 1];
for (int j = 0; j < keyCount; j++) {
- instrumentation.sendKeyDownUpSync(keyCode);
+ try {
+ instrumentation.sendKeyDownUpSync(keyCode);
+ } catch (SecurityException e) {
+ // Ignore security exceptions that are now thrown
+ // when trying to send to another app, to retain
+ // compatibility with existing tests.
+ }
}
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index bccb3a6..1a4eb69 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -184,6 +184,9 @@ public class DateUtils
*/
public static final String HOUR_MINUTE_24 = "%H:%M";
public static final String MONTH_FORMAT = "%B";
+ /**
+ * This is not actually a useful month name in all locales.
+ */
public static final String ABBREV_MONTH_FORMAT = "%b";
public static final String NUMERIC_MONTH_FORMAT = "%m";
public static final String MONTH_DAY_FORMAT = "%-d";
@@ -1444,7 +1447,8 @@ public class DateUtils
if (numericDate) {
monthFormat = NUMERIC_MONTH_FORMAT;
} else if (abbrevMonth) {
- monthFormat = ABBREV_MONTH_FORMAT;
+ monthFormat =
+ res.getString(com.android.internal.R.string.short_format_month);
} else {
monthFormat = MONTH_FORMAT;
}
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 245148d..a095913 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -37,8 +37,7 @@ public class DisplayMetrics {
* The device's density.
* @hide
*/
- public static final int DEVICE_DENSITY = SystemProperties.getInt("ro.sf.lcd_density",
- DEFAULT_DENSITY);
+ public static final int DEVICE_DENSITY = getDeviceDensity();
/**
* The absolute width of the display in pixels.
@@ -161,4 +160,13 @@ public class DisplayMetrics {
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
}
+
+ private static int getDeviceDensity() {
+ // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
+ // when running in the emulator, allowing for dynamic configurations.
+ // The reason for this is that ro.sf.lcd_density is write-once and is
+ // set by the init process when it parses build.prop before anything else.
+ return SystemProperties.getInt("qemu.sf.lcd_density",
+ SystemProperties.getInt("ro.sf.lcd_density", DEFAULT_DENSITY));
+ }
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
new file mode 100644
index 0000000..d90045f
--- /dev/null
+++ b/core/java/android/util/LongSparseArray.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.internal.util.ArrayUtils;
+
+/**
+ * SparseArrays map longs to Objects. Unlike a normal array of Objects,
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Longs to Objects.
+ *
+ * @hide
+ */
+public class LongSparseArray<E> {
+ private static final Object DELETED = new Object();
+ private boolean mGarbage = false;
+
+ /**
+ * Creates a new SparseArray containing no mappings.
+ */
+ public LongSparseArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public LongSparseArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new long[initialCapacity];
+ mValues = new Object[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(long key) {
+ return get(key, null);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(long key, E valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0 || mValues[i] == DELETED) {
+ return valueIfKeyNotFound;
+ } else {
+ return (E) mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(long key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ if (mValues[i] != DELETED) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
+ /**
+ * Alias for {@link #delete(long)}.
+ */
+ public void remove(long key) {
+ delete(key);
+ }
+
+ private void gc() {
+ // Log.e("SparseArray", "gc start with " + mSize);
+
+ int n = mSize;
+ int o = 0;
+ long[] keys = mKeys;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ Object val = values[i];
+
+ if (val != DELETED) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+
+ // Log.e("SparseArray", "gc end with " + mSize);
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(long key, E value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = value;
+ } else {
+ i = ~i;
+
+ if (i < mSize && mValues[i] == DELETED) {
+ mKeys[i] = key;
+ mValues[i] = value;
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~binarySearch(mKeys, 0, mSize, key);
+ }
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ long[] nkeys = new long[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public long keyAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public E valueAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return (E) mValues[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public void setValueAt(int index, E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(long key) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i] == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ int n = mSize;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ values[i] = null;
+ }
+
+ mSize = 0;
+ mGarbage = false;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(long key, E value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length) {
+ gc();
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ long[] nkeys = new long[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ private static int binarySearch(long[] a, int start, int len, long key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private void checkIntegrity() {
+ for (int i = 1; i < mSize; i++) {
+ if (mKeys[i] <= mKeys[i - 1]) {
+ for (int j = 0; j < mSize; j++) {
+ Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
+ }
+
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ private long[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+} \ No newline at end of file
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0497344..ec8fd96 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7157,8 +7157,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
getLocationInWindow(location);
final AttachInfo info = mAttachInfo;
- location[0] += info.mWindowLeft;
- location[1] += info.mWindowTop;
+ if (info != null) {
+ location[0] += info.mWindowLeft;
+ location[1] += info.mWindowTop;
+ }
}
/**
diff --git a/core/java/android/webkit/ByteArrayBuilder.java b/core/java/android/webkit/ByteArrayBuilder.java
index 806b458..145411c 100644
--- a/core/java/android/webkit/ByteArrayBuilder.java
+++ b/core/java/android/webkit/ByteArrayBuilder.java
@@ -17,6 +17,7 @@
package android.webkit;
import java.util.LinkedList;
+import java.util.ListIterator;
/** Utility class optimized for accumulating bytes, and then spitting
them back out. It does not optimize for returning the result in a
@@ -94,6 +95,20 @@ class ByteArrayBuilder {
return mChunks.isEmpty();
}
+ public int size() {
+ return mChunks.size();
+ }
+
+ public int getByteSize() {
+ int total = 0;
+ ListIterator<Chunk> it = mChunks.listIterator(0);
+ while (it.hasNext()) {
+ Chunk c = it.next();
+ total += c.mLength;
+ }
+ return total;
+ }
+
public synchronized void clear() {
Chunk c = getFirstChunk();
while (c != null) {
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 507fce3..cbe337a 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -18,6 +18,7 @@ package android.webkit;
import android.os.Handler;
import android.os.Message;
+import android.security.Keystore;
import android.util.Log;
final class JWebCoreJavaBridge extends Handler {
@@ -135,10 +136,9 @@ final class JWebCoreJavaBridge extends Handler {
/**
* 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();
@@ -223,18 +223,11 @@ final class JWebCoreJavaBridge extends Handler {
}
private String[] getKeyStrengthList() {
- // FIXME: fake the list for now
- String[] list = new String[2];
- list[0] = "1024";
- list[1] = "512";
- return list;
+ return Keystore.getInstance().getSupportedKeyStrenghs();
}
private String getSignedPublicKey(int index, String challenge, String url) {
- // FIXME: do nothing for now
- Log.w(LOGTAG, "getSignedPublicKey for " + index + " and challenge="
- + challenge + " and url=" + url);
- return "";
+ return Keystore.getInstance().generateKeyPair(index, challenge, url);
}
private native void nativeConstructor();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 1ebdb79..08854f7 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -25,16 +25,16 @@ import android.net.http.HttpAuthHeader;
import android.net.http.RequestHandle;
import android.net.http.SslCertificate;
import android.net.http.SslError;
-import android.net.http.SslCertificate;
import android.os.Handler;
import android.os.Message;
+import android.security.Keystore;
import android.util.Log;
import android.webkit.CacheManager.CacheResult;
+import android.widget.Toast;
import com.android.internal.R;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -70,6 +70,8 @@ class LoadListener extends Handler implements EventHandler {
private static final int HTTP_NOT_FOUND = 404;
private static final int HTTP_PROXY_AUTH = 407;
+ private static final String CERT_MIMETYPE = "application/x-x509-ca-cert";
+
private static int sNativeLoaderCount;
private final ByteArrayBuilder mDataBuilder = new ByteArrayBuilder(8192);
@@ -919,6 +921,12 @@ class LoadListener extends Handler implements EventHandler {
// This commits the headers without checking the response status code.
private void commitHeaders() {
+ if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+ // In the case of downloading certificate, we will save it to the
+ // Keystore in commitLoad. Do not call webcore.
+ return;
+ }
+
// Commit the headers to WebCore
int nativeResponse = createNativeResponse();
// The native code deletes the native response object.
@@ -959,6 +967,30 @@ class LoadListener extends Handler implements EventHandler {
private void commitLoad() {
if (mCancelled) return;
+ if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+ // In the case of downloading certificate, we will save it to the
+ // Keystore and stop the current loading so that it will not
+ // generate a new history page
+ byte[] cert = new byte[mDataBuilder.getByteSize()];
+ int position = 0;
+ ByteArrayBuilder.Chunk c;
+ while (true) {
+ c = mDataBuilder.getFirstChunk();
+ if (c == null) break;
+
+ if (c.mLength != 0) {
+ System.arraycopy(c.mArray, 0, cert, position, c.mLength);
+ position += c.mLength;
+ }
+ mDataBuilder.releaseChunk(c);
+ }
+ Keystore.getInstance().addCertificate(cert);
+ Toast.makeText(mContext, R.string.certificateSaved,
+ Toast.LENGTH_SHORT).show();
+ mBrowserFrame.stopLoading();
+ return;
+ }
+
// Give the data to WebKit now
PerfChecker checker = new PerfChecker();
ByteArrayBuilder.Chunk c;
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index f27360d..0488691 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -200,8 +200,13 @@ public final class WebStorage {
*/
public void setQuotaForOrigin(String origin, long quota) {
if (origin != null) {
- postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
- new Origin(origin, quota)));
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeSetQuotaForOrigin(origin, quota);
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+ new Origin(origin, quota)));
+ }
}
}
@@ -211,8 +216,13 @@ public final class WebStorage {
*/
public void deleteOrigin(String origin) {
if (origin != null) {
- postMessage(Message.obtain(null, DELETE_ORIGIN,
- new Origin(origin)));
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteOrigin(origin);
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, DELETE_ORIGIN,
+ new Origin(origin)));
+ }
}
}
@@ -221,7 +231,12 @@ public final class WebStorage {
* Delete all databases
*/
public void deleteAllDatabases() {
- postMessage(Message.obtain(null, DELETE_ALL));
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteAllDatabases();
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, DELETE_ALL));
+ }
}
/**
@@ -250,7 +265,11 @@ public final class WebStorage {
* Post a Sync request
*/
public void update() {
- postMessage(Message.obtain(null, UPDATE));
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, UPDATE));
+ }
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 41e007e..2d8950e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -489,22 +489,27 @@ public class WebView extends AbsoluteLayout
// width which view is considered to be fully zoomed out
static final int ZOOM_OUT_WIDTH = 1008;
- private static final float DEFAULT_MAX_ZOOM_SCALE = 4.0f;
- private static final float DEFAULT_MIN_ZOOM_SCALE = 0.25f;
+ // 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 = DEFAULT_MAX_ZOOM_SCALE;
- private float mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ private float mMaxZoomScale;
+ private float mMinZoomScale;
private boolean mMinZoomScaleFixed = false;
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // default scale. Depending on the display density.
+ static int DEFAULT_SCALE_PERCENT;
+ private float DEFAULT_SCALE;
+
// set to true temporarily while the zoom control is being dragged
private boolean mPreviewZoomOnly = false;
// computed scale and inverse, from mZoomWidth.
- private float mActualScale = 1;
- private float mInvActualScale = 1;
+ private float mActualScale;
+ private float mInvActualScale;
// if this is non-zero, it is used on drawing rather than mActualScale
private float mZoomScale;
private float mInvInitialZoomScale;
@@ -734,10 +739,19 @@ public class WebView extends AbsoluteLayout
final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = 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
- mNavSlop = (int) (16 * getContext().getResources()
- .getDisplayMetrics().density);
+ mNavSlop = (int) (16 * density);
+ // density adjusted scale factors
+ DEFAULT_SCALE_PERCENT = (int) (100 * density);
+ DEFAULT_SCALE = density;
+ mActualScale = density;
+ mInvActualScale = 1 / density;
+ DEFAULT_MAX_ZOOM_SCALE = 4.0f * density;
+ DEFAULT_MIN_ZOOM_SCALE = 0.25f * density;
+ mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+ mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
}
/* package */ boolean onSavePassword(String schemePlusHost, String username,
@@ -1750,8 +1764,9 @@ public class WebView extends AbsoluteLayout
}
// 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();
@@ -2061,7 +2076,33 @@ public class WebView extends AbsoluteLayout
* @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);
}
/*
@@ -2889,10 +2930,9 @@ public class WebView extends AbsoluteLayout
WebViewCore.CursorData result = new WebViewCore.CursorData();
result.mMoveGeneration = nativeMoveGeneration();
result.mFrame = nativeCursorFramePointer();
- result.mNode = nativeCursorNodePointer();
- Rect bounds = nativeCursorNodeBounds();
- result.mX = bounds.centerX();
- result.mY = bounds.centerY();
+ Point position = nativeCursorPosition();
+ result.mX = position.x;
+ result.mY = position.y;
return result;
}
@@ -4191,9 +4231,9 @@ public class WebView extends AbsoluteLayout
private boolean zoomWithPreview(float scale) {
float oldScale = mActualScale;
- // snap to 100% if it is close
- if (scale > 0.95f && scale < 1.05f) {
- scale = 1.0f;
+ // snap to DEFAULT_SCALE if it is close
+ if (scale > (DEFAULT_SCALE - 0.05) && scale < (DEFAULT_SCALE + 0.05)) {
+ scale = DEFAULT_SCALE;
}
setNewZoomScale(scale, false);
@@ -4582,6 +4622,9 @@ public class WebView extends AbsoluteLayout
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;
Rect visibleRect = sendOurVisibleRect();
// Note that sendOurVisibleRect calls viewToContent, so the
@@ -4593,9 +4636,14 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
cursorData());
playSoundEffect(SoundEffectConstants.CLICK);
- if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+ boolean isTextInput = nativeCursorIsTextInput();
+ if (isTextInput || !mCallbackProxy.uiOverrideUrlLoading(
+ nativeCursorText())) {
mWebViewCore.sendMessage(EventHub.CLICK);
}
+ if (isTextInput) {
+ rebuildWebTextView();
+ }
break;
case SCROLL_BY_MSG_ID:
setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
@@ -4714,8 +4762,8 @@ public class WebView extends AbsoluteLayout
}
int initialScale = msg.arg1;
int viewportWidth = msg.arg2;
- // by default starting a new page with 100% zoom scale.
- float scale = 1.0f;
+ // start a new page with DEFAULT_SCALE zoom scale.
+ float scale = DEFAULT_SCALE;
if (mInitialScale > 0) {
scale = mInitialScale / 100.0f;
} else {
@@ -5210,6 +5258,7 @@ public class WebView extends AbsoluteLayout
private native boolean nativeCursorIntersects(Rect visibleRect);
private native boolean nativeCursorIsAnchor();
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
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 90d0709..4ad9a1a 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -94,7 +94,7 @@ final class WebViewCore {
private boolean mViewportUserScalable = true;
- private int mRestoredScale = 100;
+ private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
private int mRestoredX = 0;
private int mRestoredY = 0;
@@ -309,7 +309,7 @@ final class WebViewCore {
// JNI methods
//-------------------------------------------------------------------------
- static native String nativeFindAddress(String addr);
+ static native String nativeFindAddress(String addr, boolean caseInsensitive);
/**
* Empty the picture set.
@@ -379,12 +379,10 @@ final class WebViewCore {
private native void nativeSaveDocumentState(int frame);
- private native void nativeMoveMouse(int framePtr, int nodePtr, int x,
- int y);
+ private native void nativeMoveMouse(int framePtr, int x, int y);
private native void nativeMoveMouseIfLatest(int moveGeneration,
- int framePtr, int nodePtr, int x, int y,
- boolean ignoreNullFocus);
+ int framePtr, int x, int y);
private native String nativeRetrieveHref(int framePtr, int nodePtr);
@@ -524,16 +522,13 @@ final class WebViewCore {
CursorData() {}
CursorData(int frame, int node, int x, int y) {
mFrame = frame;
- mNode = node;
mX = x;
mY = y;
}
int mMoveGeneration;
int mFrame;
- int mNode;
int mX;
int mY;
- boolean mIgnoreNullFocus;
}
static class JSInterfaceData {
@@ -725,7 +720,7 @@ final class WebViewCore {
public void handleMessage(Message msg) {
if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
- > SET_INACTIVE ? Integer.toString(msg.what)
+ > FREE_MEMORY ? Integer.toString(msg.what)
: HandlerDebugString[msg.what - LOAD_URL]);
}
switch (msg.what) {
@@ -819,7 +814,8 @@ final class WebViewCore {
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:
@@ -973,16 +969,14 @@ final class WebViewCore {
case SET_MOVE_MOUSE:
CursorData cursorData = (CursorData) msg.obj;
nativeMoveMouse(cursorData.mFrame,
- cursorData.mNode, cursorData.mX,
- cursorData.mY);
+ cursorData.mX, cursorData.mY);
break;
case SET_MOVE_MOUSE_IF_LATEST:
CursorData cData = (CursorData) msg.obj;
nativeMoveMouseIfLatest(cData.mMoveGeneration,
- cData.mFrame, cData.mNode,
- cData.mX, cData.mY,
- cData.mIgnoreNullFocus);
+ cData.mFrame,
+ cData.mX, cData.mY);
break;
case REQUEST_CURSOR_HREF: {
@@ -1627,16 +1621,16 @@ final class WebViewCore {
// infer the values if they are not defined.
if (mViewportWidth == 0) {
if (mViewportInitialScale == 0) {
- mViewportInitialScale = 100;
+ mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
}
if (mViewportMinimumScale == 0) {
- mViewportMinimumScale = 100;
+ mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
}
}
if (mViewportUserScalable == false) {
- mViewportInitialScale = 100;
- mViewportMinimumScale = 100;
- mViewportMaximumScale = 100;
+ mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
+ mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
+ mViewportMaximumScale = WebView.DEFAULT_SCALE_PERCENT;
}
if (mViewportMinimumScale > mViewportInitialScale) {
if (mViewportInitialScale == 0) {
@@ -1652,7 +1646,8 @@ final class WebViewCore {
mViewportInitialScale = mViewportMaximumScale;
}
}
- if (mViewportWidth < 0 && mViewportInitialScale == 100) {
+ if (mViewportWidth < 0
+ && mViewportInitialScale == WebView.DEFAULT_SCALE_PERCENT) {
mViewportWidth = 0;
}
@@ -1728,7 +1723,7 @@ final class WebViewCore {
}
// 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);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ff95203..1c66803 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -619,15 +619,19 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
mDropDownList.getAdapter().getCount() - 1)) {
// When the selection is at the top, we block the key
// event to prevent focus from moving.
- mDropDownList.hideSelector();
- mDropDownList.requestLayout();
+ clearListSelection();
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
mPopup.update();
return true;
+ } else {
+ // WARNING: Please read the comment where mListSelectionHidden
+ // is declared
+ mDropDownList.mListSelectionHidden = false;
}
+
consumed = mDropDownList.onKeyDown(keyCode, event);
- if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed="
- + consumed);
+ if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + consumed);
+
if (consumed) {
// If it handled the key event, then the user is
// navigating in the list, so we should put it in front.
@@ -770,9 +774,12 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* it back.
*/
public void clearListSelection() {
- if (mDropDownList != null) {
- mDropDownList.hideSelector();
- mDropDownList.requestLayout();
+ final DropDownListView list = mDropDownList;
+ if (list != null) {
+ // WARNING: Please read the comment where mListSelectionHidden is declared
+ list.mListSelectionHidden = true;
+ list.hideSelector();
+ list.requestLayout();
}
}
@@ -1062,8 +1069,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
mPopup.showAsDropDown(getDropDownAnchorView(),
mDropDownHorizontalOffset, mDropDownVerticalOffset);
mDropDownList.setSelection(ListView.INVALID_POSITION);
- mDropDownList.hideSelector();
- mDropDownList.requestFocus();
+ clearListSelection();
post(mHideSelector);
}
}
@@ -1106,6 +1112,18 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
mDropDownList.setOnItemClickListener(mDropDownItemClickListener);
mDropDownList.setFocusable(true);
mDropDownList.setFocusableInTouchMode(true);
+ mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view,
+ int position, long id) {
+
+ if (position != -1) {
+ mDropDownList.mListSelectionHidden = false;
+ }
+ }
+
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
if (mItemSelectedListener != null) {
mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
@@ -1229,10 +1247,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
private class ListSelectorHider implements Runnable {
public void run() {
- if (mDropDownList != null) {
- mDropDownList.hideSelector();
- mDropDownList.requestLayout();
- }
+ clearListSelection();
}
}
@@ -1259,6 +1274,36 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* passed to the drop down; the list only looks focused.</p>
*/
private static class DropDownListView extends ListView {
+ /*
+ * WARNING: This is a workaround for a touch mode issue.
+ *
+ * Touch mode is propagated lazily to windows. This causes problems in
+ * the following scenario:
+ * - Type something in the AutoCompleteTextView and get some results
+ * - Move down with the d-pad to select an item in the list
+ * - Move up with the d-pad until the selection disappears
+ * - Type more text in the AutoCompleteTextView *using the soft keyboard*
+ * and get new results; you are now in touch mode
+ * - The selection comes back on the first item in the list, even though
+ * the list is supposed to be in touch mode
+ *
+ * Using the soft keyboard triggers the touch mode change but that change
+ * is propagated to our window only after the first list layout, therefore
+ * after the list attempts to resurrect the selection.
+ *
+ * The trick to work around this issue is to pretend the list is in touch
+ * mode when we know that the selection should not appear, that is when
+ * we know the user moved the selection away from the list.
+ *
+ * This boolean is set to true whenever we explicitely hide the list's
+ * selection and reset to false whenver we know the user moved the
+ * selection back to the list.
+ *
+ * When this boolean is true, isInTouchMode() returns true, otherwise it
+ * returns super.isInTouchMode().
+ */
+ private boolean mListSelectionHidden;
+
/**
* <p>Creates a new list view wrapper.</p>
*
@@ -1304,6 +1349,12 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
return mSelectionBottomPadding;
}
+ @Override
+ public boolean isInTouchMode() {
+ // WARNING: Please read the comment where mListSelectionHidden is declared
+ return mListSelectionHidden || super.isInTouchMode();
+ }
+
/**
* <p>Returns the focus state in the drop down.</p>
*
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index a195ac7..6532125 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -174,6 +174,8 @@ public class ListView extends AbsListView {
setDividerHeight(dividerHeight);
}
+ setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE));
+
mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);
diff --git a/core/java/com/android/internal/backup/GoogleTransport.java b/core/java/com/android/internal/backup/GoogleTransport.java
deleted file mode 100644
index c089c23..0000000
--- a/core/java/com/android/internal/backup/GoogleTransport.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.android.internal.backup;
-
-import android.backup.RestoreSet;
-import android.content.pm.PackageInfo;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-/**
- * Backup transport for saving data to Google cloud storage.
- */
-
-public class GoogleTransport extends IBackupTransport.Stub {
-
- public long requestBackupTime() throws RemoteException {
- return 0; // !!! TODO: implement real backoff policy
- }
-
- public int startSession() throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public int endSession() throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
- throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- // Restore handling
- public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
- // !!! TODO: real implementation
- return null;
- }
-
- public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
- // !!! TODO: real implementation
- return new PackageInfo[0];
- }
-
- public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor data)
- throws android.os.RemoteException {
- // !!! TODO: real implementation
- return 0;
- }
-}
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 9daabca..84ed729 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -42,11 +42,14 @@ interface IBackupTransport {
*/
/**
* Verify that this is a suitable time for a backup pass. This should return zero
- * if a backup is reasonable right now, false otherwise. This method will be called
- * outside of the {@link #startSession}/{@link #endSession} pair.
+ * if a backup is reasonable right now, some positive value otherwise. This method
+ * will be called outside of the {@link #startSession}/{@link #endSession} pair.
*
- * <p>If this is not a suitable time for a backup, the transport should suggest a
+ * <p>If this is not a suitable time for a backup, the transport should return a
* backoff delay, in milliseconds, after which the Backup Manager should try again.
+ *
+ * @return Zero if this is a suitable time for a backup pass, or a positive time delay
+ * in milliseconds to suggest deferring the backup pass for a while.
*/
long requestBackupTime();
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index f7b89f2..3ef8666 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -12,6 +12,8 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
+import org.bouncycastle.util.encoders.Base64;
+
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
@@ -78,25 +80,35 @@ public class LocalTransport extends IBackupTransport.Stub {
byte[] buf = new byte[bufSize];
while (changeSet.readNextHeader()) {
String key = changeSet.getKey();
+ String base64Key = new String(Base64.encode(key.getBytes()));
+ File entityFile = new File(packageDir, base64Key);
+
int dataSize = changeSet.getDataSize();
- if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize);
- if (dataSize > bufSize) {
- bufSize = dataSize;
- buf = new byte[bufSize];
- }
- changeSet.readEntityData(buf, dataSize);
- if (DEBUG) Log.v(TAG, " + data size " + dataSize);
-
- File entityFile = new File(packageDir, key);
- FileOutputStream entity = new FileOutputStream(entityFile);
- try {
- entity.write(buf, 0, dataSize);
- } catch (IOException e) {
- Log.e(TAG, "Unable to update key file "
- + entityFile.getAbsolutePath());
- err = -1;
- } finally {
- entity.close();
+
+ if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize
+ + " key64=" + base64Key);
+
+ if (dataSize >= 0) {
+ FileOutputStream entity = new FileOutputStream(entityFile);
+
+ if (dataSize > bufSize) {
+ bufSize = dataSize;
+ buf = new byte[bufSize];
+ }
+ changeSet.readEntityData(buf, 0, dataSize);
+ if (DEBUG) Log.v(TAG, " data size " + dataSize);
+
+ try {
+ entity.write(buf, 0, dataSize);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to update key file "
+ + entityFile.getAbsolutePath());
+ err = -1;
+ } finally {
+ entity.close();
+ }
+ } else {
+ entityFile.delete();
}
}
} catch (IOException e) {
@@ -112,11 +124,9 @@ public class LocalTransport extends IBackupTransport.Stub {
// Restore handling
public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
// one hardcoded restore set
- RestoreSet[] set = new RestoreSet[1];
- set[0].device = "flash";
- set[0].name = "Local disk image";
- set[0].token = 0;
- return set;
+ RestoreSet set = new RestoreSet("Local disk image", "flash", 0);
+ RestoreSet[] array = { set };
+ return array;
}
public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
@@ -162,14 +172,15 @@ public class LocalTransport extends IBackupTransport.Stub {
File[] blobs = packageDir.listFiles();
int err = 0;
if (blobs != null && blobs.length > 0) {
- BackupDataOutput out = new BackupDataOutput(mContext, outFd.getFileDescriptor());
+ BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
try {
for (File f : blobs) {
FileInputStream in = new FileInputStream(f);
int size = (int) f.length();
byte[] buf = new byte[size];
in.read(buf);
- out.writeEntityHeader(f.getName(), size);
+ String key = new String(Base64.decode(f.getName()));
+ out.writeEntityHeader(key, size);
out.writeEntityData(buf, size);
}
} catch (Exception e) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 9066233..251bc84 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,6 +11,10 @@ else
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
@@ -119,7 +123,8 @@ LOCAL_SRC_FILES:= \
com_android_internal_graphics_NativeUtils.cpp \
android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \
- android_backup_FileBackupHelper.cpp
+ android_backup_FileBackupHelper.cpp \
+ android_backup_RestoreHelperBase.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4512fef..1a1ebb4 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -156,6 +156,7 @@ extern int register_android_location_GpsLocationProvider(JNIEnv* env);
extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
extern int register_android_backup_FileBackupHelper(JNIEnv *env);
+extern int register_android_backup_RestoreHelperBase(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -528,7 +529,14 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
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;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -547,6 +555,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
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, "");
@@ -683,12 +695,70 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
//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);
+ }
+#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) {
@@ -1172,6 +1242,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelper),
+ REG_JNI(register_android_backup_RestoreHelperBase),
};
/*
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 76e6f02..d1fe83e 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -69,6 +69,8 @@ public:
static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
obj->reset();
+ // utf16 is required for java
+ obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
}
static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 5b2fb73..cf8a8e8 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -55,18 +55,13 @@ static jint
readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
{
int err;
+ bool done;
BackupDataReader* reader = (BackupDataReader*)r;
- err = reader->Status();
- if (err != 0) {
- return err < 0 ? err : -1;
- }
-
int type = 0;
- err = reader->ReadNextHeader(&type);
- if (err == EIO) {
- // Clean EOF with no footer block; just claim we're done
+ err = reader->ReadNextHeader(&done, &type);
+ if (done) {
return 1;
}
@@ -75,24 +70,12 @@ readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
}
switch (type) {
- case BACKUP_HEADER_APP_V1:
- {
- String8 packageName;
- int cookie;
- err = reader->ReadAppHeader(&packageName, &cookie);
- if (err != 0) {
- LOGD("ReadAppHeader() returned %d; aborting", err);
- return err < 0 ? err : -1;
- }
- break;
- }
case BACKUP_HEADER_ENTITY_V1:
{
String8 key;
size_t dataSize;
err = reader->ReadEntityHeader(&key, &dataSize);
if (err != 0) {
- LOGD("ReadEntityHeader(); aborting", err);
return err < 0 ? err : -1;
}
// TODO: Set the fields in the entity object
@@ -101,10 +84,6 @@ readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
env->SetIntField(entity, s_dataSizeField, dataSize);
return 0;
}
- case BACKUP_FOOTER_APP_V1:
- {
- break;
- }
default:
LOGD("Unknown header type: 0x%08x\n", type);
return -1;
@@ -115,12 +94,12 @@ readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
}
static jint
-readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
+readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int offset, int size)
{
int err;
BackupDataReader* reader = (BackupDataReader*)r;
- if (env->GetArrayLength(data) < size) {
+ if (env->GetArrayLength(data) < (size+offset)) {
// size mismatch
return -1;
}
@@ -130,19 +109,31 @@ readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int si
return -2;
}
- err = reader->ReadEntityData(dataBytes, size);
+ err = reader->ReadEntityData(dataBytes+offset, size);
env->ReleaseByteArrayElements(data, dataBytes, 0);
return err;
}
+static jint
+skipEntityData_native(JNIEnv* env, jobject clazz, int r)
+{
+ int err;
+ BackupDataReader* reader = (BackupDataReader*)r;
+
+ err = reader->SkipEntityData();
+
+ return err;
+}
+
static const JNINativeMethod g_methods[] = {
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
{ "dtor", "(I)V", (void*)dtor_native },
{ "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
(void*)readNextHeader_native },
- { "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
+ { "readEntityData_native", "(I[BII)I", (void*)readEntityData_native },
+ { "skipEntityData_native", "(I)I", (void*)skipEntityData_native },
};
int register_android_backup_BackupDataInput(JNIEnv* env)
diff --git a/core/jni/android_backup_RestoreHelperBase.cpp b/core/jni/android_backup_RestoreHelperBase.cpp
new file mode 100644
index 0000000..3173420
--- /dev/null
+++ b/core/jni/android_backup_RestoreHelperBase.cpp
@@ -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.
+ */
+
+#define LOG_TAG "FileBackupHelper_native"
+#include <utils/Log.h>
+
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/BackupHelpers.h>
+
+namespace android
+{
+
+// java.io.FileDescriptor
+static jfieldID s_descriptorField = 0;
+
+static int
+ctor(JNIEnv* env, jobject clazz)
+{
+ return (int)new RestoreHelperBase();
+}
+
+static void
+dtor(JNIEnv* env, jobject clazz, jint ptr)
+{
+ delete (RestoreHelperBase*)ptr;
+}
+
+static int
+writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr)
+{
+ int err;
+ RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
+ BackupDataReader* reader = (BackupDataReader*)backupReaderPtr;
+ char const* filename;
+
+ filename = env->GetStringUTFChars(filenameObj, NULL);
+
+ err = restore->WriteFile(String8(filename), reader);
+
+ env->ReleaseStringUTFChars(filenameObj, filename);
+
+ return err;
+}
+
+static int
+writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor)
+{
+ int err;
+
+ RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
+ int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+
+ err = restore->WriteSnapshot(fd);
+
+ return err;
+}
+
+static const JNINativeMethod g_methods[] = {
+ { "ctor", "()I", (void*)ctor },
+ { "dtor", "(I)V", (void*)dtor },
+ { "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native },
+ { "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native },
+};
+
+int register_android_backup_RestoreHelperBase(JNIEnv* env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("java/io/FileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+ s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
+ LOG_FATAL_IF(s_descriptorField == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/backup/RestoreHelperBase",
+ g_methods, NELEM(g_methods));
+}
+
+}
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index 5c4fb22..bf0bd65 100644..100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -336,13 +336,15 @@ static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* e
}
static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
- jint type, jint addr, jint port)
+ jint type, jstring hostname, jint port)
{
if (!sAGpsInterface) {
sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
}
if (sAGpsInterface) {
- sAGpsInterface->set_server(type, addr, port);
+ const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+ sAGpsInterface->set_server(type, c_hostname, port);
+ env->ReleaseStringUTFChars(hostname, c_hostname);
}
}
@@ -365,7 +367,7 @@ static JNINativeMethod sMethods[] = {
{"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
- {"native_set_agps_server", "(III)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+ {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
};
int register_android_location_GpsLocationProvider(JNIEnv* env)
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 void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDe
}
}
-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 @@ static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject claz
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 @@ static const JNINativeMethod methods[] = {
{"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_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 153d16e..14da1fd 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -79,6 +79,7 @@ static bool initNative(JNIEnv* env, jobject object) {
dbus_error_free(&err);
return false;
}
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
#endif /*HAVE_BLUETOOTH*/
return true;
}
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp
index 16bfc9c..b02a19b 100644
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ b/core/jni/android_server_BluetoothDeviceService.cpp
@@ -113,6 +113,7 @@ static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
dbus_error_free(&err);
return false;
}
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
#endif /*HAVE_BLUETOOTH*/
return true;
}
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index e0ea788..0857cb3 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -117,6 +117,7 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) {
LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
dbus_error_free(&err);
}
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
}
#endif
}
@@ -148,6 +149,19 @@ static const DBusObjectPathVTable agent_vtable = {
NULL, agent_event_filter, NULL, NULL, NULL, NULL
};
+static unsigned int unix_events_to_dbus_flags(short events) {
+ return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
+ (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
+ (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
+ (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
+}
+
+static short dbus_flags_to_unix_events(unsigned int flags) {
+ return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
+ (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
+ (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
+ (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
+}
static jboolean setUpEventLoop(native_data_t *nat) {
LOGV(__FUNCTION__);
@@ -407,8 +421,7 @@ static void handleWatchAdd(native_data_t *nat) {
read(nat->controlFdR, &newFD, sizeof(int));
read(nat->controlFdR, &flags, sizeof(unsigned int));
read(nat->controlFdR, &watch, sizeof(DBusWatch *));
- int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0)
- | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0);
+ short events = dbus_flags_to_unix_events(flags);
for (int y = 0; y<nat->pollMemberCount; y++) {
if ((nat->pollData[y].fd == newFD) &&
@@ -452,8 +465,7 @@ static void handleWatchRemove(native_data_t *nat) {
read(nat->controlFdR, &removeFD, sizeof(int));
read(nat->controlFdR, &flags, sizeof(unsigned int));
- int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0)
- | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0);
+ short events = dbus_flags_to_unix_events(flags);
for (int y = 0; y < nat->pollMemberCount; y++) {
if ((nat->pollData[y].fd == removeFD) &&
@@ -517,13 +529,12 @@ static void *eventLoopMain(void *ptr) {
}
}
} else {
- int event = nat->pollData[i].revents;
- int flags = (event & POLLIN ? DBUS_WATCH_READABLE : 0) |
- (event & POLLOUT ? DBUS_WATCH_WRITABLE : 0);
- dbus_watch_handle(nat->watchData[i], event);
- nat->pollData[i].revents = 0;
- // can only do one - it may have caused a 'remove'
- break;
+ short events = nat->pollData[i].revents;
+ unsigned int flags = unix_events_to_dbus_flags(events);
+ dbus_watch_handle(nat->watchData[i], flags);
+ nat->pollData[i].revents = 0;
+ // can only do one - it may have caused a 'remove'
+ break;
}
}
while (dbus_connection_dispatch(nat->conn) ==
diff --git a/core/res/res/drawable/call_contact.png b/core/res/res/drawable/call_contact.png
new file mode 100644
index 0000000..1abeb5d
--- /dev/null
+++ b/core/res/res/drawable/call_contact.png
Binary files differ
diff --git a/core/res/res/drawable/create_contact.png b/core/res/res/drawable/create_contact.png
new file mode 100644
index 0000000..5c5718b
--- /dev/null
+++ b/core/res/res/drawable/create_contact.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background_apps.9.png b/core/res/res/drawable/search_dropdown_background_apps.9.png
index 56b697d..804260a 100644
--- a/core/res/res/drawable/search_dropdown_background_apps.9.png
+++ b/core/res/res/drawable/search_dropdown_background_apps.9.png
Binary files differ
diff --git a/core/res/res/layout/recent_apps_dialog.xml b/core/res/res/layout/recent_apps_dialog.xml
index 852b2f1..c4ee95d 100644
--- a/core/res/res/layout/recent_apps_dialog.xml
+++ b/core/res/res/layout/recent_apps_dialog.xml
@@ -17,67 +17,63 @@
*/
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
+ android:layout_height="wrap_content"
+ android:padding="3dip"
+ android:orientation="vertical">
+
+ <!-- This is only intended to be visible when all buttons (below) are invisible -->
+ <TextView
+ android:id="@+id/no_applications_message"
+ android:layout_width="285dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="15dip"
+ android:layout_marginBottom="15dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@android:string/no_recent_tasks" />
+
+ <!-- The first row has a fixed-width because the UI spec requires the box
+ to display with full-width no matter how many icons are visible, but to
+ adjust height based on number of rows. -->
+ <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
+ <LinearLayout
+ android:layout_width="285dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button1" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button2" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button3" />
+
+ </LinearLayout>
+
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="3dip"
- android:orientation="vertical">
-
- <!-- This is only intended to be visible when all buttons (below) are invisible -->
- <TextView
- android:id="@+id/no_applications_message"
- android:layout_width="285dip"
- android:layout_height="wrap_content"
- android:layout_marginTop="15dip"
- android:layout_marginBottom="15dip"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@android:string/no_recent_tasks" />
-
- <!-- The first row has a fixed-width because the UI spec requires the box
- to display with full-width no matter how many icons are visible, but to
- adjust height based on number of rows. -->
- <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
- <LinearLayout
- android:layout_width="285dip"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button4" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button5" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button6" />
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button1" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button2" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button3" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button4" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button5" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button6" />
-
- </LinearLayout>
</LinearLayout>
-</FrameLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/layout/recent_apps_icon.xml b/core/res/res/layout/recent_apps_icon.xml
index b8cf089..d32643c 100644
--- a/core/res/res/layout/recent_apps_icon.xml
+++ b/core/res/res/layout/recent_apps_icon.xml
@@ -18,27 +18,22 @@
-->
<!-- This is not a standalone element - it is imported into recent_apps_dialog.xml -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/label"
+ style="?android:attr/buttonStyle"
+ android:background="@drawable/btn_application_selector"
android:layout_width="87dip"
- android:layout_height="78dip"
+ android:layout_height="88dip"
android:layout_margin="3dip"
- android:orientation="vertical"
- android:gravity="center_vertical"
- style="?android:attr/buttonStyle"
- android:background="@drawable/btn_application_selector">
- <ImageView android:id="@+id/icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_gravity="center_horizontal"
- android:scaleType="fitCenter" />
- <TextView android:id="@+id/label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="12dip"
- android:maxLines="1"
- android:ellipsize="end"
- android:duplicateParentState="true"
- android:textColor="@color/primary_text_dark_focused"
- android:gravity="center_horizontal" />
-</LinearLayout>
+ android:textColor="@color/primary_text_dark_focused"
+
+ android:paddingTop="5dip"
+ android:paddingBottom="2dip"
+ android:drawablePadding="0dip"
+
+ android:textSize="13dip"
+ android:maxLines="2"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:gravity="top|center_horizontal" />
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index 4826a41..2c20ffc 100644
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s، %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s، %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s - %6$s، %8$s %7$s، %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-bg-rBG/donottranslate-cldr.xml b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
index 010b974..cda072a 100644
--- a/core/res/res/values-bg-rBG/donottranslate-cldr.xml
+++ b/core/res/res/values-bg-rBG/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ca-rES/donottranslate-cldr.xml b/core/res/res/values-ca-rES/donottranslate-cldr.xml
index 4eabba7..d5abeef 100644
--- a/core/res/res/values-ca-rES/donottranslate-cldr.xml
+++ b/core/res/res/values-ca-rES/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml b/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
index 0670080..e933f20 100644
--- a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
+++ b/core/res/res/values-cs-rCZ/donottranslate-cldr.xml
@@ -107,10 +107,10 @@
<string name="abbrev_month_day_year">%-e.%-m.%Y</string>
<string name="month_day">%-e. %B</string>
<string name="month">%-B</string>
- <string name="month_year">%Y %B</string>
- <string name="abbrev_month_day">%b %-e</string>
- <string name="abbrev_month">%-b</string>
- <string name="abbrev_month_year">%Y %b</string>
+ <string name="month_year">%-B %Y</string>
+ <string name="abbrev_month_day">%-e.%-m</string>
+ <string name="abbrev_month">%-B</string>
+ <string name="abbrev_month_year">%-B %Y</string>
<string name="time1_time2">%1$s - %2$s</string>
<string name="date1_date2">%2$s - %5$s</string>
<string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
@@ -121,26 +121,27 @@
<string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
<string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
<string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
- <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
- <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
<string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
- <string name="time_wday_date">%1$s %2$s %3$s</string>
- <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
<string name="time_wday">%1$s %2$s</string>
<string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
- <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
<string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
<string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
<string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s</string>
<string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
- <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%B</string>
</resources>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 0670080..e933f20 100644
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -107,10 +107,10 @@
<string name="abbrev_month_day_year">%-e.%-m.%Y</string>
<string name="month_day">%-e. %B</string>
<string name="month">%-B</string>
- <string name="month_year">%Y %B</string>
- <string name="abbrev_month_day">%b %-e</string>
- <string name="abbrev_month">%-b</string>
- <string name="abbrev_month_year">%Y %b</string>
+ <string name="month_year">%-B %Y</string>
+ <string name="abbrev_month_day">%-e.%-m</string>
+ <string name="abbrev_month">%-B</string>
+ <string name="abbrev_month_year">%-B %Y</string>
<string name="time1_time2">%1$s - %2$s</string>
<string name="date1_date2">%2$s - %5$s</string>
<string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
@@ -121,26 +121,27 @@
<string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
<string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
<string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
- <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
- <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
<string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
- <string name="time_wday_date">%1$s %2$s %3$s</string>
- <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
<string name="time_wday">%1$s %2$s</string>
<string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
- <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
<string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
<string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
<string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s - %10$s %6$s, %9$s %7$s %8$s</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s - %6$s, %9$s %7$s %8$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s</string>
<string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
- <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%B</string>
</resources>
diff --git a/core/res/res/values-da-rDK/donottranslate-cldr.xml b/core/res/res/values-da-rDK/donottranslate-cldr.xml
index 4a2a656..8cef5b2 100644
--- a/core/res/res/values-da-rDK/donottranslate-cldr.xml
+++ b/core/res/res/values-da-rDK/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s den %3$s. %2$s - %6$s den %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-de-rAT/donottranslate-cldr.xml b/core/res/res/values-de-rAT/donottranslate-cldr.xml
index e6112ba..559e1ee 100644
--- a/core/res/res/values-de-rAT/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rAT/donottranslate-cldr.xml
@@ -110,4 +110,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-de-rCH/donottranslate-cldr.xml b/core/res/res/values-de-rCH/donottranslate-cldr.xml
index b611c08..2ca6787 100644
--- a/core/res/res/values-de-rCH/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rCH/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-de-rDE/donottranslate-cldr.xml b/core/res/res/values-de-rDE/donottranslate-cldr.xml
index b611c08..2ca6787 100644
--- a/core/res/res/values-de-rDE/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rDE/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-de-rLI/donottranslate-cldr.xml b/core/res/res/values-de-rLI/donottranslate-cldr.xml
index b611c08..2ca6787 100644
--- a/core/res/res/values-de-rLI/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rLI/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index b611c08..2ca6787 100644
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-el-rGR/donottranslate-cldr.xml b/core/res/res/values-el-rGR/donottranslate-cldr.xml
index f76281a..e8f02fb 100644
--- a/core/res/res/values-el-rGR/donottranslate-cldr.xml
+++ b/core/res/res/values-el-rGR/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index 223a22b..5d1a8f6 100644
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index 32fa2b0..5d7300e 100644
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%2$s %3$s - %7$s %8$s, %9$s</string>
<string name="same_month_mdy1_mdy2">%2$s %3$s-%8$s, %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s - %6$s, %7$s %8$s, %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index b90112f..b115c6e 100644
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index 4143da5..15fc8e8 100644
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 6522d67..2507ee8 100644
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index d29455a..07d4fe8 100644
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rSG/donottranslate-cldr.xml b/core/res/res/values-en-rSG/donottranslate-cldr.xml
index 56c58e2..286cc0e 100644
--- a/core/res/res/values-en-rSG/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rSG/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%2$s %3$s – %7$s %8$s, %9$s</string>
<string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index 56c58e2..286cc0e 100644
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%2$s %3$s – %7$s %8$s, %9$s</string>
<string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index e1aac04..9e8681b 100644
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-es-rES/donottranslate-cldr.xml b/core/res/res/values-es-rES/donottranslate-cldr.xml
index b516291..c1dc58b 100644
--- a/core/res/res/values-es-rES/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rES/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 587a615..24923c3 100644
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s de %2$s al %8$s de %7$s de %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s al %6$s %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index b516291..c1dc58b 100644
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index 40cda53..dd12e57 100644
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s – %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fr-rBE/donottranslate-cldr.xml b/core/res/res/values-fr-rBE/donottranslate-cldr.xml
index 0795cc5..ea4ecf2 100644
--- a/core/res/res/values-fr-rBE/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rBE/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s au %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s au %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/donottranslate-cldr.xml b/core/res/res/values-fr-rCA/donottranslate-cldr.xml
index 7802ee0..346b971 100644
--- a/core/res/res/values-fr-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rCA/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">du %3$s %2$s au %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">du %1$s %3$s %2$s au %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fr-rCH/donottranslate-cldr.xml b/core/res/res/values-fr-rCH/donottranslate-cldr.xml
index bbda44a..0a9835f 100644
--- a/core/res/res/values-fr-rCH/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rCH/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s au %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s au %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fr-rFR/donottranslate-cldr.xml b/core/res/res/values-fr-rFR/donottranslate-cldr.xml
index 76d4141..f340e83 100644
--- a/core/res/res/values-fr-rFR/donottranslate-cldr.xml
+++ b/core/res/res/values-fr-rFR/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index 76d4141..f340e83 100644
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-he-rIL/donottranslate-cldr.xml b/core/res/res/values-he-rIL/donottranslate-cldr.xml
index 1c8a6f7..e3feb1e 100644
--- a/core/res/res/values-he-rIL/donottranslate-cldr.xml
+++ b/core/res/res/values-he-rIL/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index ba4ded7..03da515 100644
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
<string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 8dcb426..b56f520 100644
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s. %2$s %3$s. - %7$s %8$s.</string>
<string name="same_month_mdy1_mdy2">%9$s. %2$s %3$s-%8$s.</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-id-rID/donottranslate-cldr.xml b/core/res/res/values-id-rID/donottranslate-cldr.xml
index feac981..22860a7 100644
--- a/core/res/res/values-id-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-id-rID/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
<string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-it-rCH/donottranslate-cldr.xml b/core/res/res/values-it-rCH/donottranslate-cldr.xml
index 6b76f8e..6d9b550 100644
--- a/core/res/res/values-it-rCH/donottranslate-cldr.xml
+++ b/core/res/res/values-it-rCH/donottranslate-cldr.xml
@@ -138,4 +138,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-it-rIT/donottranslate-cldr.xml b/core/res/res/values-it-rIT/donottranslate-cldr.xml
index 929f899..1bf7992 100644
--- a/core/res/res/values-it-rIT/donottranslate-cldr.xml
+++ b/core/res/res/values-it-rIT/donottranslate-cldr.xml
@@ -138,4 +138,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 929f899..1bf7992 100644
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -138,4 +138,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ja-rJP/donottranslate-cldr.xml b/core/res/res/values-ja-rJP/donottranslate-cldr.xml
index ae07433..10f2f79 100644
--- a/core/res/res/values-ja-rJP/donottranslate-cldr.xml
+++ b/core/res/res/values-ja-rJP/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s年%2$s%3$s日~%7$s月%8$s日</string>
<string name="same_month_mdy1_mdy2">%9$s年%2$s%3$s日~%8$s日</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日(%1$s)~%7$s月%8$s日(%6$s)</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index ae07433..10f2f79 100644
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s年%2$s%3$s日~%7$s月%8$s日</string>
<string name="same_month_mdy1_mdy2">%9$s年%2$s%3$s日~%8$s日</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日(%1$s)~%7$s月%8$s日(%6$s)</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ko-rKR/donottranslate-cldr.xml b/core/res/res/values-ko-rKR/donottranslate-cldr.xml
index 4ec1ba4..45ca90a 100644
--- a/core/res/res/values-ko-rKR/donottranslate-cldr.xml
+++ b/core/res/res/values-ko-rKR/donottranslate-cldr.xml
@@ -131,4 +131,5 @@
<string name="same_year_mdy1_mdy2">%9$s년 %2$s %3$s일 ~ %7$s월 %8$s일</string>
<string name="same_month_mdy1_mdy2">%9$s년 %2$s %3$s일~%8$s일</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s년 %2$s %3$s일 %1$s ~ %7$s월 %8$s일 %6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index 4ec1ba4..45ca90a 100644
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -131,4 +131,5 @@
<string name="same_year_mdy1_mdy2">%9$s년 %2$s %3$s일 ~ %7$s월 %8$s일</string>
<string name="same_month_mdy1_mdy2">%9$s년 %2$s %3$s일~%8$s일</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s년 %2$s %3$s일 %1$s ~ %7$s월 %8$s일 %6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 17f228d..636a180 100644
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s m. %2$s %3$s d. - %7$s %8$s d.</string>
<string name="same_month_mdy1_mdy2">%9$s m. %2$s %3$s d.-%8$s d.</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d.,%1$s - %7$s %8$s d.,%6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index e6c3b79..3dec1d2 100644
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s. gada %3$s. %2$s - %8$s. %7$s</string>
<string name="same_month_mdy1_mdy2">%9$s. gada %3$s.-%8$s. %2$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s. gada %3$s. %2$s - %6$s, y. gada %8$s. %7$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index 17c9b24..ecf0111 100644
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s–%8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s–%6$s %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-nl-rBE/donottranslate-cldr.xml b/core/res/res/values-nl-rBE/donottranslate-cldr.xml
index 72a4694..5b4cbf7 100644
--- a/core/res/res/values-nl-rBE/donottranslate-cldr.xml
+++ b/core/res/res/values-nl-rBE/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-nl-rNL/donottranslate-cldr.xml b/core/res/res/values-nl-rNL/donottranslate-cldr.xml
index 549d816..b6231b6 100644
--- a/core/res/res/values-nl-rNL/donottranslate-cldr.xml
+++ b/core/res/res/values-nl-rNL/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 549d816..b6231b6 100644
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-pl-rPL/donottranslate-cldr.xml b/core/res/res/values-pl-rPL/donottranslate-cldr.xml
index c4bed0d..4ad17bf 100644
--- a/core/res/res/values-pl-rPL/donottranslate-cldr.xml
+++ b/core/res/res/values-pl-rPL/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index c4bed0d..4ad17bf 100644
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/donottranslate-cldr.xml b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
index 7b3304c..4729055 100644
--- a/core/res/res/values-pt-rBR/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index b14dbcb..be0fdb7 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 7b3304c..4729055 100644
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index 3672c94..4622445 100644
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ru-rRU/donottranslate-cldr.xml b/core/res/res/values-ru-rRU/donottranslate-cldr.xml
index 2b8c235..21c06ff 100644
--- a/core/res/res/values-ru-rRU/donottranslate-cldr.xml
+++ b/core/res/res/values-ru-rRU/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s г.</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index 2b8c235..21c06ff 100644
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s г.</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s - %8$s %7$s %9$s г.</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index ea2a5ab..2b3c6d9 100644
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s. - %8$s. %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index b9c30c9..2b2b9c3 100644
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s. – %8$s. %7$s. %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s. %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index f88de6b..55ca968 100644
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s.</string>
<string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s.</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s.</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-sv-rSE/donottranslate-cldr.xml b/core/res/res/values-sv-rSE/donottranslate-cldr.xml
index c846719..a6ffc9a 100644
--- a/core/res/res/values-sv-rSE/donottranslate-cldr.xml
+++ b/core/res/res/values-sv-rSE/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s–%8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s–%6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index 53cd4d7..b3c76a3 100644
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-tr-rTR/donottranslate-cldr.xml b/core/res/res/values-tr-rTR/donottranslate-cldr.xml
index 2475b21..d612305 100644
--- a/core/res/res/values-tr-rTR/donottranslate-cldr.xml
+++ b/core/res/res/values-tr-rTR/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s %1$s - %8$s %7$s y %6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index 51dabd0..55d3983 100644
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
<string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 0d9eebc..71178cc 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">Ngày %3$s tháng %2$s - Ngày %8$s tháng %7$s năm %9$s</string>
<string name="same_month_mdy1_mdy2">Ngày %3$s tháng %2$s - Ngày %8$s tháng M năm %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, ngày %3$s %2$s - %6$s, ngày %8$s %7$s năm %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index 6685a7d..8c386a4 100644
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s年%2$s%3$s日至%7$s月%8$s日</string>
<string name="same_month_mdy1_mdy2">%9$s年%2$s%3$s日至%8$s日</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日%1$s至%7$s月%8$s日%6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index 6685a7d..8c386a4 100644
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%9$s年%2$s%3$s日至%7$s月%8$s日</string>
<string name="same_month_mdy1_mdy2">%9$s年%2$s%3$s日至%8$s日</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%9$s年%2$s%3$s日%1$s至%7$s月%8$s日%6$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index 56c58e2..286cc0e 100644
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -143,4 +143,5 @@
<string name="same_year_mdy1_mdy2">%2$s %3$s – %7$s %8$s, %9$s</string>
<string name="same_month_mdy1_mdy2">%2$s %3$s – %8$s, %9$s</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s</string>
+ <string name="short_format_month">%b</string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 19fde5c..91b6609 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -228,6 +228,8 @@
<string name="httpErrorFileNotFound">The requested file was not found.</string>
<!-- 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>
+ <!-- Displayed a toast that a certificate is saved in the keystore -->
+ <string name="certificateSaved">The certificate is saved in the system\'s key store.</string>
<!-- Account notifications --> <skip />
<!-- A notification is shown when the AccountManager is unable to
@@ -1306,6 +1308,9 @@
<string name="battery_low_percent_format">less than <xliff:g id="number">%d%%</xliff:g>
remaining.</string>
+ <!-- When the battery is low, this is the label of the button to go to the
+ power usage activity to find out what drained the battery. -->
+ <string name="battery_low_why">Why?</string>
<!-- Title of the alert when something went wrong in the factory test. -->
<string name="factorytest_failed">Factory test failed</string>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index e5a9aab..2a39987 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,6 +18,7 @@ package android.graphics;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.os.MemoryFile;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -435,6 +436,17 @@ public class BitmapFactory {
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
+ try {
+ if (MemoryFile.isMemoryFile(fd)) {
+ int mappedlength = MemoryFile.getMappedSize(fd);
+ MemoryFile file = new MemoryFile(fd, mappedlength, "r");
+ InputStream is = file.getInputStream();
+ return decodeStream(is, outPadding, opts);
+ }
+ } catch (IOException ex) {
+ // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
+ return null;
+ }
return nativeDecodeFileDescriptor(fd, outPadding, opts);
}
@@ -447,7 +459,7 @@ public class BitmapFactory {
* @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/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 06d53e3..4498e1a 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1404,7 +1404,11 @@ public class Canvas {
protected void finalize() throws Throwable {
super.finalize();
- finalizer(mNativeCanvas);
+ // If the constructor threw an exception before setting mNativeCanvas, the native finalizer
+ // must not be invoked.
+ if (mNativeCanvas != 0) {
+ finalizer(mNativeCanvas);
+ }
}
/**
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index d2aa30e..8486532 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -99,14 +99,18 @@ public:
// @param size length of the language value
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result loadLanguage(const char *value, const size_t size);
-
- // Signal the engine to use the specified language. This will force the
- // language to be loaded if it wasn't loaded previously with loadLanguage().
- // See loadLanguage for the specification of the language.
- // @param value pointer to the language value
- // @param size length of the language value
+
+ // Load the resources associated with the specified language, country and Locale variant.
+ // The loaded language will only be used once a call to setLanguageFromLocale() with the same
+ // language value is issued. Language and country values are coded according to the ISO three
+ // letter codes for languages and countries, as can be retrieved from a java.util.Locale
+ // instance. The variant value is encoded as the variant string retrieved from a
+ // java.util.Locale instance built with that variant data.
+ // @param lang pointer to the ISO three letter code for the language
+ // @param country pointer to the ISO three letter code for the country
+ // @param variant pointer to the variant code
// @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result setLanguage(const char *value, const size_t size);
+ virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
// Retrieve the currently set language, or an empty "value" if no language
// has been set.
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index f60f4ea..c78b99a 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -19,33 +19,40 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/KeyedVector.h>
namespace android {
enum {
- BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian)
BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
- BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian)
};
-// the sizes of all of these match.
-typedef struct {
- int type; // == BACKUP_HEADER_APP_V1
- int packageLen; // length of the name of the package that follows, not including the null.
- int cookie;
-} app_header_v1;
-
typedef struct {
int type; // BACKUP_HEADER_ENTITY_V1
int keyLen; // length of the key name, not including the null terminator
int dataSize; // size of the data, not including the padding, -1 means delete
} entity_header_v1;
-typedef struct {
- int type; // BACKUP_FOOTER_APP_V1
- int entityCount; // the number of entities that were written
- int cookie;
-} app_footer_v1;
+struct SnapshotHeader {
+ int magic0;
+ int fileCount;
+ int magic1;
+ int totalSize;
+};
+
+struct FileState {
+ int modTime_sec;
+ int modTime_nsec;
+ int size;
+ int crc32;
+ int nameLen;
+};
+
+struct FileRec {
+ String8 file;
+ bool deleted;
+ FileState s;
+};
/**
@@ -61,13 +68,9 @@ public:
// does not close fd
~BackupDataWriter();
- status_t WriteAppHeader(const String8& packageName, int cookie);
-
status_t WriteEntityHeader(const String8& key, size_t dataSize);
status_t WriteEntityData(const void* data, size_t size);
- status_t WriteAppFooter(int cookie);
-
private:
explicit BackupDataWriter();
status_t write_padding_for(int n);
@@ -92,34 +95,46 @@ public:
~BackupDataReader();
status_t Status();
- status_t ReadNextHeader(int* type = NULL);
+ status_t ReadNextHeader(bool* done, int* type);
- status_t ReadAppHeader(String8* packageName, int* cookie);
bool HasEntities();
status_t ReadEntityHeader(String8* key, size_t* dataSize);
status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
- status_t ReadEntityData(void* data, size_t size);
- status_t ReadAppFooter(int* cookie);
+ ssize_t ReadEntityData(void* data, size_t size);
private:
explicit BackupDataReader();
status_t skip_padding();
int m_fd;
+ bool m_done;
status_t m_status;
ssize_t m_pos;
+ ssize_t m_dataEndPos;
int m_entityCount;
union {
int type;
- app_header_v1 app;
entity_header_v1 entity;
- app_footer_v1 footer;
} m_header;
+ String8 m_key;
};
int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
char const* const* files, char const* const *keys, int fileCount);
+class RestoreHelperBase
+{
+public:
+ RestoreHelperBase();
+ ~RestoreHelperBase();
+
+ status_t WriteFile(const String8& filename, BackupDataReader* in);
+ status_t WriteSnapshot(int fd);
+
+private:
+ void* m_buf;
+ KeyedVector<String8,FileRec> m_files;
+};
#define TEST_BACKUP_HELPERS 1
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 9b8c302..68f9233 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1781,7 +1781,7 @@ public:
void getLocales(Vector<String8>* locales) const;
#ifndef HAVE_ANDROID_OS
- void print() const;
+ void print(bool inclValues) const;
#endif
private:
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index 71c1cf4..2a3e6a7 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -30,6 +30,7 @@ public abstract class Keystore {
return new FileKeystore();
}
+ // for compatiblity, start from here
/**
*/
public abstract String getUserkey(String key);
@@ -46,6 +47,34 @@ public abstract class Keystore {
*/
public abstract String[] getAllUserkeyKeys();
+ // to here
+
+ /**
+ */
+ public abstract String getCaCertificate(String key);
+
+ /**
+ */
+ public abstract String getUserCertificate(String key);
+
+ /**
+ */
+ public abstract String getUserPrivateKey(String key);
+
+ /**
+ * Returns the array of the certificate keynames in keystore if successful.
+ * Or return an empty array if error.
+ *
+ * @return array of the certificate keynames
+ */
+ public abstract String[] getAllUserCertificateKeys();
+
+ /**
+ */
+ public abstract String[] getAllCaCertificateKeys();
+
+ /**
+ */
public abstract String[] getSupportedKeyStrenghs();
/**
@@ -59,17 +88,29 @@ public abstract class Keystore {
public abstract String generateKeyPair(
int keyStrengthIndex, String challenge, String organizations);
- public abstract void addCertificate(String cert);
+ public abstract void addCertificate(byte[] cert);
private static class FileKeystore extends Keystore {
private static final String SERVICE_NAME = "keystore";
+ private static final String LIST_CA_CERTIFICATES = "listcacerts";
+ private static final String LIST_USER_CERTIFICATES = "listusercerts";
+ private static final String GET_CA_CERTIFICATE = "getcacert";
+ private static final String GET_USER_CERTIFICATE = "getusercert";
+ private static final String GET_USER_KEY = "getuserkey";
+ private static final String ADD_CA_CERTIFICATE = "addcacert";
+ private static final String ADD_USER_CERTIFICATE = "addusercert";
+ private static final String ADD_USER_KEY = "adduserkey";
+ private static final String COMMAND_DELIMITER = "\t";
+ private static final ServiceCommand mServiceCommand =
+ new ServiceCommand(SERVICE_NAME);
+
+ // for compatiblity, start from here
+
private static final String LIST_CERTIFICATES = "listcerts";
private static final String LIST_USERKEYS = "listuserkeys";
private static final String PATH = "/data/misc/keystore/";
private static final String USERKEY_PATH = PATH + "userkeys/";
private static final String CERT_PATH = PATH + "certs/";
- private static final ServiceCommand mServiceCommand =
- new ServiceCommand(SERVICE_NAME);
@Override
public String getUserkey(String key) {
@@ -81,12 +122,6 @@ public abstract class Keystore {
return CERT_PATH + key;
}
- /**
- * Returns the array of the certificate names in keystore if successful.
- * Or return an empty array if error.
- *
- * @return array of the certificates
- */
@Override
public String[] getAllCertificateKeys() {
try {
@@ -98,12 +133,6 @@ public abstract class Keystore {
}
}
- /**
- * Returns the array of the names of private keys in keystore if successful.
- * Or return an empty array if errors.
- *
- * @return array of the user keys
- */
@Override
public String[] getAllUserkeyKeys() {
try {
@@ -115,6 +144,48 @@ public abstract class Keystore {
}
}
+ // to here
+
+ @Override
+ public String getUserPrivateKey(String key) {
+ return mServiceCommand.execute(
+ GET_USER_KEY + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String getUserCertificate(String key) {
+ return mServiceCommand.execute(
+ GET_USER_CERTIFICATE + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String getCaCertificate(String key) {
+ return mServiceCommand.execute(
+ GET_CA_CERTIFICATE + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String[] getAllUserCertificateKeys() {
+ try {
+ String result = mServiceCommand.execute(LIST_USER_CERTIFICATES);
+ if (result != null) return result.split("\\s+");
+ return NOTFOUND;
+ } catch (NumberFormatException ex) {
+ return NOTFOUND;
+ }
+ }
+
+ @Override
+ public String[] getAllCaCertificateKeys() {
+ try {
+ String result = mServiceCommand.execute(LIST_CA_CERTIFICATES);
+ if (result != null) return result.split("\\s+");
+ return NOTFOUND;
+ } catch (NumberFormatException ex) {
+ return NOTFOUND;
+ }
+ }
+
@Override
public String[] getSupportedKeyStrenghs() {
// TODO: real implementation
@@ -146,8 +217,29 @@ public abstract class Keystore {
}
@Override
- public void addCertificate(String cert) {
+ public void addCertificate(byte[] cert) {
// TODO: real implementation
}
+
+ private boolean addUserCertificate(String key, String certificate,
+ String privateKey) {
+ if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + certificate) != null) {
+ if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + privateKey) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean addCaCertificate(String key, String content) {
+ if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + content) != null) {
+ return true;
+ }
+ return false;
+ }
+
}
}
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 1bf5f22..221ab41 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -30,64 +30,64 @@ typedef struct {
#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
typedef struct {
- const void * (*loadEnvVp)(void *con, uint32_t bank, uint32_t offset);
+ const void * (*loadEnvVp)(uint32_t bank, uint32_t offset);
- float (*loadEnvF)(void *con, uint32_t bank, uint32_t offset);
- int32_t (*loadEnvI32)(void *con, uint32_t bank, uint32_t offset);
- uint32_t (*loadEnvU32)(void *con, uint32_t bank, uint32_t offset);
- void (*loadEnvVec4)(void *con, uint32_t bank, uint32_t offset, rsc_Vector4 *);
- void (*loadEnvMatrix)(void *con, uint32_t bank, uint32_t offset, rsc_Matrix *);
+ float (*loadEnvF)(uint32_t bank, uint32_t offset);
+ int32_t (*loadEnvI32)(uint32_t bank, uint32_t offset);
+ uint32_t (*loadEnvU32)(uint32_t bank, uint32_t offset);
+ void (*loadEnvVec4)(uint32_t bank, uint32_t offset, rsc_Vector4 *);
+ void (*loadEnvMatrix)(uint32_t bank, uint32_t offset, rsc_Matrix *);
- void (*storeEnvF)(void *con, uint32_t bank, uint32_t offset, float);
- void (*storeEnvI32)(void *con, uint32_t bank, uint32_t offset, int32_t);
- void (*storeEnvU32)(void *con, uint32_t bank, uint32_t offset, uint32_t);
- void (*storeEnvVec4)(void *con, uint32_t bank, uint32_t offset, const rsc_Vector4 *);
- void (*storeEnvMatrix)(void *con, uint32_t bank, uint32_t offset, const rsc_Matrix *);
+ void (*storeEnvF)(uint32_t bank, uint32_t offset, float);
+ void (*storeEnvI32)(uint32_t bank, uint32_t offset, int32_t);
+ void (*storeEnvU32)(uint32_t bank, uint32_t offset, uint32_t);
+ void (*storeEnvVec4)(uint32_t bank, uint32_t offset, const rsc_Vector4 *);
+ void (*storeEnvMatrix)(uint32_t bank, uint32_t offset, const rsc_Matrix *);
- void (*matrixLoadIdentity)(void *con, rsc_Matrix *);
- void (*matrixLoadFloat)(void *con, rsc_Matrix *, const float *);
- void (*matrixLoadMat)(void *con, rsc_Matrix *, const rsc_Matrix *);
- void (*matrixLoadRotate)(void *con, rsc_Matrix *, float rot, float x, float y, float z);
- void (*matrixLoadScale)(void *con, rsc_Matrix *, float x, float y, float z);
- void (*matrixLoadTranslate)(void *con, rsc_Matrix *, float x, float y, float z);
- void (*matrixLoadMultiply)(void *con, rsc_Matrix *, const rsc_Matrix *lhs, const rsc_Matrix *rhs);
- void (*matrixMultiply)(void *con, rsc_Matrix *, const rsc_Matrix *rhs);
- void (*matrixRotate)(void *con, rsc_Matrix *, float rot, float x, float y, float z);
- void (*matrixScale)(void *con, rsc_Matrix *, float x, float y, float z);
- void (*matrixTranslate)(void *con, rsc_Matrix *, float x, float y, float z);
+ void (*matrixLoadIdentity)(rsc_Matrix *);
+ void (*matrixLoadFloat)(rsc_Matrix *, const float *);
+ void (*matrixLoadMat)(rsc_Matrix *, const rsc_Matrix *);
+ void (*matrixLoadRotate)(rsc_Matrix *, float rot, float x, float y, float z);
+ void (*matrixLoadScale)(rsc_Matrix *, float x, float y, float z);
+ void (*matrixLoadTranslate)(rsc_Matrix *, float x, float y, float z);
+ void (*matrixLoadMultiply)(rsc_Matrix *, const rsc_Matrix *lhs, const rsc_Matrix *rhs);
+ void (*matrixMultiply)(rsc_Matrix *, const rsc_Matrix *rhs);
+ void (*matrixRotate)(rsc_Matrix *, float rot, float x, float y, float z);
+ void (*matrixScale)(rsc_Matrix *, float x, float y, float z);
+ void (*matrixTranslate)(rsc_Matrix *, float x, float y, float z);
- void (*color)(void *con, float r, float g, float b, float a);
+ void (*color)(float r, float g, float b, float a);
- void (*programFragmentBindTexture)(void *con, RsProgramFragment, uint32_t slot, RsAllocation);
- void (*programFragmentBindSampler)(void *con, RsProgramFragment, uint32_t slot, RsAllocation);
+ void (*programFragmentBindTexture)(RsProgramFragment, uint32_t slot, RsAllocation);
+ void (*programFragmentBindSampler)(RsProgramFragment, uint32_t slot, RsAllocation);
- void (*materialDiffuse)(void *con, float r, float g, float b, float a);
- void (*materialSpecular)(void *con, float r, float g, float b, float a);
- void (*lightPosition)(void *con, float x, float y, float z, float w);
- void (*materialShininess)(void *con, float s);
+ void (*materialDiffuse)(float r, float g, float b, float a);
+ void (*materialSpecular)(float r, float g, float b, float a);
+ void (*lightPosition)(float x, float y, float z, float w);
+ void (*materialShininess)(float s);
- void (*uploadToTexture)(void *con, RsAllocation va, uint32_t baseMipLevel);
+ void (*uploadToTexture)(RsAllocation va, uint32_t baseMipLevel);
- void (*enable)(void *con, uint32_t);
- void (*disable)(void *con, uint32_t);
+ void (*enable)(uint32_t);
+ void (*disable)(uint32_t);
- uint32_t (*rand)(void *con, uint32_t max);
+ uint32_t (*rand)(uint32_t max);
- void (*contextBindProgramFragment)(void *con, RsProgramFragment pf);
- void (*contextBindProgramFragmentStore)(void *con, RsProgramFragmentStore pfs);
+ void (*contextBindProgramFragment)(RsProgramFragment pf);
+ void (*contextBindProgramFragmentStore)(RsProgramFragmentStore pfs);
// Drawing funcs
- void (*renderTriangleMesh)(void *con, RsTriangleMesh);
- void (*renderTriangleMeshRange)(void *con, RsTriangleMesh, uint32_t start, uint32_t count);
+ void (*renderTriangleMesh)(RsTriangleMesh);
+ void (*renderTriangleMeshRange)(RsTriangleMesh, uint32_t start, uint32_t count);
// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
- void (*drawTriangleArray)(void *con, RsAllocation alloc, uint32_t count);
+ void (*drawTriangleArray)(RsAllocation alloc, uint32_t count);
- void (*drawRect)(void *con, int32_t x1, int32_t x2, int32_t y1, int32_t y2);
+ void (*drawRect)(int32_t x1, int32_t x2, int32_t y1, int32_t y2);
} rsc_FunctionTable;
-typedef int (*rsc_RunScript)(void *con, const rsc_FunctionTable *, uint32_t launchID);
+typedef int (*rsc_RunScript)(uint32_t launchIndex, const rsc_FunctionTable *);
/* EnableCap */
diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Film/Android.mk
new file mode 100644
index 0000000..2e9c243
--- /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..491ee14
--- /dev/null
+++ b/libs/rs/java/Film/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.film">
+ <application android:label="Film">
+ <activity android:name="Film"
+ 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/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..75810c0
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -0,0 +1,131 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(default)
+#pragma stateFragmentStore(default)
+
+/*
+typedef struct FilmScriptUserEnvRec {
+ RsAllocation tex[13];
+ int32_t triangleOffsets[64];
+ float triangleOffsetsTex[64];
+ int32_t triangleOffsetsCount;
+} FilmScriptUserEnv;
+*/
+
+// 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(void* con, int ft, int index)
+{
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+ int f5;
+ int f6;
+ int f7;
+ int f8;
+ int f9;
+ int f10;
+ int f11;
+ int f12;
+ int f13;
+ int f14;
+ int f15;
+ int f16;
+
+ int trans; // float
+ int rot; // float
+
+
+ //trans = loadEnvF(con, 1, 0);
+ //rot = loadEnvF(con, 1, 1);
+
+ //matrixLoadTranslate(con, &f1, 0, 0, trans);
+ //matrixRotate(con, &f1, rot, 1, 0, 0);
+ //matrixScale(con, &f1, 3.0f, 3.0f, 3.0f);
+ //storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, &f1);
+
+ //rsc_Matrix m;
+ //int imgId = 0;
+
+ // This should be replaced in the compiler with a
+ // smart load of a structure.
+ //const FilmScriptUserEnv *env = loadEnvVp(con, 0,0);
+
+ //materialDiffuse(con, 0.0f, 0.0f, 0.0f, 1.0f);
+ //materialSpecular(con, 0.5f, 0.5f, 0.5f, 0.5f);
+ //materialShininess(con, 20.0f);
+
+
+
+ //lightPosition(con, 0.2f, -0.2f, -2.0f, 0.0f);
+
+ //contextBindProgramFragmentStore(con, NAMED_PFSBackground);
+ //contextBindProgramFragment(con, NAMED_PFBackground);
+ //enable(con, GL_LIGHTING);
+ renderTriangleMesh(con, NAMED_mesh);
+
+/*
+ contextBindProgramFragmentStore(con, env->fsImages);
+ contextBindProgramFragment(con, env->fpImages);
+ disable(con, GL_LIGHTING);
+
+ float focusPos = loadEnvF(con, 1, 2);
+ int32_t focusID = 0;
+ int32_t lastFocusID = loadEnvI32(con, 2, 0);
+ int32_t imgCount = 13;
+
+ if (trans > (-.3)) {
+ focusID = -1.0 - 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);
+ }
+ }
+ storeEnvI32(con, 2, 0, focusID);
+
+
+ for (imgId=1; imgId <= imgCount; imgId++) {
+ float pos = focusPos + imgId + .4f;
+ int offset = (int)floor(pos*2);
+ pos -= 0.75;
+
+ offset += env->triangleOffsetsCount / 2;
+
+ if ((offset < 0) || (offset >= env->triangleOffsetsCount)) {
+ continue;
+ }
+
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > env->triangleOffsetsCount) {
+ end = env->triangleOffsetsCount;
+ }
+
+ programFragmentBindTexture(con, env->fpImages, 0, env->tex[imgId - 1]);
+ matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
+ storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
+ renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
+ }
+*/
+}
+
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..b4b5f4b
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -0,0 +1,242 @@
+/*
+ * 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.renderscript.RenderScript;
+import android.renderscript.ProgramVertexAlloc;
+import android.renderscript.Matrix;
+
+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 FilmRS {
+
+ public FilmRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initNamed();
+ initRS();
+ }
+
+ public void setFilmStripPosition(int x, int y)
+ {
+ if (x < 0) {
+ x = 0;
+ }
+ if (x > 50) {
+ x = 50;
+ }
+
+ float anim = ((float)x) / 50.f;
+ mBufferPos[0] = -2f * anim - .2f; // translation
+ mBufferPos[1] = -90 + (anim * 40); // rotation
+ mBufferPos[2] = ((float)y) / 16.f - 8; // focusPos
+
+ mAllocPos.data(mBufferPos);
+ }
+
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private RenderScript.Script mScriptStrip;
+ private RenderScript.Script mScriptImage;
+ private RenderScript.Element mElementVertex;
+ private RenderScript.Element mElementIndex;
+ private RenderScript.Sampler mSampler;
+ private RenderScript.ProgramFragmentStore mPFSBackground;
+ private RenderScript.ProgramFragmentStore mPFSImages;
+ private RenderScript.ProgramFragment mPFBackground;
+ private RenderScript.ProgramFragment mPFImages;
+ private RenderScript.ProgramVertex mPV;
+ private ProgramVertexAlloc mPVA;
+
+ private RenderScript.Allocation mAllocEnv;
+ private RenderScript.Allocation mAllocPos;
+ private RenderScript.Allocation mAllocState;
+ private RenderScript.Allocation mAllocPV;
+ private RenderScript.TriangleMesh mMesh;
+
+ private float[] mBufferPos;
+ private float[] mBufferPV;
+
+ private void initNamed() {
+ mElementVertex = mRS.elementGetPredefined(
+ RenderScript.ElementPredefined.NORM_ST_XYZ_F32);
+ mElementIndex = mRS.elementGetPredefined(
+ RenderScript.ElementPredefined.INDEX_16);
+
+ mRS.triangleMeshBegin(mElementVertex, mElementIndex);
+ FilmStripMesh fsm = new FilmStripMesh();
+ fsm.init(mRS);
+ mMesh = mRS.triangleMeshCreate();
+ mMesh.setName("mesh");
+ Log.e("rs", "Done loading strips");
+
+
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN,
+ RenderScript.SamplerValue.LINEAR_MIP_LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_S,
+ RenderScript.SamplerValue.CLAMP);
+ mRS.samplerSet(RenderScript.SamplerParam.WRAP_MODE_T,
+ RenderScript.SamplerValue.CLAMP);
+ mSampler = mRS.samplerCreate();
+
+ mRS.programFragmentBegin(null, null);
+ mPFBackground = mRS.programFragmentCreate();
+ mPFBackground.setName("PFBackground");
+
+ mRS.programFragmentBegin(null, null);
+ mRS.programFragmentSetTexEnable(0, true);
+ //mRS.programFragmentSetEnvMode(0, RS_TEX_ENV_MODE_REPLACE);
+ //rsProgramFragmentSetType(0, gEnv.tex[0]->getType());
+ mPFImages = mRS.programFragmentCreate();
+ mPFImages.setName("PFImages");
+ mPFImages.bindSampler(mSampler, 0);
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
+ mRS.programFragmentStoreDitherEnable(true);
+ mPFSBackground = mRS.programFragmentStoreCreate();
+ mPFSBackground.setName("PFSBackground");
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.EQUAL);
+ mRS.programFragmentStoreDitherEnable(false);
+ mRS.programFragmentStoreDepthMask(false);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
+ RenderScript.BlendDstFunc.ONE);
+ mPFSImages = mRS.programFragmentStoreCreate();
+ mPFSImages.setName("PFSImages");
+
+ mRS.programVertexBegin(null, null);
+ mRS.programVertexSetTextureMatrixEnable(true);
+ mPV = mRS.programVertexCreate();
+ mPV.setName("PV");
+
+ Log.e("rs", "Done loading named");
+ }
+
+
+ private Bitmap mBackground;
+
+ int mParams[] = new int[10];
+
+ private void initRS() {
+ int partCount = 1024;
+
+ mRS.scriptCBegin();
+ mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ mRS.scriptCSetScript(mRes, R.raw.filmstrip);
+ mRS.scriptCSetRoot(true);
+ mScriptStrip = mRS.scriptCCreate();
+
+ mBufferPos = new float[3];
+ mAllocPos = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferPos.length);
+ setFilmStripPosition(0, 0);
+
+ mPVA = new ProgramVertexAlloc(mRS);
+ mPV.bindAllocation(0, mPVA.mAlloc);
+ mPVA.setupProjectionNormalized(320, 480);
+
+ Matrix m = new Matrix();
+
+ m.loadIdentity();
+
+ m.translate(0, 0, 1);
+ m.rotate(90, 0, 0, 1);
+ m.rotate(20, 1, 0, 0);
+ mPVA.loadModelview(m);
+
+
+
+
+
+ //mScriptStrip.bindAllocation(mEnvAlloc, 0);
+ mScriptStrip.bindAllocation(mAllocPos, 1);
+ //mScriptStrip.bindAllocation(gStateAlloc, 2);
+ mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
+
+
+ //mIntAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, 10);
+ //mPartAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 3 * 3);
+ //mPartAlloc.setName("PartBuffer");
+ //mVertAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 5 + 1);
+/*
+ {
+ Resources res = getResources();
+ Drawable d = res.getDrawable(R.drawable.gadgets_clock_mp3);
+ BitmapDrawable bd = (BitmapDrawable)d;
+ Bitmap b = bd.getBitmap();
+ mTexture = mRS.allocationCreateFromBitmap(b,
+ RenderScript.ElementPredefined.RGB_565,
+ true);
+ mTexture.uploadToTexture(0);
+ }
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA, RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.ALWAYS);
+ mPFS = mRS.programFragmentStoreCreate();
+ mPFS.setName("MyBlend");
+ mRS.contextBindProgramFragmentStore(mPFS);
+
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MAG, RenderScript.SamplerValue.LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN, RenderScript.SamplerValue.LINEAR);
+ mSampler = mRS.samplerCreate();
+
+
+ mParams[0] = 0;
+ mParams[1] = partCount;
+ mParams[2] = 0;
+ mParams[3] = 0;
+ mParams[4] = 0;
+ mIntAlloc.data(mParams);
+
+ int t2[] = new int[partCount * 4*3];
+ for (int ct=0; ct < t2.length; ct++) {
+ t2[ct] = 0;
+ }
+ mPartAlloc.data(t2);
+ */
+
+ 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..452d522
--- /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.newTouchPosition((int)ev.getX(), (int)ev.getY());
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index 3bd9496..8a55406 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -1,13 +1,12 @@
// Fountain test script
#pragma version(1)
-#pragma stateVertex(orthoWindow)
-#pragma stateRaster(flat)
+#pragma stateVertex(default)
#pragma stateFragment(PgmFragBackground)
-#pragma stateFragmentStore(MyBlend)
+#pragma stateFragmentStore(parent)
-int main(void* con, int ft, int launchID) {
+int main(int launchID) {
int count, touch, x, y, rate, maxLife, lifeShift;
int life;
int ct, ct2;
@@ -19,10 +18,10 @@ int main(void* con, int ft, int launchID) {
int srcIdx;
int dstIdx;
- count = loadI32(con, 0, 1);
- touch = loadI32(con, 0, 2);
- x = loadI32(con, 0, 3);
- y = loadI32(con, 0, 4);
+ count = loadI32(0, 1);
+ touch = loadI32(0, 2);
+ x = loadI32(0, 3);
+ y = loadI32(0, 4);
rate = 4;
maxLife = (count / rate) - 1;
@@ -35,56 +34,56 @@ int main(void* con, int ft, int launchID) {
}
}
- drawRect(con, 0, 256, 0, 512);
- contextBindProgramFragment(con, NAMED_PgmFragParts);
+ drawRect(0, 256, 0, 512);
+ contextBindProgramFragment(NAMED_PgmFragParts);
if (touch) {
- newPart = loadI32(con, 2, 0);
+ newPart = loadI32(2, 0);
for (ct2=0; ct2<rate; ct2++) {
- dx = scriptRand(con, 0x10000) - 0x8000;
- dy = scriptRand(con, 0x10000) - 0x8000;
+ dx = scriptRand(0x10000) - 0x8000;
+ dy = scriptRand(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);
+ storeI32(2, idx, dx);
+ storeI32(2, idx + 1, dy);
+ storeI32(2, idx + 2, maxLife);
+ storeI32(2, idx + 3, x << 16);
+ storeI32(2, idx + 4, y << 16);
newPart++;
if (newPart >= count) {
newPart = 0;
}
}
- storeI32(con, 2, 0, newPart);
+ storeI32(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);
+ dx = loadI32(2, srcIdx);
+ dy = loadI32(2, srcIdx + 1);
+ life = loadI32(2, srcIdx + 2);
+ posx = loadI32(2, srcIdx + 3);
+ posy = loadI32(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(1, dstIdx, c);
+ storeI32(1, dstIdx + 1, posx);
+ storeI32(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(1, dstIdx + 3, c);
+ storeI32(1, dstIdx + 4, posx + 0x10000);
+ storeI32(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);
+ storeU32(1, dstIdx + 6, c);
+ storeI32(1, dstIdx + 7, posx - 0x10000);
+ storeI32(1, dstIdx + 8, posy + dy * 4);
drawCount ++;
} else {
if (dy > 0) {
@@ -97,14 +96,14 @@ int main(void* con, int ft, int launchID) {
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);
+ //storeI32(2, srcIdx, dx);
+ storeI32(2, srcIdx + 1, dy);
+ storeI32(2, srcIdx + 2, life);
+ storeI32(2, srcIdx + 3, posx);
+ storeI32(2, srcIdx + 4, posy);
}
}
- drawTriangleArray(con, NAMED_PartBuffer, drawCount);
+ drawTriangleArray(NAMED_PartBuffer, drawCount);
return 1;
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index 0a0b05a..467115a 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -18,12 +18,13 @@ package com.android.fountain;
import java.io.Writer;
-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.renderscript.RenderScript;
+import android.renderscript.ProgramVertexAlloc;
import android.util.Log;
public class FountainRS {
@@ -107,6 +108,7 @@ public class FountainRS {
mPF2.bindSampler(mSampler, 0);
mPF2.setName("PgmFragBackground");
+
mParams[0] = 0;
mParams[1] = partCount;
mParams[2] = 0;
diff --git a/libs/rs/java/RenderScript/android/renderscript/Matrix.java b/libs/rs/java/RenderScript/android/renderscript/Matrix.java
index 03222aa..79b60d0 100644
--- a/libs/rs/java/RenderScript/android/renderscript/Matrix.java
+++ b/libs/rs/java/RenderScript/android/renderscript/Matrix.java
@@ -20,7 +20,7 @@ import java.lang.Math;
import android.util.Log;
-class Matrix {
+public class Matrix {
public Matrix() {
mMat = new float[16];
@@ -139,8 +139,8 @@ class Matrix {
mMat[5] = 2 / (t - b);
mMat[10]= -2 / (f - n);
mMat[12]= -(r + l) / (r - l);
- mMat[12]= -(t + b) / (t - b);
- mMat[12]= -(f + n) / (f - n);
+ 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) {
diff --git a/libs/rs/java/RenderScript/android/renderscript/RenderScript.java b/libs/rs/java/RenderScript/android/renderscript/RenderScript.java
index afb4ae3..4d5c4a0 100644
--- a/libs/rs/java/RenderScript/android/renderscript/RenderScript.java
+++ b/libs/rs/java/RenderScript/android/renderscript/RenderScript.java
@@ -154,10 +154,7 @@ public class RenderScript {
native private void nProgramVertexBindAllocation(int pv, int slot, int mID);
native private void nProgramVertexBegin(int inID, int outID);
native private void nProgramVertexSetType(int slot, int mID);
- native private void nProgramVertexSetCameraMode(boolean isOrtho);
native private void nProgramVertexSetTextureMatrixEnable(boolean enable);
- native private void nProgramVertexSetModelMatrixEnable(boolean enable);
- native private void nProgramVertexSetProjectionMatrixEnable(boolean enable);
native private int nProgramVertexCreate();
@@ -733,22 +730,10 @@ public class RenderScript {
nProgramVertexSetType(slot, t.mID);
}
- public void programVertexSetCameraMode(boolean isOrtho) {
- nProgramVertexSetCameraMode(isOrtho);
- }
-
public void programVertexSetTextureMatrixEnable(boolean enable) {
nProgramVertexSetTextureMatrixEnable(enable);
}
- public void programVertexSetModelMatrixEnable(boolean enable) {
- nProgramVertexSetModelMatrixEnable(enable);
- }
-
- public void programVertexSetProjectionMatrixEnable(boolean enable) {
- nProgramVertexSetProjectionMatrixEnable(enable);
- }
-
public ProgramVertex programVertexCreate() {
int id = nProgramVertexCreate();
return new ProgramVertex(id);
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
index b81c567..56ee425 100644
--- a/libs/rs/java/Rollo/res/raw/rollo.c
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -8,6 +8,7 @@ int main(void* con, int ft, int launchID)
int x;
renderTriangleMesh(con, NAMED_MeshCard);
+ renderTriangleMesh(con, NAMED_MeshTab);
return 1;
}
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
index c44a817..d7252fb 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
@@ -24,6 +24,11 @@ import android.renderscript.RenderScript;
class RolloMesh {
+ static public final float mCardHeight = 1.2f;
+ static public final float mCardWidth = 1.8f;
+ static public final float mTabHeight = 0.2f;
+ static public final float mTabs = 3;
+ static public final float mTabGap = 0.1f;
static RenderScript.TriangleMesh createCard(RenderScript rs) {
RenderScript.Element vtx = rs.elementGetPredefined(
@@ -31,12 +36,15 @@ class RolloMesh {
RenderScript.Element idx = rs.elementGetPredefined(
RenderScript.ElementPredefined.INDEX_16);
- rs.triangleMeshBegin(vtx, idx);
- rs.triangleMeshAddVertex_XYZ_ST(0, 0, 0, 0, 0);
- rs.triangleMeshAddVertex_XYZ_ST(0, 1, 0, 0, 1);
- rs.triangleMeshAddVertex_XYZ_ST(1, 1, 0, 1, 1);
- rs.triangleMeshAddVertex_XYZ_ST(1, 0, 0, 1, 0);
+ float w = mCardWidth / 2;
+ float h = mCardHeight;
+ float z = 0;
+ rs.triangleMeshBegin(vtx, idx);
+ rs.triangleMeshAddVertex_XYZ_ST(-w, 0, z, 0, 0);
+ rs.triangleMeshAddVertex_XYZ_ST(-w, h, z, 0, 1);
+ rs.triangleMeshAddVertex_XYZ_ST( w, h, z, 1, 1);
+ rs.triangleMeshAddVertex_XYZ_ST( w, 0, z, 1, 0);
rs.triangleMeshAddTriangle(0,1,2);
rs.triangleMeshAddTriangle(0,2,3);
return rs.triangleMeshCreate();
@@ -48,11 +56,28 @@ class RolloMesh {
RenderScript.Element idx = rs.elementGetPredefined(
RenderScript.ElementPredefined.INDEX_16);
+
+ float tabSlope = 0.1f;
+ float num = 0;
+
+ float w = (mCardWidth - ((mTabs - 1) * mTabGap)) / mTabs;
+ float w1 = -(mCardWidth / 2) + ((w + mTabGap) * num);
+ float w2 = w1 + (w * tabSlope);
+ float w3 = w1 + w - (w * tabSlope);
+ float w4 = w1 + w;
+ float h1 = mCardHeight;
+ float h2 = h1 + mTabHeight;
+ float z = 0;
+
+ float stScale = w / mTabHeight / 2;
+ float stScale2 = stScale * (tabSlope / w);
+
+
rs.triangleMeshBegin(vtx, idx);
- rs.triangleMeshAddVertex_XYZ_ST(0.0f, 0, 0, -1.0f, 0);
- rs.triangleMeshAddVertex_XYZ_ST(0.2f, 1, 0, -0.8f, 1);
- rs.triangleMeshAddVertex_XYZ_ST(1.8f, 1, 0, 0.8f, 1);
- rs.triangleMeshAddVertex_XYZ_ST(2.0f, 0, 0, 1.0f, 0);
+ rs.triangleMeshAddVertex_XYZ_ST(w1, h1, z, -stScale, 0);
+ rs.triangleMeshAddVertex_XYZ_ST(w2, h2, z, -stScale2, 1);
+ rs.triangleMeshAddVertex_XYZ_ST(w3, h2, z, stScale2, 1);
+ rs.triangleMeshAddVertex_XYZ_ST(w4, h1, z, stScale, 0);
rs.triangleMeshAddTriangle(0,1,2);
rs.triangleMeshAddTriangle(0,2,3);
return rs.triangleMeshCreate();
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
index aa9f338..da0b146 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -74,8 +74,8 @@ public class RolloRS {
//private float[] mBufferPV;
private void initNamed() {
- //mMeshTab = RolloMesh.createTab(mRS);
- //mMeshTab.setName("MeshTab");
+ mMeshTab = RolloMesh.createTab(mRS);
+ mMeshTab.setName("MeshTab");
mMeshCard = RolloMesh.createCard(mRS);
mMeshCard.setName("MeshCard");
Log.e("rs", "Done loading strips");
@@ -117,10 +117,7 @@ public class RolloRS {
mPVAlloc = new ProgramVertexAlloc(mRS);
mRS.programVertexBegin(null, null);
- mRS.programVertexSetCameraMode(true);
mRS.programVertexSetTextureMatrixEnable(true);
- mRS.programVertexSetModelMatrixEnable(true);
- mRS.programVertexSetProjectionMatrixEnable(true);
mPV = mRS.programVertexCreate();
mPV.setName("PV");
mPV.bindAllocation(0, mPVAlloc.mAlloc);
diff --git a/libs/rs/jni/RenderScript_jni.cpp b/libs/rs/jni/RenderScript_jni.cpp
index 7a3a7af..ab17a4a 100644
--- a/libs/rs/jni/RenderScript_jni.cpp
+++ b/libs/rs/jni/RenderScript_jni.cpp
@@ -791,14 +791,6 @@ nProgramVertexSetType(JNIEnv *_env, jobject _this, jint slot, jint t)
}
static void
-nProgramVertexSetCameraMode(JNIEnv *_env, jobject _this, jboolean isOrtho)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramVertexSetCameraMode, con(%p), isOrtho(%i)", con, isOrtho);
- rsProgramVertexSetCameraMode(isOrtho);
-}
-
-static void
nProgramVertexSetTextureMatrixEnable(JNIEnv *_env, jobject _this, jboolean enable)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -806,22 +798,6 @@ nProgramVertexSetTextureMatrixEnable(JNIEnv *_env, jobject _this, jboolean enabl
rsProgramVertexSetTextureMatrixEnable(enable);
}
-static void
-nProgramVertexSetModelMatrixEnable(JNIEnv *_env, jobject _this, jboolean enable)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramVertexSetModelMatrixEnable, con(%p), enable(%i)", con, enable);
- rsProgramVertexSetModelMatrixEnable(enable);
-}
-
-static void
-nProgramVertexSetProjectionMatrixEnable(JNIEnv *_env, jobject _this, jboolean enable)
-{
- RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nProgramVertexSetProjectionMatrixEnable, con(%p), enable(%i)", con, enable);
- rsProgramVertexSetProjectionMatrixEnable(enable);
-}
-
static jint
nProgramVertexCreate(JNIEnv *_env, jobject _this)
{
@@ -1000,10 +976,7 @@ static JNINativeMethod methods[] = {
{"nProgramVertexBindAllocation", "(III)V", (void*)nProgramVertexBindAllocation },
{"nProgramVertexBegin", "(II)V", (void*)nProgramVertexBegin },
{"nProgramVertexSetType", "(II)V", (void*)nProgramVertexSetType },
-{"nProgramVertexSetCameraMode", "(Z)V", (void*)nProgramVertexSetCameraMode },
{"nProgramVertexSetTextureMatrixEnable", "(Z)V", (void*)nProgramVertexSetTextureMatrixEnable },
-{"nProgramVertexSetModelMatrixEnable", "(Z)V", (void*)nProgramVertexSetModelMatrixEnable },
-{"nProgramVertexSetProjectionMatrixEnable", "(Z)V", (void*)nProgramVertexSetProjectionMatrixEnable },
{"nProgramVertexCreate", "()I", (void*)nProgramVertexCreate },
{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript },
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 107096f..dd489b8 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -286,10 +286,6 @@ ScriptCSetRoot {
param bool isRoot
}
-ScriptCSetOrtho {
- param bool isOrtho
- }
-
ScriptCSetScript {
param void * codePtr
}
@@ -403,19 +399,7 @@ ProgramVertexSetType {
param RsType constants
}
-ProgramVertexSetCameraMode {
- param bool ortho
- }
-
ProgramVertexSetTextureMatrixEnable {
param bool enable
}
-ProgramVertexSetModelMatrixEnable {
- param bool enable
- }
-
-ProgramVertexSetProjectionMatrixEnable {
- param bool enable
- }
-
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 266c455..7c46c0e 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -23,6 +23,7 @@ using namespace android;
using namespace android::renderscript;
Context * Context::gCon = NULL;
+pthread_key_t Context::gThreadTLSKey = 0;
void Context::initEGL()
{
@@ -81,24 +82,6 @@ bool Context::runRootScript()
glEnable(GL_LIGHT0);
glViewport(0, 0, mWidth, mHeight);
- if(mRootScript->mEnviroment.mIsOrtho) {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrthof(0, mWidth, mHeight, 0, 0, 1);
- glMatrixMode(GL_MODELVIEW);
- } else {
- float aspectH = ((float)mWidth) / mHeight;
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustumf(-1, 1, -aspectH, aspectH, 1, 100);
- glRotatef(-90, 0,0,1);
- glTranslatef(0, 0, -3);
- glMatrixMode(GL_MODELVIEW);
- }
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -137,17 +120,33 @@ void * Context::threadProc(void *vrsc)
rsc->mServerReturns.init(128);
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 |= gIO->playCoreCommands(rsc);
-
- if (!mDraw || !rsc->mRootScript.get()) {
- usleep(10000);
- continue;
- }
+ mDraw |= gIO->playCoreCommands(rsc, !mDraw);
+ mDraw &= (rsc->mRootScript.get() != NULL);
- if (rsc->mRootScript.get()) {
+ if (mDraw) {
mDraw = rsc->runRootScript();
eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
}
@@ -176,6 +175,12 @@ Context::Context(Device *dev, Surface *sur)
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.");
@@ -209,6 +214,7 @@ Context::~Context()
if (mDev) {
mDev->removeContext(this);
+ pthread_key_delete(gThreadTLSKey);
}
}
@@ -230,20 +236,32 @@ void Context::setRootScript(Script *s)
void Context::setFragmentStore(ProgramFragmentStore *pfs)
{
- mFragmentStore.set(pfs);
- pfs->setupGL();
+ if (pfs == NULL) {
+ mFragmentStore.set(mStateFragmentStore.mDefault);
+ } else {
+ mFragmentStore.set(pfs);
+ }
+ mFragmentStore->setupGL();
}
void Context::setFragment(ProgramFragment *pf)
{
- mFragment.set(pf);
- pf->setupGL();
+ if (pf == NULL) {
+ mFragment.set(mStateFragment.mDefault);
+ } else {
+ mFragment.set(pf);
+ }
+ mFragment->setupGL();
}
void Context::setVertex(ProgramVertex *pv)
{
- mVertex.set(pv);
- pv->setupGL();
+ if (pv == NULL) {
+ mVertex.set(mStateVertex.mDefault);
+ } else {
+ mVertex.set(pv);
+ }
+ mVertex->setupGL();
}
void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 21ae8c5..334ef3c 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -48,6 +48,12 @@ public:
Context(Device *, Surface *);
~Context();
+ static pthread_key_t gThreadTLSKey;
+ struct ScriptTLSStruct {
+ Context * mContext;
+ Script * mScript;
+ };
+
//StructuredAllocationContext mStateAllocation;
ElementState mStateElement;
@@ -81,6 +87,17 @@ public:
ObjectBase * lookupName(const char *name) const;
void appendNameDefines(String8 *str) const;
+
+ ProgramFragment * getDefaultProgramFragment() const {
+ return mStateFragment.mDefault.get();
+ }
+ ProgramVertex * getDefaultProgramVertex() const {
+ return mStateVertex.mDefault.get();
+ }
+ ProgramFragmentStore * getDefaultProgramFragmentStore() const {
+ return mStateFragmentStore.mDefault.get();
+ }
+
protected:
Device *mDev;
@@ -107,10 +124,6 @@ protected:
ObjectBaseRef<ProgramVertex> mVertex;
ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
- ProgramFragment * mDefaultFragment;
- ProgramVertex * mDefaultVertex;
- ProgramFragmentStore * mDefaultFragmentStore;
-
private:
Context();
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 67ab434..37ec14b 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -37,16 +37,8 @@ bool LocklessCommandFifo::init(uint32_t sizeInBytes)
return false;
}
- int status = pthread_mutex_init(&mMutex, NULL);
- if (status) {
- LOGE("LocklessFifo mutex init failure");
- free(mBuffer);
- return false;
- }
- status = pthread_cond_init(&mCondition, NULL);
- if (status) {
- LOGE("LocklessFifo condition init failure");
- pthread_mutex_destroy(&mMutex);
+ if (!mSignalToControl.init() || !mSignalToWorker.init()) {
+ LOGE("Signal setup failed");
free(mBuffer);
return false;
}
@@ -106,6 +98,7 @@ void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
mPut += ((sizeInBytes + 3) & ~3) + 4;
//dumpState("commit 2");
+ mSignalToWorker.set();
}
void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
@@ -118,7 +111,7 @@ void LocklessCommandFifo::flush()
{
//dumpState("flush 1");
while(mPut != mGet) {
- usleep(1);
+ mSignalToControl.wait();
}
//dumpState("flush 2");
}
@@ -126,8 +119,10 @@ void LocklessCommandFifo::flush()
const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
{
while(1) {
+ //dumpState("get");
while(isEmpty()) {
- usleep(10);
+ mSignalToControl.set();
+ mSignalToWorker.wait();
}
//dumpState("get 3");
@@ -149,6 +144,9 @@ void LocklessCommandFifo::next()
{
uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
mGet += ((bytes + 3) & ~3) + 4;
+ if (isEmpty()) {
+ mSignalToControl.set();
+ }
//dumpState("next");
}
@@ -179,4 +177,79 @@ void LocklessCommandFifo::dumpState(const char *s) const
LOGE("%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
index ddef382..2f4d5c5 100644
--- a/libs/rs/rsLocklessFifo.h
+++ b/libs/rs/rsLocklessFifo.h
@@ -41,14 +41,32 @@ public:
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;
- pthread_mutex_t mMutex;
- pthread_cond_t mCondition;
+ Signal mSignalToWorker;
+ Signal mSignalToControl;
+
+
public:
void * reserve(uint32_t bytes);
diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp
index e68d5ac..258b836 100644
--- a/libs/rs/rsMatrix.cpp
+++ b/libs/rs/rsMatrix.cpp
@@ -136,4 +136,26 @@ void Matrix::loadMultiply(const Matrix *lhs, const Matrix *rhs)
}
}
+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
index 619b494..7dc4165 100644
--- a/libs/rs/rsMatrix.h
+++ b/libs/rs/rsMatrix.h
@@ -44,6 +44,9 @@ struct Matrix
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);
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 316e791..8777335 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -148,6 +148,11 @@ ProgramFragmentState::~ProgramFragmentState()
}
+void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragment *pf = new ProgramFragment(NULL, NULL);
+ mDefault.set(pf);
+}
namespace android {
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index ed9c49b..896d8dd 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -82,9 +82,10 @@ public:
~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;
};
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
index a1855a6..96d37ae 100644
--- a/libs/rs/rsProgramFragmentStore.cpp
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -201,6 +201,12 @@ ProgramFragmentStoreState::~ProgramFragmentStoreState()
}
+void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragmentStore *pfs = new ProgramFragmentStore(NULL, NULL);
+ mDefault.set(pfs);
+}
+
namespace android {
namespace renderscript {
diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h
index d862775..bd3a9f4 100644
--- a/libs/rs/rsProgramFragmentStore.h
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -74,7 +74,9 @@ class ProgramFragmentStoreState
public:
ProgramFragmentStoreState();
~ProgramFragmentStoreState();
+ void init(Context *rsc, int32_t w, int32_t h);
+ ObjectBaseRef<ProgramFragmentStore> mDefault;
ProgramFragmentStore *mPFS;
};
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index fc26ab5..19afad5 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -25,14 +25,21 @@ ProgramVertex::ProgramVertex(Element *in, Element *out) :
Program(in, out)
{
mTextureMatrixEnable = false;
- mProjectionEnable = false;
- mTransformEnable = false;
}
ProgramVertex::~ProgramVertex()
{
}
+static void logMatrix(const char *txt, const float *f)
+{
+ LOGE("Matrix %s, %p", txt, f);
+ LOGE("%6.2f, %6.2f, %6.2f, %6.2f", f[0], f[4], f[8], f[12]);
+ LOGE("%6.2f, %6.2f, %6.2f, %6.2f", f[1], f[5], f[9], f[13]);
+ LOGE("%6.2f, %6.2f, %6.2f, %6.2f", f[2], f[6], f[10], f[14]);
+ LOGE("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]);
+}
+
void ProgramVertex::setupGL()
{
const float *f = static_cast<const float *>(mConstants[0]->getPtr());
@@ -44,19 +51,13 @@ void ProgramVertex::setupGL()
glLoadIdentity();
}
+ //logMatrix("prog", &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
+ //logMatrix("model", &f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
glMatrixMode(GL_PROJECTION);
- if (mProjectionEnable) {
- glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
- } else {
- }
-
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
glMatrixMode(GL_MODELVIEW);
- if (mTransformEnable) {
- glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
- } else {
- glLoadIdentity();
- }
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
}
void ProgramVertex::setConstantType(uint32_t slot, const Type *t)
@@ -80,6 +81,23 @@ 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(0, 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 {
@@ -110,26 +128,11 @@ void rsi_ProgramVertexSetType(Context *rsc, uint32_t slot, RsType constants)
rsc->mStateVertex.mPV->setConstantType(slot, static_cast<const Type *>(constants));
}
-void rsi_ProgramVertexSetCameraMode(Context *rsc, bool ortho)
-{
- rsc->mStateVertex.mPV->setProjectionEnabled(!ortho);
-}
-
void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable)
{
rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
}
-void rsi_ProgramVertexSetModelMatrixEnable(Context *rsc, bool enable)
-{
- rsc->mStateVertex.mPV->setTransformEnable(enable);
-}
-
-void rsi_ProgramVertexSetProjectionMatrixEnable(Context *rsc, bool enable)
-{
- rsc->mStateVertex.mPV->setProjectionEnable(enable);
-}
-
}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 677be6e..1a92f01 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -38,9 +38,6 @@ public:
void setConstantType(uint32_t slot, const Type *);
void bindAllocation(uint32_t slot, Allocation *);
void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
- void setProjectionEnabled(bool e) {mProjectionEnable = e;}
- void setTransformEnable(bool e) {mTransformEnable = e;}
- void setProjectionEnable(bool e) {mProjectionEnable = e;}
protected:
bool mDirty;
@@ -50,8 +47,6 @@ protected:
// Hacks to create a program for now
bool mTextureMatrixEnable;
- bool mProjectionEnable;
- bool mTransformEnable;
};
@@ -62,6 +57,11 @@ public:
ProgramVertexState();
~ProgramVertexState();
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramVertex> mDefault;
+ ObjectBaseRef<Allocation> mDefaultAlloc;
+
ProgramVertex *mPV;
//ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index d32f116..7dd2b61 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -39,7 +39,6 @@ public:
struct Enviroment_t {
bool mIsRoot;
- bool mIsOrtho;
float mClearColor[4];
float mClearDepth;
uint32_t mClearStencil;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index d29eb9f..557f3ae 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -24,6 +24,11 @@
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()
{
@@ -38,220 +43,212 @@ ScriptC::~ScriptC()
}
}
-extern "C" void matrixLoadIdentity(void *con, rsc_Matrix *mat)
+extern "C" void matrixLoadIdentity(rsc_Matrix *mat)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->loadIdentity();
}
-extern "C" void matrixLoadFloat(void *con, rsc_Matrix *mat, const float *f)
+extern "C" void matrixLoadFloat(rsc_Matrix *mat, const float *f)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->load(f);
}
-extern "C" void matrixLoadMat(void *con, rsc_Matrix *mat, const rsc_Matrix *newmat)
+extern "C" void matrixLoadMat(rsc_Matrix *mat, const rsc_Matrix *newmat)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->load(reinterpret_cast<const Matrix *>(newmat));
}
-extern "C" void matrixLoadRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
+extern "C" void matrixLoadRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->loadRotate(rot, x, y, z);
}
-extern "C" void matrixLoadScale(void *con, rsc_Matrix *mat, float x, float y, float z)
+extern "C" void matrixLoadScale(rsc_Matrix *mat, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->loadScale(x, y, z);
}
-extern "C" void matrixLoadTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
+extern "C" void matrixLoadTranslate(rsc_Matrix *mat, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->loadTranslate(x, y, z);
}
-extern "C" void matrixLoadMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs)
+extern "C" void 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));
}
-extern "C" void matrixMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *rhs)
+extern "C" void matrixMultiply(rsc_Matrix *mat, const rsc_Matrix *rhs)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->multiply(reinterpret_cast<const Matrix *>(rhs));
}
-extern "C" void matrixRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
+extern "C" void matrixRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->rotate(rot, x, y, z);
}
-extern "C" void matrixScale(void *con, rsc_Matrix *mat, float x, float y, float z)
+extern "C" void matrixScale(rsc_Matrix *mat, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->scale(x, y, z);
}
-extern "C" void matrixTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
+extern "C" void matrixTranslate(rsc_Matrix *mat, float x, float y, float z)
{
Matrix *m = reinterpret_cast<Matrix *>(mat);
m->translate(x, y, z);
}
-extern "C" const void * loadVp(void *vp, uint32_t bank, uint32_t offset)
+extern "C" const void * loadVp(uint32_t bank, uint32_t offset)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- return &static_cast<const uint8_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+ GET_TLS();
+ return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset];
}
-extern "C" float loadF(void *vp, uint32_t bank, uint32_t offset)
+extern "C" float loadF(uint32_t bank, uint32_t offset)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- //LOGE("bank %i, offset %i", bank, offset);
- //LOGE("%p", env->mScript->mSlots[bank]->getPtr());
- return static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset];
+ GET_TLS();
+ return static_cast<const float *>(sc->mSlots[bank]->getPtr())[offset];
}
-extern "C" int32_t loadI32(void *vp, uint32_t bank, uint32_t offset)
+extern "C" int32_t loadI32(uint32_t bank, uint32_t offset)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- return static_cast<const int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+ GET_TLS();
+ return static_cast<const int32_t *>(sc->mSlots[bank]->getPtr())[offset];
}
-extern "C" uint32_t loadU32(void *vp, uint32_t bank, uint32_t offset)
+extern "C" uint32_t loadU32(uint32_t bank, uint32_t offset)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- return static_cast<const uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+ GET_TLS();
+ return static_cast<const uint32_t *>(sc->mSlots[bank]->getPtr())[offset];
}
-extern "C" void loadEnvVec4(void *vp, uint32_t bank, uint32_t offset, rsc_Vector4 *v)
+extern "C" void loadEnvVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- memcpy(v, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Vector4));
+ GET_TLS();
+ memcpy(v, &static_cast<const float *>(sc->mSlots[bank]->getPtr())[offset], sizeof(rsc_Vector4));
}
-extern "C" void loadEnvMatrix(void *vp, uint32_t bank, uint32_t offset, rsc_Matrix *m)
+extern "C" void loadEnvMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- memcpy(m, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Matrix));
+ GET_TLS();
+ memcpy(m, &static_cast<const float *>(sc->mSlots[bank]->getPtr())[offset], sizeof(rsc_Matrix));
}
-extern "C" void storeF(void *vp, uint32_t bank, uint32_t offset, float v)
+extern "C" void storeF(uint32_t bank, uint32_t offset, float v)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+ GET_TLS();
+ static_cast<float *>(sc->mSlots[bank]->getPtr())[offset] = v;
}
-extern "C" void storeI32(void *vp, uint32_t bank, uint32_t offset, int32_t v)
+extern "C" void storeI32(uint32_t bank, uint32_t offset, int32_t v)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- static_cast<int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+ GET_TLS();
+ static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
}
-extern "C" void storeU32(void *vp, uint32_t bank, uint32_t offset, uint32_t v)
+extern "C" void storeU32(uint32_t bank, uint32_t offset, uint32_t v)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- static_cast<uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+ GET_TLS();
+ static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
}
-extern "C" void storeEnvVec4(void *vp, uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
+extern "C" void storeEnvVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], v, sizeof(rsc_Vector4));
+ GET_TLS();
+ memcpy(&static_cast<float *>(sc->mSlots[bank]->getPtr())[offset], v, sizeof(rsc_Vector4));
}
-extern "C" void storeEnvMatrix(void *vp, uint32_t bank, uint32_t offset, const rsc_Matrix *m)
+extern "C" void storeEnvMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], m, sizeof(rsc_Matrix));
+ GET_TLS();
+ memcpy(&static_cast<float *>(sc->mSlots[bank]->getPtr())[offset], m, sizeof(rsc_Matrix));
}
-extern "C" void color(void *vp, float r, float g, float b, float a)
+extern "C" void color(float r, float g, float b, float a)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
glColor4f(r, g, b, a);
}
-extern "C" void renderTriangleMesh(void *vp, RsTriangleMesh mesh)
+extern "C" void renderTriangleMesh(RsTriangleMesh mesh)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_TriangleMeshRender(env->mContext, mesh);
+ GET_TLS();
+ rsi_TriangleMeshRender(rsc, mesh);
}
-extern "C" void renderTriangleMeshRange(void *vp, RsTriangleMesh mesh, uint32_t start, uint32_t count)
+extern "C" void renderTriangleMeshRange(RsTriangleMesh mesh, uint32_t start, uint32_t count)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_TriangleMeshRenderRange(env->mContext, mesh, start, count);
+ GET_TLS();
+ rsi_TriangleMeshRenderRange(rsc, mesh, start, count);
}
-extern "C" void materialDiffuse(void *vp, float r, float g, float b, float a)
+extern "C" void materialDiffuse(float r, float g, float b, float a)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
float v[] = {r, g, b, a};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
}
-extern "C" void materialSpecular(void *vp, float r, float g, float b, float a)
+extern "C" void materialSpecular(float r, float g, float b, float a)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
float v[] = {r, g, b, a};
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
}
-extern "C" void lightPosition(void *vp, float x, float y, float z, float w)
+extern "C" void lightPosition(float x, float y, float z, float w)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
float v[] = {x, y, z, w};
glLightfv(GL_LIGHT0, GL_POSITION, v);
}
-extern "C" void materialShininess(void *vp, float s)
+extern "C" void materialShininess(float s)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
}
-extern "C" void uploadToTexture(void *vp, RsAllocation va, uint32_t baseMipLevel)
+extern "C" void uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_AllocationUploadToTexture(env->mContext, va, baseMipLevel);
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
}
-extern "C" void enable(void *vp, uint32_t p)
+extern "C" void enable(uint32_t p)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
glEnable(p);
}
-extern "C" void disable(void *vp, uint32_t p)
+extern "C" void disable(uint32_t p)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
glDisable(p);
}
-extern "C" uint32_t scriptRand(void *vp, uint32_t max)
+extern "C" uint32_t scriptRand(uint32_t max)
{
return (uint32_t)(((float)rand()) * max / RAND_MAX);
}
// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
-extern "C" void drawTriangleArray(void *vp, RsAllocation alloc, uint32_t count)
+extern "C" void drawTriangleArray(RsAllocation alloc, uint32_t count)
{
+ GET_TLS();
+
const Allocation *a = (const Allocation *)alloc;
const uint32_t *ptr = (const uint32_t *)a->getPtr();
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- env->mContext->setupCheck();
+ rsc->setupCheck();
glBindBuffer(GL_ARRAY_BUFFER, 0);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
@@ -268,8 +265,9 @@ extern "C" void drawTriangleArray(void *vp, RsAllocation alloc, uint32_t count)
glDrawArrays(GL_TRIANGLES, 0, count * 3);
}
-extern "C" void drawRect(void *vp, int32_t x1, int32_t x2, int32_t y1, int32_t y2)
+extern "C" void drawRect(int32_t x1, int32_t x2, int32_t y1, int32_t y2)
{
+ GET_TLS();
x1 = (x1 << 16);
x2 = (x2 << 16);
y1 = (y1 << 16);
@@ -279,8 +277,7 @@ extern "C" void drawRect(void *vp, int32_t x1, int32_t x2, int32_t y1, int32_t y
static const int32_t tex[] = {0,0, 0,0x10000, 0x10000,0, 0x10000,0x10000};
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- env->mContext->setupCheck();
+ rsc->setupCheck();
glBindBuffer(GL_ARRAY_BUFFER, 0);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
@@ -297,40 +294,37 @@ extern "C" void drawRect(void *vp, int32_t x1, int32_t x2, int32_t y1, int32_t y
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
-extern "C" void pfBindTexture(void *vp, RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+extern "C" void pfBindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
{
- //LOGE("pfBindTexture %p", vpf);
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_ProgramFragmentBindTexture(env->mContext,
+ GET_TLS();
+ rsi_ProgramFragmentBindTexture(rsc,
static_cast<ProgramFragment *>(vpf),
slot,
static_cast<Allocation *>(va));
}
-extern "C" void pfBindSampler(void *vp, RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+extern "C" void pfBindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
{
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_ProgramFragmentBindSampler(env->mContext,
+ GET_TLS();
+ rsi_ProgramFragmentBindSampler(rsc,
static_cast<ProgramFragment *>(vpf),
slot,
static_cast<Sampler *>(vs));
}
-extern "C" void contextBindProgramFragmentStore(void *vp, RsProgramFragmentStore pfs)
+extern "C" void contextBindProgramFragmentStore(RsProgramFragmentStore pfs)
{
- //LOGE("contextBindProgramFragmentStore %p", pfs);
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_ContextBindProgramFragmentStore(env->mContext, pfs);
+ GET_TLS();
+ rsi_ContextBindProgramFragmentStore(rsc, pfs);
}
-extern "C" void contextBindProgramFragment(void *vp, RsProgramFragment pf)
+extern "C" void contextBindProgramFragment(RsProgramFragment pf)
{
- //LOGE("contextBindProgramFragment %p", pf);
- ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
- rsi_ContextBindProgramFragment(env->mContext, pf);
+ GET_TLS();
+ rsi_ContextBindProgramFragment(rsc, pf);
}
@@ -388,9 +382,10 @@ static rsc_FunctionTable scriptCPtrTable = {
};
-bool ScriptC::run(Context *rsc, uint32_t launchID)
+bool ScriptC::run(Context *rsc, uint32_t launchIndex)
{
- Env e = {rsc, this};
+ Context::ScriptTLSStruct * tls =
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
if (mEnviroment.mFragmentStore.get()) {
rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
@@ -398,8 +393,13 @@ bool ScriptC::run(Context *rsc, uint32_t launchID)
if (mEnviroment.mFragment.get()) {
rsc->setFragment(mEnviroment.mFragment.get());
}
+ if (mEnviroment.mVertex.get()) {
+ rsc->setVertex(mEnviroment.mVertex.get());
+ }
- return mProgram.mScript(&e, &scriptCPtrTable, launchID) != 0;
+ tls->mScript = this;
+ return mProgram.mScript(launchIndex, &scriptCPtrTable) != 0;
+ tls->mScript = NULL;
}
ScriptCState::ScriptCState()
@@ -428,7 +428,6 @@ void ScriptCState::clear()
mEnviroment.mClearDepth = 1;
mEnviroment.mClearStencil = 0;
mEnviroment.mIsRoot = false;
- mEnviroment.mIsOrtho = true;
mAccScript = NULL;
@@ -449,6 +448,9 @@ void ScriptCState::runCompiler(Context *rsc)
accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
rsAssert(mProgram.mScript);
+ mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+ mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+ mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
if (mProgram.mScript) {
const static int pragmaMax = 16;
@@ -466,6 +468,18 @@ void ScriptCState::runCompiler(Context *rsc)
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]);
}
@@ -474,8 +488,14 @@ void ScriptCState::runCompiler(Context *rsc)
}
if (!strcmp(str[ct], "stateFragment")) {
- ProgramFragment * pf =
- (ProgramFragment *)rsc->lookupName(str[ct+1]);
+ 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;
@@ -484,18 +504,19 @@ void ScriptCState::runCompiler(Context *rsc)
}
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;
}
-
- if (!strcmp(str[ct+1], "parent")) {
- //mEnviroment.mStateFragmentStore =
- //Script::Enviroment_t::FRAGMENT_STORE_PARENT;
- continue;
- }
LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
}
@@ -556,12 +577,6 @@ void rsi_ScriptCSetRoot(Context * rsc, bool isRoot)
ss->mEnviroment.mIsRoot = isRoot;
}
-void rsi_ScriptCSetOrtho(Context * rsc, bool isOrtho)
-{
- ScriptCState *ss = &rsc->mScriptC;
- ss->mEnviroment.mIsOrtho = isOrtho;
-}
-
void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
{
ScriptCState *ss = &rsc->mScriptC;
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 55a2cc6..c46901b1 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -52,12 +52,6 @@ public:
ACCscript* mAccScript;
virtual bool run(Context *, uint32_t launchID);
-
- struct Env {
- Context *mContext;
- ScriptC *mScript;
- };
-
};
class ScriptCState
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 23c808a..5641581 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -34,16 +34,17 @@ ThreadIO::~ThreadIO()
{
}
-bool ThreadIO::playCoreCommands(Context *con)
+bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
{
//LOGE("playCoreCommands 1");
uint32_t cmdID = 0;
uint32_t cmdSize = 0;
bool ret = false;
- while(!mToCore.isEmpty()) {
+ while(!mToCore.isEmpty() || waitForCommand) {
ret = true;
//LOGE("playCoreCommands 2");
const void * data = mToCore.get(&cmdID, &cmdSize);
+ waitForCommand = false;
//LOGE("playCoreCommands 3 %i %i", cmdID, cmdSize);
gPlaybackFuncs[cmdID](con, data);
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index ae2ffc0..973ee05 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -37,7 +37,7 @@ public:
// Plays back commands from the client.
// Returns true if any commands were processed.
- bool playCoreCommands(Context *con);
+ bool playCoreCommands(Context *con, bool waitForCommand);
LocklessCommandFifo mToCore;
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 3f19c85..784dfa5 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -218,9 +218,14 @@ void DisplayHardware::init(uint32_t dpy)
mRefreshRate = fbDev->fps;
char property[PROPERTY_VALUE_MAX];
- if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
- LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
- strcpy(property, "160");
+ /* Read density from build-specific ro.sf.lcd_density property
+ * except if it is overriden 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) {
+ LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
+ strcpy(property, "160");
+ }
}
mDensity = atoi(property) * (1.0f/160.0f);
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 8c9f875..6a7f056 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -86,46 +86,6 @@ BackupDataWriter::write_padding_for(int n)
}
status_t
-BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- ssize_t amt;
-
- amt = write_padding_for(m_pos);
- if (amt != 0) {
- return amt;
- }
-
- app_header_v1 header;
- ssize_t nameLen;
-
- nameLen = packageName.length();
-
- header.type = tolel(BACKUP_HEADER_APP_V1);
- header.packageLen = tolel(nameLen);
- header.cookie = cookie;
-
- amt = write(m_fd, &header, sizeof(app_header_v1));
- if (amt != sizeof(app_header_v1)) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- amt = write(m_fd, packageName.string(), nameLen+1);
- if (amt != nameLen+1) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- return NO_ERROR;
-}
-
-status_t
BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
{
if (m_status != NO_ERROR) {
@@ -188,40 +148,11 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size)
return NO_ERROR;
}
-status_t
-BackupDataWriter::WriteAppFooter(int cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- ssize_t amt;
-
- amt = write_padding_for(m_pos);
- if (amt != 0) {
- return amt;
- }
-
- app_footer_v1 footer;
- ssize_t nameLen;
-
- footer.type = tolel(BACKUP_FOOTER_APP_V1);
- footer.entityCount = tolel(m_entityCount);
- footer.cookie = cookie;
-
- amt = write(m_fd, &footer, sizeof(app_footer_v1));
- if (amt != sizeof(app_footer_v1)) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- return NO_ERROR;
-}
BackupDataReader::BackupDataReader(int fd)
:m_fd(fd),
+ m_done(false),
m_status(NO_ERROR),
m_pos(0),
m_entityCount(0)
@@ -260,32 +191,31 @@ BackupDataReader::Status()
} while(0)
status_t
-BackupDataReader::ReadNextHeader(int* type)
+BackupDataReader::ReadNextHeader(bool* done, int* type)
{
+ *done = m_done;
if (m_status != NO_ERROR) {
return m_status;
}
int amt;
- SKIP_PADDING();
+ // No error checking here, in case we're at the end of the stream. Just let read() fail.
+ skip_padding();
amt = read(m_fd, &m_header, sizeof(m_header));
+ *done = m_done = (amt == 0);
CHECK_SIZE(amt, sizeof(m_header));
+ m_pos += sizeof(m_header);
+ if (type) {
+ *type = m_header.type;
+ }
// validate and fix up the fields.
m_header.type = fromlel(m_header.type);
switch (m_header.type)
{
- case BACKUP_HEADER_APP_V1:
- m_header.app.packageLen = fromlel(m_header.app.packageLen);
- if (m_header.app.packageLen < 0) {
- LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
- (int)m_header.app.packageLen);
- m_status = EINVAL;
- }
- m_header.app.cookie = m_header.app.cookie;
- break;
case BACKUP_HEADER_ENTITY_V1:
+ {
m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
if (m_header.entity.keyLen <= 0) {
LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos,
@@ -294,52 +224,31 @@ BackupDataReader::ReadNextHeader(int* type)
}
m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
m_entityCount++;
- break;
- case BACKUP_FOOTER_APP_V1:
- m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
- if (m_header.footer.entityCount < 0) {
- LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
- (int)m_header.footer.entityCount);
- m_status = EINVAL;
+
+ // read the rest of the header (filename)
+ size_t size = m_header.entity.keyLen;
+ char* buf = m_key.lockBuffer(size);
+ if (buf == NULL) {
+ m_status = ENOMEM;
+ return m_status;
}
- m_header.footer.cookie = m_header.footer.cookie;
+ int amt = read(m_fd, buf, size+1);
+ CHECK_SIZE(amt, (int)size+1);
+ m_key.unlockBuffer(size);
+ m_pos += size+1;
+ SKIP_PADDING();
+ m_dataEndPos = m_pos + m_header.entity.dataSize;
+
break;
+ }
default:
LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
m_status = EINVAL;
}
- m_pos += sizeof(m_header);
- if (type) {
- *type = m_header.type;
- }
return m_status;
}
-status_t
-BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
- if (m_header.type != BACKUP_HEADER_APP_V1) {
- return EINVAL;
- }
- size_t size = m_header.app.packageLen;
- char* buf = packageName->lockBuffer(size);
- if (buf == NULL) {
- packageName->unlockBuffer();
- m_status = ENOMEM;
- return m_status;
- }
- int amt = read(m_fd, buf, size+1);
- CHECK_SIZE(amt, (int)size+1);
- packageName->unlockBuffer(size);
- m_pos += size+1;
- *cookie = m_header.app.cookie;
- return NO_ERROR;
-}
-
bool
BackupDataReader::HasEntities()
{
@@ -355,19 +264,8 @@ BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize)
if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
return EINVAL;
}
- size_t size = m_header.entity.keyLen;
- char* buf = key->lockBuffer(size);
- if (key == NULL) {
- key->unlockBuffer();
- m_status = ENOMEM;
- return m_status;
- }
- int amt = read(m_fd, buf, size+1);
- CHECK_SIZE(amt, (int)size+1);
- key->unlockBuffer(size);
- m_pos += size+1;
+ *key = m_key;
*dataSize = m_header.entity.dataSize;
- SKIP_PADDING();
return NO_ERROR;
}
@@ -381,42 +279,36 @@ BackupDataReader::SkipEntityData()
return EINVAL;
}
if (m_header.entity.dataSize > 0) {
- int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
+ int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
return pos == -1 ? (int)errno : (int)NO_ERROR;
} else {
return NO_ERROR;
}
}
-status_t
+ssize_t
BackupDataReader::ReadEntityData(void* data, size_t size)
{
if (m_status != NO_ERROR) {
- return m_status;
+ return -1;
}
- int amt = read(m_fd, data, size);
- CHECK_SIZE(amt, (int)size);
- m_pos += size;
- return NO_ERROR;
-}
-
-status_t
-BackupDataReader::ReadAppFooter(int* cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
+ int remaining = m_dataEndPos - m_pos;
+ //LOGD("ReadEntityData size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+ // size, m_pos, m_dataEndPos, remaining);
+ if (remaining <= 0) {
+ return 0;
}
- if (m_header.type != BACKUP_FOOTER_APP_V1) {
- return EINVAL;
+ if (size > remaining) {
+ size = remaining;
}
- if (m_header.footer.entityCount != m_entityCount) {
- LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
- m_header.footer.entityCount);
- m_status = EINVAL;
- return m_status;
+ //LOGD(" reading %d bytes", size);
+ int amt = read(m_fd, data, size);
+ if (amt < 0) {
+ m_status = errno;
+ return -1;
}
- *cookie = m_header.footer.cookie;
- return NO_ERROR;
+ m_pos += amt;
+ return amt;
}
status_t
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 4c3e37d..d65a457 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -47,27 +47,6 @@ namespace android {
#define LOGP(x...) LOGD(x)
#endif
-struct SnapshotHeader {
- int magic0;
- int fileCount;
- int magic1;
- int totalSize;
-};
-
-struct FileState {
- int modTime_sec;
- int modTime_nsec;
- int size;
- int crc32;
- int nameLen;
-};
-
-struct FileRec {
- char const* file; // this object does not own this string
- bool deleted;
- FileState s;
-};
-
const static int ROUND_UP[4] = { 0, 3, 2, 1 };
static inline int
@@ -310,7 +289,8 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
for (int i=0; i<fileCount; i++) {
String8 key(keys[i]);
FileRec r;
- char const* file = r.file = files[i];
+ char const* file = files[i];
+ r.file = file;
struct stat st;
err = stat(file, &st);
@@ -351,20 +331,20 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
}
else if (cmp > 0) {
// file added
- LOGP("file added: %s", g.file);
- write_update_file(dataStream, q, g.file);
+ LOGP("file added: %s", g.file.string());
+ write_update_file(dataStream, q, g.file.string());
m++;
}
else {
// both files exist, check them
const FileState& f = oldSnapshot.valueAt(n);
- int fd = open(g.file, O_RDONLY);
+ int fd = open(g.file.string(), O_RDONLY);
if (fd < 0) {
// We can't open the file. Don't report it as a delete either. Let the
// server keep the old version. Maybe they'll be able to deal with it
// on restore.
- LOGP("Unable to open file %s - skipping", g.file);
+ LOGP("Unable to open file %s - skipping", g.file.string());
} else {
g.s.crc32 = compute_crc32(fd);
@@ -375,7 +355,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|| f.size != g.s.size || f.crc32 != g.s.crc32) {
- write_update_file(dataStream, fd, p, g.file);
+ write_update_file(dataStream, fd, p, g.file.string());
}
close(fd);
@@ -395,7 +375,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
while (m<fileCount) {
const String8& q = newSnapshot.keyAt(m);
FileRec& g = newSnapshot.editValueAt(m);
- write_update_file(dataStream, q, g.file);
+ write_update_file(dataStream, q, g.file.string());
m++;
}
@@ -404,6 +384,86 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
return 0;
}
+#define RESTORE_BUF_SIZE (8*1024)
+
+RestoreHelperBase::RestoreHelperBase()
+{
+ m_buf = malloc(RESTORE_BUF_SIZE);
+}
+
+RestoreHelperBase::~RestoreHelperBase()
+{
+ free(m_buf);
+}
+
+status_t
+RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
+{
+ ssize_t err;
+ size_t dataSize;
+ String8 key;
+ int fd;
+ void* buf = m_buf;
+ ssize_t amt;
+ int mode;
+ int crc;
+ struct stat st;
+ FileRec r;
+
+ err = in->ReadEntityHeader(&key, &dataSize);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // TODO: World readable/writable for now.
+ mode = 0666;
+
+ // Write the file and compute the crc
+ crc = crc32(0L, Z_NULL, 0);
+ fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
+ if (fd == -1) {
+ LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
+ return errno;
+ }
+
+ while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
+ err = write(fd, buf, amt);
+ if (err != amt) {
+ close(fd);
+ LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
+ return errno;
+ }
+ crc = crc32(crc, (Bytef*)buf, amt);
+ }
+
+ close(fd);
+
+ // Record for the snapshot
+ err = stat(filename.string(), &st);
+ if (err != 0) {
+ LOGW("Error stating file that we just created %s", filename.string());
+ return errno;
+ }
+
+ r.file = filename;
+ r.deleted = false;
+ r.s.modTime_sec = st.st_mtime;
+ r.s.modTime_nsec = 0; // workaround sim breakage
+ //r.s.modTime_nsec = st.st_mtime_nsec;
+ r.s.size = st.st_size;
+ r.s.crc32 = crc;
+
+ m_files.add(key, r);
+
+ return NO_ERROR;
+}
+
+status_t
+RestoreHelperBase::WriteSnapshot(int fd)
+{
+ return write_snapshot_file(fd, m_files);;
+}
+
#if TEST_BACKUP_HELPERS
#define SCRATCH_DIR "/data/backup_helper_test/"
@@ -560,7 +620,6 @@ backup_helper_test_four()
FileState states[4];
FileRec r;
r.deleted = false;
- r.file = NULL;
states[0].modTime_sec = 0xfedcba98;
states[0].modTime_nsec = 0xdeadbeef;
@@ -689,41 +748,27 @@ backup_helper_test_four()
// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
const unsigned char DATA_GOLDEN_FILE[] = {
- 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
- 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
- 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
- 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
- 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
+ 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+ 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
- 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
- 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
- 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
- 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
- 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
- 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+ 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
- 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
- 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
- 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
- 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+ 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
- 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
- 0x99, 0x99, 0x77, 0x77
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
};
const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
@@ -733,12 +778,6 @@ test_write_header_and_entity(BackupDataWriter& writer, const char* str)
int err;
String8 text(str);
- err = writer.WriteAppHeader(text, 0xaabbccdd);
- if (err != 0) {
- fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
- return err;
- }
-
err = writer.WriteEntityHeader(text, text.length()+1);
if (err != 0) {
fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
@@ -779,8 +818,6 @@ backup_helper_test_data_writer()
err |= test_write_header_and_entity(writer, "padded_to_2__");
err |= test_write_header_and_entity(writer, "padded_to1");
- writer.WriteAppFooter(0x77779999);
-
close(fd);
err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
@@ -800,70 +837,59 @@ test_read_header_and_entity(BackupDataReader& reader, const char* str)
String8 string;
int cookie = 0x11111111;
size_t actualSize;
+ bool done;
+ int type;
// printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
- err = reader.ReadNextHeader();
- if (err != 0) {
- fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
- goto done;
+ err = reader.ReadNextHeader(&done, &type);
+ if (done) {
+ fprintf(stderr, "should not be done yet\n");
+ goto finished;
}
-
- err = reader.ReadAppHeader(&string, &cookie);
if (err != 0) {
- fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
- goto done;
- }
- if (string != str) {
- fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
- err = EINVAL;
- goto done;
+ fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
+ goto finished;
}
- if (cookie != (int)0xaabbccdd) {
- fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
+ if (type != BACKUP_HEADER_ENTITY_V1) {
err = EINVAL;
- goto done;
- }
-
- err = reader.ReadNextHeader();
- if (err != 0) {
- fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
- goto done;
+ fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
}
err = reader.ReadEntityHeader(&string, &actualSize);
if (err != 0) {
fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
- goto done;
+ goto finished;
}
if (string != str) {
fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
err = EINVAL;
- goto done;
+ goto finished;
}
if ((int)actualSize != bufSize) {
fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
actualSize);
err = EINVAL;
- goto done;
+ goto finished;
}
err = reader.ReadEntityData(buf, bufSize);
if (err != NO_ERROR) {
fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
- goto done;
+ goto finished;
}
if (0 != memcmp(buf, str, bufSize)) {
fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
- "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
+ "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+ buf[0], buf[1], buf[2], buf[3]);
err = EINVAL;
- goto done;
+ goto finished;
}
// The next read will confirm whether it got the right amount of data.
-done:
+finished:
if (err != NO_ERROR) {
fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
}
@@ -923,23 +949,6 @@ backup_helper_test_data_reader()
if (err == NO_ERROR) {
err = test_read_header_and_entity(reader, "padded_to1");
}
-
- if (err == NO_ERROR) {
- err = reader.ReadNextHeader();
- if (err != 0) {
- fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
- }
-
- if (err == NO_ERROR) {
- int cookie;
- err |= reader.ReadAppFooter(&cookie);
- if (cookie != 0x77779999) {
- fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
- 0x77779999, cookie);
- err = EINVAL;
- }
- }
- }
}
close(fd);
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 3d12dca..69d47f0 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3830,9 +3830,45 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
#define CHAR16_ARRAY_EQ(constant, var, len) \
((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
-void ResTable::print() const
+void print_complex(uint32_t complex, bool isFraction)
+{
+ const float MANTISSA_MULT =
+ 1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
+ const float RADIX_MULTS[] = {
+ 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
+ 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
+ };
+
+ float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
+ <<Res_value::COMPLEX_MANTISSA_SHIFT))
+ * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
+ & Res_value::COMPLEX_RADIX_MASK];
+ printf("%f", value);
+
+ if (isFraction) {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
+ case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
+ case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
+ case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
+ case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
+ case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ } else {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ }
+}
+
+void ResTable::print(bool inclValues) const
{
- printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ if (mError != 0) {
+ printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ }
#if 0
printf("mParams=%c%c-%c%c,\n",
mParams.language[0], mParams.language[1],
@@ -3947,6 +3983,8 @@ void ResTable::print() const
(void*)(entriesStart + thisOffset));
continue;
}
+
+ const Res_value* value = NULL;
if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
printf("<bag>");
} else {
@@ -3962,7 +4000,7 @@ void ResTable::print() const
continue;
}
- const Res_value* value = (const Res_value*)
+ value = (const Res_value*)
(((const uint8_t*)ent) + esize);
printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
(int)value->dataType, (int)dtohl(value->data),
@@ -3973,6 +4011,49 @@ void ResTable::print() const
printf(" (PUBLIC)");
}
printf("\n");
+
+ if (inclValues) {
+ if (value != NULL) {
+ printf(" ");
+ if (value->dataType == Res_value::TYPE_NULL) {
+ printf("(null)\n");
+ } else if (value->dataType == Res_value::TYPE_REFERENCE) {
+ printf("(reference) 0x%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_ATTRIBUTE) {
+ printf("(attribute) 0x%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_STRING) {
+ size_t len;
+ const char16_t* str = pkg->header->values.stringAt(
+ value->data, &len);
+ if (str == NULL) {
+ printf("(string) null\n");
+ } else {
+ printf("(string) \"%s\"\n",
+ String8(str, len).string());
+ }
+ } else if (value->dataType == Res_value::TYPE_FLOAT) {
+ printf("(float) %g\n", *(const float*)&value->data);
+ } else if (value->dataType == Res_value::TYPE_DIMENSION) {
+ printf("(dimension) ");
+ print_complex(value->data, false);
+ printf("\n");
+ } else if (value->dataType == Res_value::TYPE_FRACTION) {
+ printf("(fraction) ");
+ print_complex(value->data, true);
+ printf("\n");
+ } else if (value->dataType >= Res_value::TYPE_FIRST_COLOR_INT
+ || value->dataType <= Res_value::TYPE_LAST_COLOR_INT) {
+ printf("(color) #%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_INT_BOOLEAN) {
+ printf("(boolean) %s\n", value->data ? "true" : "false");
+ } else if (value->dataType >= Res_value::TYPE_FIRST_INT
+ || value->dataType <= Res_value::TYPE_LAST_INT) {
+ printf("(int) 0x%08x or %d\n", value->data, value->data);
+ } else {
+ printf("(unknown type)\n");
+ }
+ }
+ }
}
}
}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 9698553..e4ff0e3 100644..100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -208,12 +208,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private GpsNetworkThread mNetworkThread;
private Object mNetworkThreadLock = new Object();
- private String mSuplHost;
- private int mSuplPort;
- private String mC2KHost;
- private int mC2KPort;
- private boolean mSetSuplServer;
- private boolean mSetC2KServer;
private String mAGpsApn;
private int mAGpsDataConnectionState;
private final ConnectivityManager mConnMgr;
@@ -355,23 +349,27 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
- mSuplHost = mProperties.getProperty("SUPL_HOST");
+ String host = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
- if (mSuplHost != null && portString != null) {
+ if (host != null && portString != null) {
try {
- mSuplPort = Integer.parseInt(portString);
- mSetSuplServer = true;
+ 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;
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
}
}
- mC2KHost = mProperties.getProperty("C2K_HOST");
+ host = mProperties.getProperty("C2K_HOST");
portString = mProperties.getProperty("C2K_PORT");
- if (mC2KHost != null && portString != null) {
+ if (host != null && portString != null) {
try {
- mC2KPort = Integer.parseInt(portString);
- mSetC2KServer = true;
+ 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;
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
@@ -386,10 +384,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
* data network (e.g., the Internet), false otherwise.
*/
public boolean requiresNetwork() {
- // We want updateNetworkState() to get called when the network state changes
- // for XTRA and NTP time injection support.
- return (mNtpServer != null || native_supports_xtra() ||
- mSuplHost != null || mC2KHost != null);
+ return true;
}
public void updateNetworkState(int state) {
@@ -989,29 +984,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
- private boolean setAGpsServer(int type, String host, int port) {
- try {
- InetAddress inetAddress = InetAddress.getByName(host);
- if (inetAddress != null) {
- byte[] addrBytes = inetAddress.getAddress();
- long addr = 0;
- for (int i = 0; i < addrBytes.length; i++) {
- int temp = addrBytes[i];
- // signed -> unsigned
- if (temp < 0) temp = 256 + temp;
- addr = addr * 256 + temp;
- }
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
- native_set_agps_server(type, (int)addr, port);
- }
- } catch (UnknownHostException e) {
- Log.e(TAG, "unknown host for server " + host);
- return false;
- }
- return true;
- }
-
private class GpsEventThread extends Thread {
public GpsEventThread() {
@@ -1085,7 +1057,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
waitTime = getWaitTime();
} while (!mDone && ((!mXtraDownloadRequested &&
- !mTimeInjectRequested && !mSetSuplServer && !mSetC2KServer && waitTime > 0)
+ !mTimeInjectRequested && waitTime > 0)
|| !mNetworkAvailable));
if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
@@ -1113,18 +1085,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
- // Set the AGPS server addresses if we have not yet
- if (mSetSuplServer) {
- if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) {
- mSetSuplServer = false;
- }
- }
- if (mSetC2KServer) {
- if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) {
- mSetC2KServer = false;
- }
- }
-
if ((mXtraDownloadRequested ||
(mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
&& xtraDownloader != null) {
@@ -1225,5 +1185,5 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private native void native_agps_data_conn_open(String apn);
private native void native_agps_data_conn_closed();
private native void native_agps_data_conn_failed();
- private native void native_set_agps_server(int type, int addr, int port);
+ private native void native_set_agps_server(int type, String hostname, int port);
}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 16c66a6..2407d87 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -3,7 +3,7 @@
android:sharedUserId="android.uid.system">
<application android:allowClearUserData="false"
- android:label="Settings Storage"
+ android:label="@string/app_label"
android:icon="@drawable/ic_launcher_settings">
<provider android:name="SettingsProvider" android:authorities="settings"
diff --git a/packages/SettingsProvider/res/values/strings.xml b/packages/SettingsProvider/res/values/strings.xml
new file mode 100644
index 0000000..9ca575e
--- /dev/null
+++ b/packages/SettingsProvider/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources>
+ <!-- Name of the activity for Settings storage. -->
+ <string name="app_label">Settings Storage</string>
+</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6d90001..1a03900 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -158,14 +158,18 @@ public class SettingsProvider extends ContentProvider {
getContext().checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Cannot write secure settings table");
-
+ throw new SecurityException(
+ String.format("Permission denial: writing to secure settings requires %1$s",
+ android.Manifest.permission.WRITE_SECURE_SETTINGS));
+
// TODO: Move gservices into its own provider so we don't need this nonsense.
} else if ("gservices".equals(args.table) &&
getContext().checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_GSERVICES) !=
PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Cannot write gservices table");
+ throw new SecurityException(
+ String.format("Permission denial: writing to gservices settings requires %1$s",
+ android.Manifest.permission.WRITE_GSERVICES));
}
}
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index c254d93..d839c4e 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -10,7 +10,7 @@
<application android:process="system"
android:allowClearUserData="false"
android:icon="@drawable/app_icon"
- android:label="Sync Feeds">
+ android:label="@string/app_label">
<uses-library android:name="com.google.android.gtalkservice" />
<provider android:name="SubscribedFeedsProvider"
android:authorities="subscribedfeeds" android:syncable="false"
diff --git a/packages/SubscribedFeedsProvider/res/values/strings.xml b/packages/SubscribedFeedsProvider/res/values/strings.xml
new file mode 100644
index 0000000..072571d
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <!-- Title of the feed synchronization activity. -->
+ <string name="app_label">Sync Feeds</string>
+</resources>
+
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 582e6219..54d038a 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -272,7 +272,7 @@ android_tts_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
static void
android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language)
+ jstring language, jstring country, jstring variant)
{
if (jniData == 0) {
LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
@@ -281,12 +281,16 @@ android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
const char *langNativeString = env->GetStringUTFChars(language, 0);
+ const char *countryNativeString = env->GetStringUTFChars(country, 0);
+ const char *variantNativeString = env->GetStringUTFChars(variant, 0);
// TODO check return codes
if (pSynthData->mNativeSynthInterface) {
- pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
- strlen(langNativeString));
+ pSynthData->mNativeSynthInterface->setLanguage(langNativeString, countryNativeString,
+ variantNativeString);
}
env->ReleaseStringUTFChars(language, langNativeString);
+ env->ReleaseStringUTFChars(language, countryNativeString);
+ env->ReleaseStringUTFChars(language, variantNativeString);
}
@@ -494,6 +498,7 @@ android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
return env->NewStringUTF(buf);
}
+
JNIEXPORT int JNICALL
android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
{
@@ -529,7 +534,7 @@ static JNINativeMethod gMethods[] = {
(void*)android_tts_SynthProxy_synthesizeToFile
},
{ "native_setLanguage",
- "(ILjava/lang/String;)V",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
(void*)android_tts_SynthProxy_setLanguage
},
{ "native_setSpeechRate",
@@ -565,7 +570,6 @@ static JNINativeMethod gMethods[] = {
#define SP_JNIDATA_FIELD_NAME "mJniData"
#define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
-// TODO: verify this is the correct path
static const char* const kClassPathName = "android/tts/SynthProxy";
jint JNI_OnLoad(JavaVM* vm, void* reserved)
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index e065f40..364dc58 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -70,8 +70,8 @@ public class SynthProxy {
/**
* Sets the language
*/
- public void setLanguage(String language) {
- native_setLanguage(mJniData, language);
+ public void setLanguage(String language, String country, String variant) {
+ native_setLanguage(mJniData, language, country, variant);
}
/**
@@ -141,7 +141,8 @@ public class SynthProxy {
private native final void native_synthesizeToFile(int jniData, String text, String filename);
- private native final void native_setLanguage(int jniData, String language);
+ private native final void native_setLanguage(int jniData, String language, String country,
+ String variant);
private native final void native_setSpeechRate(int jniData, int speechRate);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 8a64113..e9c4ab7 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -15,10 +15,8 @@
*/
package android.tts;
-import android.speech.tts.ITts.Stub;
-import android.speech.tts.ITtsCallback;
-
import android.app.Service;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -31,6 +29,9 @@ import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.preference.PreferenceManager;
+import android.speech.tts.ITts.Stub;
+import android.speech.tts.ITtsCallback;
+import android.speech.tts.TextToSpeech;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
@@ -101,7 +102,7 @@ public class TtsService extends Service implements OnCompletionListener {
private MediaPlayer mPlayer;
private TtsService mSelf;
- private SharedPreferences prefs;
+ private ContentResolver mResolver;
private final ReentrantLock speechQueueLock = new ReentrantLock();
private final ReentrantLock synthesizerLock = new ReentrantLock();
@@ -113,9 +114,7 @@ public class TtsService extends Service implements OnCompletionListener {
super.onCreate();
Log.i("TTS", "TTS starting");
- // TODO: Make this work when the settings are done in the main Settings
- // app.
- prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mResolver = getContentResolver();
String soLibPath = "/system/lib/libttspico.so";
nativeSynth = new SynthProxy(soLibPath);
@@ -129,8 +128,7 @@ public class TtsService extends Service implements OnCompletionListener {
mSpeechQueue = new ArrayList<SpeechItem>();
mPlayer = null;
- setLanguage(prefs.getString("lang_pref", "en-rUS"));
- setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140")));
+ setDefaultSettings();
}
@Override
@@ -145,25 +143,50 @@ public class TtsService extends Service implements OnCompletionListener {
mCallbacks.kill();
}
+
+ private void setDefaultSettings() {
+
+ // TODO handle default language
+ setLanguage("eng", "USA", "");
+
+ // speech rate
+ setSpeechRate(getDefaultRate());
+
+ // TODO handle default pitch
+ }
+
+
+ private boolean isDefaultEnforced() {
+ return (android.provider.Settings.Secure.getInt(mResolver,
+ android.provider.Settings.Secure.TTS_USE_DEFAULTS,
+ TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS)
+ == 1 );
+ }
+
+
+ private int getDefaultRate() {
+ return android.provider.Settings.Secure.getInt(mResolver,
+ android.provider.Settings.Secure.TTS_DEFAULT_RATE,
+ TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE);
+ }
+
+
private void setSpeechRate(int rate) {
- if (prefs.getBoolean("override_pref", false)) {
- // This is set to the default here so that the preview in the prefs
- // activity will show the change without a restart, even if apps are
- // not allowed to change the defaults.
- rate = Integer.parseInt(prefs.getString("rate_pref", "140"));
+ if (isDefaultEnforced()) {
+ nativeSynth.setSpeechRate(getDefaultRate());
+ } else {
+ nativeSynth.setSpeechRate(rate);
}
- nativeSynth.setSpeechRate(rate);
}
- private void setLanguage(String lang) {
- if (prefs.getBoolean("override_pref", false)) {
- // This is set to the default here so that the preview in the prefs
- // activity will show the change without a restart, even if apps are
- // not
- // allowed to change the defaults.
- lang = prefs.getString("lang_pref", "en-rUS");
+ private void setLanguage(String lang, String country, String variant) {
+ Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
+ if (isDefaultEnforced()) {
+ nativeSynth.setLanguage(lang, country, variant);
+ } else {
+ // TODO handle default language
+ nativeSynth.setLanguage("eng", "USA", "");
}
- nativeSynth.setLanguage(lang);
}
/**
@@ -683,20 +706,14 @@ public class TtsService extends Service implements OnCompletionListener {
}
/**
- * Sets the speech rate for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
+ * Sets the speech rate for the TTS, which affects the synthesized voice.
*
- * @param language
- * Language values are based on the Android conventions for
- * localization as described in the Android platform
- * documentation on internationalization. This implies that
- * language data is specified in the format xx-rYY, where xx
- * is a two letter ISO 639-1 language code in lowercase and
- * rYY is a two letter ISO 3166-1-alpha-2 language code in
- * uppercase preceded by a lowercase "r".
+ * @param lang the three letter ISO language code.
+ * @param country the three letter ISO country code.
+ * @param variant the variant code associated with the country and language pair.
*/
- public void setLanguage(String language) {
- mSelf.setLanguage(language);
+ public void setLanguage(String lang, String country, String variant) {
+ mSelf.setLanguage(lang, country, variant);
}
/**
diff --git a/packages/VpnServices/AndroidManifest.xml b/packages/VpnServices/AndroidManifest.xml
index e48b2da..6092e30 100644
--- a/packages/VpnServices/AndroidManifest.xml
+++ b/packages/VpnServices/AndroidManifest.xml
@@ -3,7 +3,7 @@
package="com.android.server.vpn"
android:sharedUserId="android.uid.system"
>
- <application android:label="VPN Services">
+ <application android:label="@string/app_label">
<service android:name=".VpnServiceBinder" android:process=":remote">
<intent-filter>
diff --git a/packages/VpnServices/res/values/strings.xml b/packages/VpnServices/res/values/strings.xml
index 892850a..e42c1e8 100755
--- a/packages/VpnServices/res/values/strings.xml
+++ b/packages/VpnServices/res/values/strings.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <!-- Title for the VPN Services activity. -->
+ <string name="app_label">VPN Services</string>
+
<string name="vpn_notification_title">%s VPN %s</string>
<string name="vpn_notification_connected">connected</string>
<string name="vpn_notification_disconnected">disconnected</string>
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index ce56921..8358c5c 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -50,16 +50,17 @@ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
}
private String getCaCertPath() {
- return Keystore.getInstance().getCertificate(
+ return Keystore.getInstance().getCaCertificate(
getProfile().getCaCertificate());
}
private String getUserCertPath() {
- return Keystore.getInstance().getCertificate(
+ return Keystore.getInstance().getUserCertificate(
getProfile().getUserCertificate());
}
private String getUserkeyPath() {
- return Keystore.getInstance().getUserkey(getProfile().getUserkey());
+ return Keystore.getInstance().getUserPrivateKey(
+ getProfile().getUserCertificate());
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2f964ba..75e0e64 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -21,14 +21,17 @@ import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
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.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -48,9 +51,11 @@ import android.backup.BackupManager;
import android.backup.RestoreSet;
import com.android.internal.backup.LocalTransport;
-import com.android.internal.backup.GoogleTransport;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.PackageManagerBackupAgent;
+import com.android.server.PackageManagerBackupAgent.Metadata;
+
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
@@ -68,7 +73,8 @@ import java.util.List;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
private static final boolean DEBUG = true;
-
+
+ // Default time to wait after data changes before we back up the data
private static final long COLLECTION_INTERVAL = 1000;
//private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
@@ -90,7 +96,7 @@ class BackupManagerService extends IBackupManager.Stub {
private class BackupRequest {
public ApplicationInfo appInfo;
public boolean fullBackup;
-
+
BackupRequest(ApplicationInfo app, boolean isFull) {
appInfo = app;
fullBackup = isFull;
@@ -103,9 +109,11 @@ class BackupManagerService extends IBackupManager.Stub {
// Backups that we haven't started yet.
private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
= new HashMap<ApplicationInfo,BackupRequest>();
- // Backups that we have started. These are separate to prevent starvation
- // if an app keeps re-enqueuing itself.
- private ArrayList<BackupRequest> mBackupQueue;
+ // Do we need to back up the package manager metadata on the next pass?
+ private boolean mDoPackageManager;
+ private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+
+ // locking around the pending-backup management
private final Object mQueueLock = new Object();
// The thread performing the sequence of queued backups binds to each app's agent
@@ -120,14 +128,17 @@ class BackupManagerService extends IBackupManager.Stub {
private final Object mClearDataLock = new Object();
private volatile boolean mClearingData;
+ // Current active transport & restore session
private int mTransportId;
+ private IBackupTransport mLocalTransport, mGoogleTransport;
+ private RestoreSession mActiveRestoreSession;
private File mStateDir;
private File mDataDir;
private File mJournalDir;
private File mJournal;
private RandomAccessFile mJournalStream;
-
+
public BackupManagerService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -143,14 +154,27 @@ class BackupManagerService extends IBackupManager.Stub {
mJournalDir.mkdirs();
makeJournalLocked(); // okay because no other threads are running yet
- //!!! TODO: default to cloud transport, not local
- mTransportId = BackupManager.TRANSPORT_LOCAL;
-
- // Build our mapping of uid to backup client services
+ // 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.
synchronized (mBackupParticipants) {
addPackageParticipantsLocked(null);
}
+ // Set up our transport options and initialize the default transport
+ // TODO: Have transports register themselves somehow?
+ // TODO: Don't create transports that we don't need to?
+ //mTransportId = BackupManager.TRANSPORT_LOCAL;
+ mTransportId = BackupManager.TRANSPORT_GOOGLE;
+ mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
+ mGoogleTransport = null;
+
+ // Attach to the Google backup transport.
+ Intent intent = new Intent().setComponent(new ComponentName(
+ "com.google.android.backup",
+ "com.google.android.backup.BackupTransportService"));
+ context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
+
// Now that we know about valid backup participants, parse any
// leftover journal files and schedule a new backup pass
parseLeftoverJournals();
@@ -244,6 +268,19 @@ class BackupManagerService extends IBackupManager.Stub {
}
};
+ // ----- Track connection to GoogleBackupTransport service -----
+ ServiceConnection mGoogleConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.v(TAG, "Connected to Google transport");
+ mGoogleTransport = IBackupTransport.Stub.asInterface(service);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.v(TAG, "Disconnected from Google transport");
+ mGoogleTransport = null;
+ }
+ };
+
// ----- Run the actual backup process asynchronously -----
private class BackupHandler extends Handler {
@@ -251,7 +288,15 @@ class BackupManagerService extends IBackupManager.Stub {
switch (msg.what) {
case MSG_RUN_BACKUP:
+ {
+ IBackupTransport transport = getTransport(mTransportId);
+ if (transport == null) {
+ Log.v(TAG, "Backup requested but no transport available");
+ break;
+ }
+
// snapshot the pending-backup set and work on that
+ ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
File oldJournal = mJournal;
synchronized (mQueueLock) {
if (mPendingBackups.size() == 0) {
@@ -259,13 +304,11 @@ class BackupManagerService extends IBackupManager.Stub {
break;
}
- if (mBackupQueue == null) {
- mBackupQueue = new ArrayList<BackupRequest>();
- for (BackupRequest b: mPendingBackups.values()) {
- mBackupQueue.add(b);
- }
- mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
+ for (BackupRequest b: mPendingBackups.values()) {
+ queue.add(b);
}
+ Log.v(TAG, "clearing pending backups");
+ mPendingBackups.clear();
// Start a new backup-queue journal file too
if (mJournalStream != null) {
@@ -283,8 +326,10 @@ class BackupManagerService extends IBackupManager.Stub {
// deleted. If we crash prior to that, the old journal is parsed
// at next boot and the journaled requests fulfilled.
}
- (new PerformBackupThread(mTransportId, mBackupQueue, oldJournal)).run();
+
+ (new PerformBackupThread(transport, queue, oldJournal)).start();
break;
+ }
case MSG_RUN_FULL_BACKUP:
break;
@@ -293,7 +338,7 @@ class BackupManagerService extends IBackupManager.Stub {
{
int token = msg.arg1;
IBackupTransport transport = (IBackupTransport)msg.obj;
- (new PerformRestoreThread(transport, token)).run();
+ (new PerformRestoreThread(transport, token)).start();
break;
}
}
@@ -327,12 +372,13 @@ class BackupManagerService extends IBackupManager.Stub {
mBackupParticipants.put(uid, set);
}
set.add(app);
+ backUpPackageManagerData();
}
}
}
- // Remove the given package's backup services from our known active set. If
- // 'packageName' is null, *all* backup services will be removed.
+ // Remove the given package's entry from our known active set. If
+ // 'packageName' is null, *all* participating apps will be removed.
void removePackageParticipantsLocked(String packageName) {
if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
List<ApplicationInfo> allApps = null;
@@ -370,6 +416,7 @@ class BackupManagerService extends IBackupManager.Stub {
for (ApplicationInfo entry: set) {
if (entry.packageName.equals(app.packageName)) {
set.remove(entry);
+ backUpPackageManagerData();
break;
}
}
@@ -382,6 +429,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Returns the set of all applications that define an android:backupAgent attribute
private List<ApplicationInfo> allAgentApps() {
+ // !!! TODO: cache this and regenerate only when necessary
List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
int N = allApps.size();
if (N > 0) {
@@ -395,7 +443,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
return allApps;
}
-
+
// Reset the given package's known backup participants. Unlike add/remove, the update
// action cannot be passed a null package name.
void updatePackageParticipantsLocked(String packageName) {
@@ -411,25 +459,35 @@ class BackupManagerService extends IBackupManager.Stub {
addPackageParticipantsLockedInner(packageName, allApps);
}
- // Instantiate the given transport
- private IBackupTransport createTransport(int transportID) {
- IBackupTransport transport = null;
+ private void backUpPackageManagerData() {
+ // No need to schedule a backup just for the metadata; just piggyback on
+ // the next actual data backup.
+ synchronized(this) {
+ mDoPackageManager = true;
+ }
+ }
+
+ // The queue lock should be held when scheduling a backup pass
+ private void scheduleBackupPassLocked(long timeFromNowMillis) {
+ mBackupHandler.removeMessages(MSG_RUN_BACKUP);
+ mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
+ }
+
+ // Return the given transport
+ private IBackupTransport getTransport(int transportID) {
switch (transportID) {
case BackupManager.TRANSPORT_LOCAL:
- if (DEBUG) Log.v(TAG, "Initializing local transport");
- transport = new LocalTransport(mContext);
- break;
+ Log.v(TAG, "Supplying local transport");
+ return mLocalTransport;
case BackupManager.TRANSPORT_GOOGLE:
- if (DEBUG) Log.v(TAG, "Initializing Google transport");
- //!!! TODO: stand up the google backup transport for real here
- transport = new GoogleTransport();
- break;
+ Log.v(TAG, "Supplying Google transport");
+ return mGoogleTransport;
default:
- Log.e(TAG, "creating unknown transport " + transportID);
+ Log.e(TAG, "Asked for unknown transport " + transportID);
+ return null;
}
- return transport;
}
// fire off a backup agent, blocking until it attaches or times out
@@ -495,7 +553,7 @@ class BackupManagerService extends IBackupManager.Stub {
throws android.os.RemoteException {
synchronized(mClearDataLock) {
mClearingData = false;
- notifyAll();
+ mClearDataLock.notifyAll();
}
}
}
@@ -504,13 +562,13 @@ class BackupManagerService extends IBackupManager.Stub {
class PerformBackupThread extends Thread {
private static final String TAG = "PerformBackupThread";
- int mTransport;
+ IBackupTransport mTransport;
ArrayList<BackupRequest> mQueue;
File mJournal;
- public PerformBackupThread(int transportId, ArrayList<BackupRequest> queue,
+ public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
File journal) {
- mTransport = transportId;
+ mTransport = transport;
mQueue = queue;
mJournal = journal;
}
@@ -519,27 +577,43 @@ class BackupManagerService extends IBackupManager.Stub {
public void run() {
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
- // stand up the current transport
- IBackupTransport transport = createTransport(mTransport);
- if (transport == null) {
- return;
- }
-
// start up the transport
try {
- transport.startSession();
+ mTransport.startSession();
} catch (Exception e) {
Log.e(TAG, "Error session transport");
e.printStackTrace();
return;
}
- // The transport is up and running; now run all the backups in our queue
- doQueuedBackups(transport);
+ // The transport is up and running. First, back up the package manager
+ // metadata if necessary
+ boolean doPackageManager;
+ synchronized (BackupManagerService.this) {
+ doPackageManager = mDoPackageManager;
+ mDoPackageManager = false;
+ }
+ if (doPackageManager) {
+ // 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.
+ if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
+
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentApps());
+ 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 {
- transport.endSession();
+ mTransport.endSession();
} catch (Exception e) {
Log.e(TAG, "Error ending transport");
e.printStackTrace();
@@ -585,8 +659,15 @@ class BackupManagerService extends IBackupManager.Stub {
// 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 = mPackageManager.getPackageInfo(packageName,
+ PackageInfo packInfo;
+ if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ // The metadata 'package' is synthetic
+ packInfo = new PackageInfo();
+ packInfo.packageName = packageName;
+ } else {
+ packInfo = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
+ }
// !!! TODO: get the state file dir from the transport
File savedStateName = new File(mStateDir, packageName);
@@ -674,6 +755,40 @@ class BackupManagerService extends IBackupManager.Stub {
return null;
}
+ private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
+ // Allow unsigned apps, but not signed on one device and unsigned on the other
+ // !!! TODO: is this the right policy?
+ if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ + " device=" + deviceSigs);
+ if ((storedSigs == null || storedSigs.length == 0)
+ && (deviceSigs == null || deviceSigs.length == 0)) {
+ return true;
+ }
+ if (storedSigs == null || deviceSigs == null) {
+ return false;
+ }
+
+ // !!! TODO: this demands that every stored signature match one
+ // that is present on device, and does not demand the converse.
+ // Is this this right policy?
+ int nStored = storedSigs.length;
+ int nDevice = deviceSigs.length;
+
+ for (int i=0; i < nStored; i++) {
+ boolean match = false;
+ for (int j=0; j < nDevice; j++) {
+ if (storedSigs[i].equals(deviceSigs[j])) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
+ }
+ }
+ return true;
+ }
+
class PerformRestoreThread extends Thread {
private IBackupTransport mTransport;
private int mToken;
@@ -686,6 +801,7 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
+ if (DEBUG) Log.v(TAG, "Beginning restore process");
/**
* Restore sequence:
*
@@ -718,6 +834,13 @@ class BackupManagerService extends IBackupManager.Stub {
// !!! TODO: pick out the set for this token
mImage = images[0];
+ // Pull the Package Manager metadata from the restore set first
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentApps());
+ PackageInfo pmApp = new PackageInfo();
+ pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneRestore(pmApp, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
// build the set of apps we will attempt to restore
PackageInfo[] packages = mTransport.getAppSet(mImage.token);
HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>();
@@ -725,7 +848,21 @@ class BackupManagerService extends IBackupManager.Stub {
// get the real PackageManager idea of the package
PackageInfo app = isRestorable(pkg);
if (app != null) {
- appsToRestore.add(app);
+ // Validate against the backed-up signature block, too
+ Metadata info = pmAgent.getRestoredMetadata(app.packageName);
+ if (app.versionCode >= info.versionCode) {
+ if (DEBUG) Log.v(TAG, "Restore version " + info.versionCode
+ + " compatible with app version " + app.versionCode);
+ if (signaturesMatch(info.signatures, app.signatures)) {
+ appsToRestore.add(app);
+ } else {
+ Log.w(TAG, "Sig mismatch restoring " + app.packageName);
+ }
+ } else {
+ Log.i(TAG, "Restore set for " + app.packageName
+ + " is too new [" + info.versionCode
+ + "] for installed app version " + app.versionCode);
+ }
}
}
@@ -849,8 +986,26 @@ class BackupManagerService extends IBackupManager.Stub {
// a backup pass for each of them.
Log.d(TAG, "dataChanged packageName=" + packageName);
-
- HashSet<ApplicationInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
+
+ // If the caller does not hold the BACKUP permission, it can only request a
+ // backup of its own data.
+ HashSet<ApplicationInfo> targets;
+ if ((mContext.checkPermission("android.permission.BACKUP", Binder.getCallingPid(),
+ Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ targets = mBackupParticipants.get(Binder.getCallingUid());
+ } else {
+ // a caller with full permission can ask to back up any participating app
+ // !!! TODO: allow backup of ANY app?
+ if (DEBUG) Log.v(TAG, "Privileged caller, allowing backup of other apps");
+ targets = new HashSet<ApplicationInfo>();
+ int N = mBackupParticipants.size();
+ for (int i = 0; i < N; i++) {
+ HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+ if (s != null) {
+ targets.addAll(s);
+ }
+ }
+ }
if (targets != null) {
synchronized (mQueueLock) {
// Note that this client has made data changes that need to be backed up
@@ -878,8 +1033,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Schedule a backup pass in a few minutes. As backup-eligible data
// keeps changing, continue to defer the backup pass until things
// settle down, to avoid extra overhead.
- mBackupHandler.removeMessages(MSG_RUN_BACKUP);
- mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
+ scheduleBackupPassLocked(COLLECTION_INTERVAL);
}
} else {
Log.w(TAG, "dataChanged but no participant pkg " + packageName);
@@ -905,14 +1059,14 @@ class BackupManagerService extends IBackupManager.Stub {
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
synchronized (mQueueLock) {
- mBackupHandler.removeMessages(MSG_RUN_BACKUP);
- mBackupHandler.sendEmptyMessage(MSG_RUN_BACKUP);
+ scheduleBackupPassLocked(0);
}
}
// Report the currently active transport
public int getCurrentTransport() {
mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
+ Log.v(TAG, "getCurrentTransport() returning " + mTransportId);
return mTransportId;
}
@@ -922,6 +1076,7 @@ class BackupManagerService extends IBackupManager.Stub {
int prevTransport = mTransportId;
mTransportId = transportId;
+ Log.v(TAG, "selectBackupTransport() set " + mTransportId + " returning " + prevTransport);
return prevTransport;
}
@@ -962,17 +1117,27 @@ class BackupManagerService extends IBackupManager.Stub {
// Hand off a restore session
public IRestoreSession beginRestoreSession(int transportID) {
mContext.enforceCallingPermission("android.permission.BACKUP", "beginRestoreSession");
- return null;
+
+ synchronized(this) {
+ if (mActiveRestoreSession != null) {
+ Log.d(TAG, "Restore session requested but one already active");
+ return null;
+ }
+ mActiveRestoreSession = new RestoreSession(transportID);
+ }
+ return mActiveRestoreSession;
}
// ----- Restore session -----
class RestoreSession extends IRestoreSession.Stub {
+ private static final String TAG = "RestoreSession";
+
private IBackupTransport mRestoreTransport = null;
RestoreSet[] mRestoreSets = null;
RestoreSession(int transportID) {
- mRestoreTransport = createTransport(transportID);
+ mRestoreTransport = getTransport(transportID);
}
// --- Binder interface ---
@@ -980,12 +1145,18 @@ class BackupManagerService extends IBackupManager.Stub {
mContext.enforceCallingPermission("android.permission.BACKUP",
"getAvailableRestoreSets");
+ try {
synchronized(this) {
if (mRestoreSets == null) {
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
}
return mRestoreSets;
}
+ } catch (RuntimeException e) {
+ Log.d(TAG, "getAvailableRestoreSets exception");
+ e.printStackTrace();
+ throw e;
+ }
}
public int performRestore(int token) throws android.os.RemoteException {
@@ -1001,6 +1172,8 @@ class BackupManagerService extends IBackupManager.Stub {
return 0;
}
}
+ } else {
+ if (DEBUG) Log.v(TAG, "No current restore set, not doing restore");
}
return -1;
}
@@ -1011,6 +1184,13 @@ class BackupManagerService extends IBackupManager.Stub {
mRestoreTransport.endSession();
mRestoreTransport = null;
+ synchronized(BackupManagerService.this) {
+ if (BackupManagerService.this.mActiveRestoreSession == this) {
+ BackupManagerService.this.mActiveRestoreSession = null;
+ } else {
+ Log.e(TAG, "ending non-current restore session");
+ }
+ }
}
}
@@ -1030,11 +1210,10 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(app.toString());
}
}
- pw.println("Pending:");
- Iterator<BackupRequest> br = mPendingBackups.values().iterator();
- while (br.hasNext()) {
- pw.print(" ");
- pw.println(br);
+ pw.println("Pending: " + mPendingBackups.size());
+ for (BackupRequest req : mPendingBackups.values()) {
+ pw.print(" ");
+ pw.println(req);
}
}
}
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
new file mode 100644
index 0000000..e51a0af
--- /dev/null
+++ b/services/java/com/android/server/EntropyService.java
@@ -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.
+ */
+
+package com.android.server;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * A service designed to load and periodically save &quot;randomness&quot;
+ * for the Linux kernel.
+ *
+ * <p>When a Linux system starts up, the entropy pool associated with
+ * {@code /dev/random} may be in a fairly predictable state. Applications which
+ * depend strongly on randomness may find {@code /dev/random} or
+ * {@code /dev/urandom} returning predictable data. In order to counteract
+ * this effect, it's helpful to carry the entropy pool information across
+ * shutdowns and startups.
+ *
+ * <p>This class was modeled after the script in
+ * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man
+ * 4 random</a>.
+ *
+ * <p>TODO: Investigate attempting to write entropy data at shutdown time
+ * instead of periodically.
+ */
+public class EntropyService extends Binder {
+ private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
+ private static final String TAG = "EntropyService";
+ private static final int ENTROPY_WHAT = 1;
+ private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000; // 3 hrs
+ private static final String RANDOM_DEV = "/dev/urandom";
+
+ /**
+ * Handler that periodically updates the entropy on disk.
+ */
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what != ENTROPY_WHAT) {
+ Log.e(TAG, "Will not process invalid message");
+ return;
+ }
+ writeEntropy();
+ scheduleEntropyWriter();
+ }
+ };
+
+ public EntropyService() {
+ loadInitialEntropy();
+ writeEntropy();
+ scheduleEntropyWriter();
+ }
+
+ private void scheduleEntropyWriter() {
+ mHandler.removeMessages(ENTROPY_WHAT);
+ mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
+ }
+
+ private void loadInitialEntropy() {
+ try {
+ RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+ } catch (IOException e) {
+ Log.w(TAG, "unable to load initial entropy (first boot?)", e);
+ }
+ }
+
+ private void writeEntropy() {
+ try {
+ RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+ } catch (IOException e) {
+ Log.e(TAG, "unable to write entropy", e);
+ }
+ }
+
+ private static String getSystemDir() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ systemDir.mkdirs();
+ return systemDir.toString();
+ }
+}
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
new file mode 100644
index 0000000..cc84430
--- /dev/null
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.BackupAgent;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataOutput;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * We back up the signatures of each package so that during a system restore,
+ * we can verify that the app whose data we think we have matches the app
+ * actually resident on the device.
+ *
+ * Since the Package Manager isn't a proper "application" we just provide a
+ * direct IBackupAgent implementation and hand-construct it at need.
+ */
+public class PackageManagerBackupAgent extends BackupAgent {
+ private static final String TAG = "PMBA";
+ private static final boolean DEBUG = true;
+
+ private List<ApplicationInfo> mAllApps;
+ private PackageManager mPackageManager;
+ private HashMap<String, Metadata> mRestoredSignatures;
+
+ public class Metadata {
+ public int versionCode;
+ public Signature[] signatures;
+
+ Metadata(int version, Signature[] sigs) {
+ versionCode = version;
+ signatures = sigs;
+ }
+ }
+
+ // We're constructed with the set of applications that are participating
+ // in backup. This set changes as apps are installed & removed.
+ PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
+ mPackageManager = packageMgr;
+ mAllApps = apps;
+ mRestoredSignatures = null;
+ }
+
+ public Metadata getRestoredMetadata(String packageName) {
+ if (mRestoredSignatures == null) {
+ return null;
+ }
+
+ return mRestoredSignatures.get(packageName);
+ }
+
+ // The backed up data is the signature block for each app, keyed by
+ // the package name.
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) {
+ HashSet<String> existing = parseStateFile(oldState);
+
+ // For each app we have on device, see if we've backed it up yet. If not,
+ // write its signature block to the output, keyed on the package name.
+ if (DEBUG) Log.v(TAG, "onBackup()");
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
+ DataOutputStream outWriter = new DataOutputStream(bufStream);
+ for (ApplicationInfo app : mAllApps) {
+ String packName = app.packageName;
+ if (!existing.contains(packName)) {
+ // We haven't stored this app's signatures yet, so we do that now
+ try {
+ PackageInfo info = mPackageManager.getPackageInfo(packName,
+ PackageManager.GET_SIGNATURES);
+ /*
+ * Metadata for each package:
+ *
+ * int version -- [4] the package's versionCode
+ * byte[] signatures -- [len] flattened Signature[] of the package
+ */
+
+ // marshall the version code in a canonical form
+ bufStream.reset();
+ outWriter.writeInt(info.versionCode);
+ byte[] versionBuf = bufStream.toByteArray();
+
+ byte[] sigs = flattenSignatureArray(info.signatures);
+
+ // !!! TODO: take out this debugging
+ if (DEBUG) {
+ Log.v(TAG, "+ metadata for " + packName + " version=" + info.versionCode);
+ }
+ // Now we can write the backup entity for this package
+ data.writeEntityHeader(packName, versionBuf.length + sigs.length);
+ data.writeEntityData(versionBuf, versionBuf.length);
+ data.writeEntityData(sigs, sigs.length);
+ } catch (NameNotFoundException e) {
+ // Weird; we just found it, and now are told it doesn't exist.
+ // Treat it as having been removed from the device.
+ existing.add(packName);
+ } catch (IOException e) {
+ // Real error writing data
+ Log.e(TAG, "Unable to write package backup data file!");
+ return;
+ }
+ } else {
+ // We've already backed up this app. Remove it from the set so
+ // we can tell at the end what has disappeared from the device.
+ // !!! TODO: take out the debugging message
+ if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName);
+ if (!existing.remove(packName)) {
+ Log.d(TAG, "*** failed to remove " + packName + " from package set!");
+ }
+ }
+ }
+
+ // At this point, the only entries in 'existing' are apps that were
+ // mentioned in the saved state file, but appear to no longer be present
+ // on the device. Write a deletion entity for them.
+ for (String app : existing) {
+ // !!! TODO: take out this msg
+ if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
+ try {
+ data.writeEntityHeader(app, -1);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write package deletions!");
+ return;
+ }
+ }
+
+ // Finally, write the new state blob -- just the list of all apps we handled
+ writeStateFile(mAllApps, newState);
+ }
+
+ // "Restore" here is a misnomer. What we're really doing is reading back the
+ // set of app signatures associated with each backed-up app in this restore
+ // image. We'll use those later to determine what we can legitimately restore.
+ public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
+ throws IOException {
+ List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
+ HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
+
+ while (data.readNextHeader()) {
+ int dataSize = data.getDataSize();
+ byte[] buf = new byte[dataSize];
+ data.readEntityData(buf, 0, dataSize);
+
+ ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
+ DataInputStream in = new DataInputStream(bufStream);
+ int versionCode = in.readInt();
+
+ Signature[] sigs = unflattenSignatureArray(in);
+ String pkg = data.getKey();
+// !!! TODO: take out this debugging
+ if (DEBUG) {
+ Log.i(TAG, "+ restored metadata for " + pkg
+ + " versionCode=" + versionCode + " sigs=" + sigs);
+ }
+
+ ApplicationInfo app = new ApplicationInfo();
+ app.packageName = pkg;
+ restoredApps.add(app);
+ sigMap.put(pkg, new Metadata(versionCode, sigs));
+ }
+
+ mRestoredSignatures = sigMap;
+ }
+
+
+ // Util: convert an array of Signatures into a flattened byte buffer. The
+ // flattened format contains enough info to reconstruct the signature array.
+ private byte[] flattenSignatureArray(Signature[] allSigs) {
+ ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(outBuf);
+
+ // build the set of subsidiary buffers
+ try {
+ // first the # of signatures in the array
+ out.writeInt(allSigs.length);
+
+ // then the signatures themselves, length + flattened buffer
+ for (Signature sig : allSigs) {
+ byte[] flat = sig.toByteArray();
+ out.writeInt(flat.length);
+ out.write(flat);
+ }
+ } catch (IOException e) {
+ // very strange; we're writing to memory here. abort.
+ return null;
+ }
+
+ return outBuf.toByteArray();
+ }
+
+ private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
+ Signature[] sigs = null;
+
+ try {
+ int num = in.readInt();
+ sigs = new Signature[num];
+ for (int i = 0; i < num; i++) {
+ int len = in.readInt();
+ byte[] flatSig = new byte[len];
+ in.read(flatSig);
+ sigs[i] = new Signature(flatSig);
+ }
+ } catch (EOFException e) {
+ // clean termination
+ if (sigs == null) {
+ Log.w(TAG, "Empty signature block found");
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to unflatten sigs");
+ return null;
+ }
+
+ return sigs;
+ }
+
+ // Util: parse out an existing state file into a usable structure
+ private HashSet<String> parseStateFile(ParcelFileDescriptor stateFile) {
+ HashSet<String> set = new HashSet<String>();
+ // The state file is just the list of app names we have stored signatures for
+ FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
+ DataInputStream in = new DataInputStream(instream);
+
+ int bufSize = 256;
+ byte[] buf = new byte[bufSize];
+ try {
+ int nameSize = in.readInt();
+ if (bufSize < nameSize) {
+ bufSize = nameSize + 32;
+ buf = new byte[bufSize];
+ }
+ in.read(buf, 0, nameSize);
+ String pkg = new String(buf, 0, nameSize);
+ set.add(pkg);
+ } catch (EOFException eof) {
+ // safe; we're done
+ } catch (IOException e) {
+ // whoops, bad state file. abort.
+ Log.e(TAG, "Unable to read Package Manager state file");
+ return null;
+ }
+ return set;
+ }
+
+ // Util: write a set of names into a new state file
+ private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
+ FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+
+ for (ApplicationInfo app : apps) {
+ try {
+ byte[] pkgNameBuf = app.packageName.getBytes();
+ out.writeInt(pkgNameBuf.length);
+ out.write(pkgNameBuf);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write package manager state file!");
+ return;
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index d98738a..4b583e4 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -19,7 +19,6 @@ package com.android.server;
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
-import com.android.server.PackageManagerService.PreferredActivity;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -27,13 +26,12 @@ import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
@@ -150,6 +148,7 @@ class PackageManagerService extends IPackageManager.Stub {
final Context mContext;
final boolean mFactoryTest;
+ final boolean mNoDexOpt;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
@@ -301,6 +300,7 @@ class PackageManagerService extends IPackageManager.Stub {
mContext = context;
mFactoryTest = factoryTest;
+ mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings();
mSettings.addSharedUserLP("android.uid.system",
@@ -370,6 +370,10 @@ class PackageManagerService extends IPackageManager.Stub {
startTime);
int scanMode = SCAN_MONITOR;
+ if (mNoDexOpt) {
+ Log.w(TAG, "Running ENG build: no pre-dexopt!");
+ scanMode |= SCAN_NO_DEX;
+ }
final HashSet<String> libFiles = new HashSet<String>();
@@ -930,7 +934,7 @@ class PackageManagerService extends IPackageManager.Stub {
});
}
- public void freeStorage(final long freeStorageSize, final PendingIntent opFinishedIntent) {
+ public void freeStorage(final long freeStorageSize, final IntentSender pi) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
// Queue up an async operation since clearing cache may take a little while.
@@ -944,11 +948,13 @@ class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Couldn't clear application caches");
}
}
- if(opFinishedIntent != null) {
+ if(pi != null) {
try {
// Callback via pending intent
- opFinishedIntent.send((retCode >= 0) ? 1 : 0);
- } catch (CanceledException e1) {
+ int code = (retCode >= 0) ? 1 : 0;
+ pi.sendIntent(null, code, null,
+ null, null);
+ } catch (SendIntentException e1) {
Log.i(TAG, "Failed to send pending intent");
}
}
@@ -963,10 +969,11 @@ class PackageManagerService extends IPackageManager.Stub {
if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledLP(a.info, flags)) {
ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
- if (ainfo != null && (flags & PackageManager.GET_EXPANDABLE) != 0) {
+ if (ainfo != null) {
ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
- PackageManager.GET_EXPANDABLE | PackageManager.GET_SUPPORTS_DENSITIES);
- if (appInfo != null && !appInfo.expandable) {
+ PackageManager.GET_SUPPORTS_DENSITIES);
+ if (appInfo != null &&
+ (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
// Check if the screen size is same as what the application expect.
CompatibilityInfo info = new CompatibilityInfo(appInfo);
DisplayMetrics metrics = new DisplayMetrics();
@@ -979,11 +986,13 @@ class PackageManagerService extends IPackageManager.Stub {
// Don't allow an app that cannot expand to handle rotation.
ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
} else {
- appInfo.expandable = true;
+ appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
}
if (DEBUG_SETTINGS) {
Log.d(TAG, "component=" + component +
- ", expandable:" + appInfo.expandable);
+ ", expandable:" +
+ ((appInfo.flags &
+ ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
}
}
}
@@ -1239,28 +1248,6 @@ class PackageManagerService extends IPackageManager.Stub {
return chooseBestActivity(intent, resolvedType, flags, query);
}
- public ResolveInfo resolveIntentForPackage(Intent intent, String resolvedType,
- int flags, String packageName) {
- ComponentName comp = intent.getComponent();
- if (comp != null) {
- // if this is an explicit intent, it must have the same the packageName
- if (packageName.equals(comp.getPackageName())) {
- return resolveIntent(intent, resolvedType, flags);
- }
- return null;
- } else {
- List<ResolveInfo> query = null;
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null) {
- query = (List<ResolveInfo>) mActivities.
- queryIntentForPackage(intent, resolvedType, flags, pkg.activities);
- }
- }
- return chooseBestActivity(intent, resolvedType, flags, query);
- }
- }
-
private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query) {
if (query != null) {
@@ -1379,8 +1366,17 @@ class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
- return (List<ResolveInfo>)mActivities.
- queryIntent(intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mActivities.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.activities);
+ }
+ return null;
}
}
@@ -1547,9 +1543,30 @@ class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags) {
+ ComponentName comp = intent.getComponent();
+ if (comp != null) {
+ List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ ActivityInfo ai = getReceiverInfo(comp, flags);
+ if (ai != null) {
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ list.add(ri);
+ }
+ return list;
+ }
+
synchronized (mPackages) {
- return (List<ResolveInfo>)mReceivers.
- queryIntent(intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mReceivers.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.receivers);
+ }
+ return null;
}
}
@@ -1582,7 +1599,17 @@ class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
- return (List<ResolveInfo>)mServices.queryIntent(intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mServices.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.services);
+ }
+ return null;
}
}
@@ -1898,7 +1925,56 @@ class PackageManagerService extends IPackageManager.Stub {
}
return true;
}
+
+ public boolean performDexOpt(String packageName) {
+ if (!mNoDexOpt) {
+ return false;
+ }
+ PackageParser.Package p;
+ synchronized (mPackages) {
+ p = mPackages.get(packageName);
+ if (p == null || p.mDidDexOpt) {
+ return false;
+ }
+ }
+ synchronized (mInstallLock) {
+ return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
+ }
+ }
+
+ static final int DEX_OPT_SKIPPED = 0;
+ static final int DEX_OPT_PERFORMED = 1;
+ static final int DEX_OPT_FAILED = -1;
+
+ private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
+ boolean performed = false;
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ String path = pkg.mScanPath;
+ int ret = 0;
+ try {
+ if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
+ ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
+ !pkg.mForwardLocked);
+ pkg.mDidDexOpt = true;
+ performed = true;
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Apk not found for dexopt: " + path);
+ ret = -1;
+ } catch (IOException e) {
+ Log.w(TAG, "Exception reading apk: " + path, e);
+ ret = -1;
+ }
+ if (ret < 0) {
+ //error from installer
+ return DEX_OPT_FAILED;
+ }
+ }
+
+ return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+ }
+
private PackageParser.Package scanPackageLI(
File scanFile, File destCodeFile, File destResourceFile,
PackageParser.Package pkg, int parseFlags, int scanMode) {
@@ -2194,23 +2270,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if ((scanMode&SCAN_NO_DEX) == 0
- && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- int ret = 0;
- try {
- if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
- ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
- (scanMode&SCAN_FORWARD_LOCKED) == 0);
- }
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Apk not found for dexopt: " + path);
- ret = -1;
- } catch (IOException e) {
- Log.w(TAG, "Exception reading apk: " + path, e);
- ret = -1;
- }
- if (ret < 0) {
- //error from installer
+ pkg.mForwardLocked = (scanMode&SCAN_FORWARD_LOCKED) != 0;
+ pkg.mScanPath = path;
+
+ if ((scanMode&SCAN_NO_DEX) == 0) {
+ if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
return null;
}
@@ -3079,6 +3143,27 @@ class PackageManagerService extends IPackageManager.Stub {
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
}
+ public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
+ ArrayList<PackageParser.Service> packageServices) {
+ if (packageServices == null) {
+ return null;
+ }
+ mFlags = flags;
+ final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
+ int N = packageServices.size();
+ ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
+ new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
+
+ ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
+ for (int i = 0; i < N; ++i) {
+ intentFilters = packageServices.get(i).intents;
+ if (intentFilters != null && intentFilters.size() > 0) {
+ listCut.add(intentFilters);
+ }
+ }
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+ }
+
public final void addService(PackageParser.Service s) {
mServices.put(s.component, s);
if (SHOW_INFO || Config.LOGV) Log.v(
diff --git a/services/java/com/android/server/RandomBlock.java b/services/java/com/android/server/RandomBlock.java
new file mode 100644
index 0000000..4ac1c6e
--- /dev/null
+++ b/services/java/com/android/server/RandomBlock.java
@@ -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.
+ */
+
+package com.android.server;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+
+/**
+ * A 4k block of random {@code byte}s.
+ */
+class RandomBlock {
+
+ private static final String TAG = "RandomBlock";
+ private static final int BLOCK_SIZE = 4096;
+ private byte[] block = new byte[BLOCK_SIZE];
+
+ private RandomBlock() { }
+
+ static RandomBlock fromFile(String filename) throws IOException {
+ Log.v(TAG, "reading from file " + filename);
+ InputStream stream = null;
+ try {
+ stream = new FileInputStream(filename);
+ return fromStream(stream);
+ } finally {
+ close(stream);
+ }
+ }
+
+ private static RandomBlock fromStream(InputStream in) throws IOException {
+ RandomBlock retval = new RandomBlock();
+ int total = 0;
+ while(total < BLOCK_SIZE) {
+ int result = in.read(retval.block, total, BLOCK_SIZE - total);
+ if (result == -1) {
+ throw new EOFException();
+ }
+ total += result;
+ }
+ return retval;
+ }
+
+ void toFile(String filename) throws IOException {
+ Log.v(TAG, "writing to file " + filename);
+ RandomAccessFile out = null;
+ try {
+ out = new RandomAccessFile(filename, "rws");
+ toDataOut(out);
+ truncateIfPossible(out);
+ } finally {
+ close(out);
+ }
+ }
+
+ private static void truncateIfPossible(RandomAccessFile f) {
+ try {
+ f.setLength(BLOCK_SIZE);
+ } catch (IOException e) {
+ // ignore this exception. Sometimes, the file we're trying to
+ // write is a character device, such as /dev/urandom, and
+ // these character devices do not support setting the length.
+ }
+ }
+
+ private void toDataOut(DataOutput out) throws IOException {
+ out.write(block);
+ }
+
+ private static void close(Closeable c) {
+ try {
+ if (c == null) {
+ return;
+ }
+ c.close();
+ } catch (IOException e) {
+ Log.w(TAG, "IOException thrown while closing Closeable", e);
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 36fc5bb..c26ba5c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -93,6 +93,9 @@ class ServerThread extends Thread {
// Critical services...
try {
+ Log.i(TAG, "Starting Entropy Service.");
+ ServiceManager.addService("entropy", new EntropyService());
+
Log.i(TAG, "Starting Power Manager.");
power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 07d6b6f..ac176ca 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -34,8 +34,6 @@ import android.app.Dialog;
import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
-import android.app.IIntentReceiver;
-import android.app.IIntentSender;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
import android.app.Instrumentation;
@@ -48,6 +46,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -61,7 +61,6 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -88,7 +87,6 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
-import android.util.LogPrinter;
import android.util.PrintWriterPrinter;
import android.util.SparseArray;
import android.view.Gravity;
@@ -127,6 +125,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
+ static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_SERVICE = localLOGV || false;
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PROCESSES = localLOGV || false;
@@ -182,7 +181,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
- | PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
+ | PackageManager.GET_SUPPORTS_DENSITIES;
private static final String SYSTEM_SECURE = "ro.secure";
@@ -316,6 +315,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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;
@@ -810,6 +815,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
int[] mProcDeaths = new int[20];
+ /**
+ * This is set if we had to do a delayed dexopt of an app before launching
+ * it, to increasing the ANR timeouts in that case.
+ */
+ boolean mDidDexOpt;
+
String mDebugApp = null;
boolean mWaitForDebugger = false;
boolean mDebugTransient = false;
@@ -1008,6 +1019,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
+ mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
+ return;
+ }
broadcastTimeout();
} break;
case PAUSE_TIMEOUT_MSG: {
@@ -1018,9 +1035,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activityPaused(token, null, true);
} break;
case IDLE_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
+ return;
+ }
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
+ IBinder token = (IBinder)msg.obj;
Log.w(TAG, "Activity idle timeout for " + token);
activityIdleInternal(token, true);
} break;
@@ -1036,6 +1060,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activityIdle(token);
} break;
case SERVICE_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
+ return;
+ }
serviceTimeout((ProcessRecord)msg.obj);
} break;
case UPDATE_TIME_ZONE: {
@@ -1072,6 +1103,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} break;
case LAUNCH_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
+ mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
+ return;
+ }
synchronized (ActivityManagerService.this) {
if (mLaunchingActivity.isHeld()) {
Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
@@ -1092,6 +1129,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
case PROC_START_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
+ return;
+ }
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
processStartTimedOutLocked(app);
@@ -1608,6 +1652,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return proc;
}
+ private void ensurePackageDexOpt(String packageName) {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ try {
+ if (pm.performDexOpt(packageName)) {
+ mDidDexOpt = true;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
private boolean isNextTransitionForward() {
int transit = mWindowManager.getPendingAppTransition();
return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
@@ -1667,6 +1721,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.isHomeActivity) {
mHomeProcess = app;
}
+ ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
@@ -4820,6 +4875,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
}
+ ensurePackageDexOpt(app.info.packageName);
+ if (app.instrumentationInfo != null) {
+ ensurePackageDexOpt(app.instrumentationInfo.packageName);
+ }
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
@@ -4908,6 +4967,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Check whether the next backup agent is in this process...
if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
+ ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
} catch (Exception e) {
@@ -6919,6 +6979,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
app.pubProviders.put(cpi.name, cpr);
app.addPackage(cpi.applicationInfo.packageName);
+ ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
@@ -7895,26 +7956,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
- ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
- 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,
@@ -8219,12 +8316,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
report.time = crashData.getTime();
report.crashInfo.stackTrace = throwData.toString();
- // extract the source of the exception, useful for report
- // clustering
+ // Extract the source of the exception, useful for report
+ // clustering. Also extract the "deepest" non-null exception
+ // message.
+ String exceptionMessage = throwData.getMessage();
while (throwData.getCause() != null) {
throwData = throwData.getCause();
+ String msg = throwData.getMessage();
+ if (msg != null && msg.length() > 0) {
+ exceptionMessage = msg;
+ }
}
StackTraceElementData trace = throwData.getStackTrace()[0];
+ report.crashInfo.exceptionMessage = exceptionMessage;
report.crashInfo.exceptionClassName = throwData.getType();
report.crashInfo.throwFileName = trace.getFileName();
report.crashInfo.throwClassName = trace.getClassName();
@@ -9535,6 +9639,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
+ ensurePackageDexOpt(r.serviceInfo.packageName);
app.thread.scheduleCreateService(r, r.serviceInfo);
created = true;
} finally {
@@ -10596,7 +10701,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST_LIGHT) Log.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
if ((resultTo != null) && !ordered) {
@@ -11088,9 +11193,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean started = false;
try {
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
"Delivering to component " + r.curComponent
+ ": " + r);
+ ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
r.resultCode, r.resultData, r.resultExtras, r.ordered);
started = true;
@@ -11158,12 +11264,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
+ if (filter.receiverList.app != null) {
+ // Bump hosting application to no longer be in background
+ // scheduling class. Note that we can't do that if there
+ // isn't an app... but we can only be in that case for
+ // things that directly call the IActivityManager API, which
+ // are already core system stuff so don't matter for this.
+ r.curApp = filter.receiverList.app;
+ filter.receiverList.app.curReceiver = r;
+ updateOomAdjLocked();
+ }
}
try {
- if (DEBUG_BROADCAST) {
+ if (DEBUG_BROADCAST_LIGHT) {
int seq = r.intent.getIntExtra("seq", -1);
- Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
- + " app=" + filter.receiverList.app);
+ Log.i(TAG, "Delivering to " + filter.receiverList.app
+ + " (seq=" + seq + "): " + r);
}
performReceive(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode,
@@ -11177,6 +11293,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
+ if (filter.receiverList.app != null) {
+ filter.receiverList.app.curReceiver = null;
+ }
}
}
}
@@ -11200,6 +11319,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
+ + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Log.v(TAG,
@@ -11207,6 +11328,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ target + ": " + r);
deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
}
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
+ + r);
}
// Now take care of the next serialized one...
@@ -11232,10 +11355,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ boolean looped = false;
+
do {
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ updateOomAdjLocked();
+ }
return;
}
r = mOrderedBroadcasts.get(0);
@@ -11292,9 +11423,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
+ + r);
+
// ... and on to the next...
mOrderedBroadcasts.remove(0);
r = null;
+ looped = true;
continue;
}
} while (r == null);
@@ -11308,6 +11443,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (recIdx == 0) {
r.dispatchTime = r.startTime;
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
+ + r);
if (DEBUG_BROADCAST) Log.v(TAG,
"Submitting BROADCAST_TIMEOUT_MSG for "
+ (r.startTime + BROADCAST_TIMEOUT));
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 4057ae8..da55049 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import android.app.IIntentReceiver;
+import android.content.IIntentReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 944ea02..b3fc313 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -463,6 +463,12 @@ class HistoryRecord extends IApplicationToken.Stub {
return false;
}
+ if (service.mDidDexOpt) {
+ // Give more time since we were dexopting.
+ service.mDidDexOpt = false;
+ return false;
+ }
+
if (r.app.instrumentationClass == null) {
service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
} else {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 4381392..fa2a100 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -17,8 +17,8 @@
package com.android.server.am;
import android.app.IActivityManager;
-import android.app.IIntentSender;
-import android.app.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.IIntentReceiver;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Binder;
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java
index 0facefc..32c24c6 100644
--- a/services/java/com/android/server/am/ReceiverList.java
+++ b/services/java/com/android/server/am/ReceiverList.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import android.app.IIntentReceiver;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 866334b..2d58659 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -56,9 +56,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1004;
+ private static final int VERSION = 1005;
- private static final int CHECKIN_VERSION = 3;
+ private static final int CHECKIN_VERSION = 4;
private static final String FILE_PREFIX = "usage-";
@@ -82,7 +82,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
// this lock held.
final Object mFileLock;
// Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
- private String mResumedPkg;
+ private String mLastResumedPkg;
+ private String mLastResumedComp;
+ private boolean mIsResumed;
private File mFile;
private String mFileLeaf;
//private File mBackupFile;
@@ -92,11 +94,16 @@ public final class UsageStatsService extends IUsageStats.Stub {
private int mLastWriteDay;
static class TimeStats {
+ int count;
int[] times = new int[NUM_LAUNCH_TIME_BINS];
TimeStats() {
}
+ void incCount() {
+ count++;
+ }
+
void add(int val) {
final int[] bins = LAUNCH_TIME_BINS;
for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
@@ -109,6 +116,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
TimeStats(Parcel in) {
+ count = in.readInt();
final int[] localTimes = times;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
localTimes[i] = in.readInt();
@@ -116,6 +124,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
void writeToParcel(Parcel out) {
+ out.writeInt(count);
final int[] localTimes = times;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
out.writeInt(localTimes[i]);
@@ -152,8 +161,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void updateResume() {
- mLaunchCount ++;
+ void updateResume(boolean launched) {
+ if (launched) {
+ mLaunchCount ++;
+ }
mResumedTime = SystemClock.elapsedRealtime();
}
@@ -162,6 +173,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
mUsageTime += (mPausedTime - mResumedTime);
}
+ void addLaunchCount(String comp) {
+ TimeStats times = mLaunchTimes.get(comp);
+ if (times == null) {
+ times = new TimeStats();
+ mLaunchTimes.put(comp, times);
+ }
+ times.incCount();
+ }
+
void addLaunchTime(String comp, int millis) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -436,43 +456,70 @@ public final class UsageStatsService extends IUsageStats.Stub {
public void noteResumeComponent(ComponentName componentName) {
enforceCallingPermission();
String pkgName;
- if ((componentName == null) ||
- ((pkgName = componentName.getPackageName()) == null)) {
- return;
- }
- if ((mResumedPkg != null) && (mResumedPkg.equalsIgnoreCase(pkgName))) {
- // Moving across activities in same package. just return
- return;
- }
- if (localLOGV) Log.i(TAG, "started component:"+pkgName);
synchronized (mStatsLock) {
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+
+ final boolean samePackage = pkgName.equals(mLastResumedPkg);
+ if (mIsResumed) {
+ if (samePackage) {
+ Log.w(TAG, "Something wrong here, didn't expect "
+ + pkgName + " to be resumed");
+ return;
+ }
+
+ if (mLastResumedPkg != null) {
+ // We last resumed some other package... just pause it now
+ // to recover.
+ Log.w(TAG, "Unexpected resume of " + pkgName
+ + " while already resumed in " + mLastResumedPkg);
+ PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+ if (pus != null) {
+ pus.updatePause();
+ }
+ }
+ }
+
+ final boolean sameComp = samePackage
+ && componentName.getClassName().equals(mLastResumedComp);
+
+ mIsResumed = true;
+ mLastResumedPkg = pkgName;
+ mLastResumedComp = componentName.getClassName();
+
+ if (localLOGV) Log.i(TAG, "started component:" + pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
pus = new PkgUsageStatsExtended();
mStats.put(pkgName, pus);
}
- pus.updateResume();
+ pus.updateResume(!samePackage);
+ if (!sameComp) {
+ pus.addLaunchCount(mLastResumedComp);
+ }
}
- mResumedPkg = pkgName;
}
public void notePauseComponent(ComponentName componentName) {
enforceCallingPermission();
- String pkgName;
- if ((componentName == null) ||
- ((pkgName = componentName.getPackageName()) == null)) {
- return;
- }
- if ((mResumedPkg == null) || (!pkgName.equalsIgnoreCase(mResumedPkg))) {
- Log.w(TAG, "Something wrong here, Didn't expect "+pkgName+" to be paused");
- return;
- }
- if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
-
- // Persist current data to file if needed.
- writeStatsToFile(false);
synchronized (mStatsLock) {
+ String pkgName;
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+ if (!mIsResumed) {
+ Log.w(TAG, "Something wrong here, didn't expect "
+ + pkgName + " to be paused");
+ return;
+ }
+ mIsResumed = false;
+
+ if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
+
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
// Weird some error here
@@ -481,6 +528,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
pus.updatePause();
}
+
+ // Persist current data to file if needed.
+ writeStatsToFile(false);
}
public void noteLaunchTime(ComponentName componentName, int millis) {
@@ -631,9 +681,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (isCompactOutput) {
sb.append("P:");
sb.append(pkgName);
- sb.append(",");
+ sb.append(',');
sb.append(pus.mLaunchCount);
- sb.append(",");
+ sb.append(',');
sb.append(pus.mUsageTime);
sb.append('\n');
final int NC = pus.mLaunchTimes.size();
@@ -642,6 +692,8 @@ public final class UsageStatsService extends IUsageStats.Stub {
sb.append("A:");
sb.append(ent.getKey());
TimeStats times = ent.getValue();
+ sb.append(',');
+ sb.append(times.count);
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
sb.append(",");
sb.append(times.times[i]);
@@ -665,25 +717,26 @@ public final class UsageStatsService extends IUsageStats.Stub {
sb.append(" ");
sb.append(ent.getKey());
TimeStats times = ent.getValue();
+ sb.append(": ");
+ sb.append(times.count);
+ sb.append(" starts");
int lastBin = 0;
- boolean first = true;
for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
if (times.times[i] != 0) {
- sb.append(first ? ": " : ", ");
+ sb.append(", ");
sb.append(lastBin);
sb.append('-');
sb.append(LAUNCH_TIME_BINS[i]);
- sb.append('=');
+ sb.append("ms=");
sb.append(times.times[i]);
- first = false;
}
lastBin = LAUNCH_TIME_BINS[i];
}
if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
- sb.append(first ? ": " : ", ");
+ sb.append(", ");
sb.append(">=");
sb.append(lastBin);
- sb.append('=');
+ sb.append("ms=");
sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
}
sb.append('\n');
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index b59fe54..059dc7b 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -707,6 +707,23 @@ public class StatusBarPolicy {
b.setView(v);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setPositiveButton(android.R.string.ok, null);
+
+ final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+ b.setNegativeButton(com.android.internal.R.string.battery_low_why,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mContext.startActivity(intent);
+ if (mLowBatteryDialog != null) {
+ mLowBatteryDialog.dismiss();
+ }
+ }
+ });
+ }
AlertDialog d = b.create();
d.setOnDismissListener(mLowBatteryListener);
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 9395d66..890f930 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -22,7 +22,6 @@ import android.os.ServiceManager;
import android.text.TextUtils;
import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.SmsRawData;
@@ -31,14 +30,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import static android.telephony.SmsMessage.ENCODING_7BIT;
-import static android.telephony.SmsMessage.ENCODING_8BIT;
-import static android.telephony.SmsMessage.ENCODING_16BIT;
-import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
-import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
-import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
-import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
-import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
+/*
+ * TODO(code review): Curious question... Why are a lot of these
+ * methods not declared as static, since they do not seem to require
+ * any local object state? Assumedly this cannot be changed without
+ * interfering with the API...
+ */
/**
* Manages SMS operations such as sending data, text, and pdu SMS messages.
@@ -88,7 +85,7 @@ public final class SmsManager {
}
/**
- * Divide a text message into several messages, none bigger than
+ * Divide a message text into several fragments, none bigger than
* the maximum SMS message size.
*
* @param text the original message. Must not be null.
@@ -96,40 +93,7 @@ public final class SmsManager {
* comprise the original message
*/
public ArrayList<String> divideMessage(String text) {
- int size = text.length();
- int[] params = SmsMessage.calculateLength(text, false);
- /* SmsMessage.calculateLength returns an int[4] with:
- * int[0] being the number of SMS's required,
- * int[1] the number of code units used,
- * int[2] is the number of code units remaining until the next message.
- * int[3] is the encoding type that should be used for the message.
- */
- int messageCount = params[0];
- int encodingType = params[3];
- ArrayList<String> result = new ArrayList<String>(messageCount);
-
- int start = 0;
- int limit;
-
- if (messageCount > 1) {
- limit = (encodingType == ENCODING_7BIT)?
- MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER;
- } else {
- limit = (encodingType == ENCODING_7BIT)?
- MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES;
- }
-
- try {
- while (start < size) {
- int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType);
- result.add(text.substring(start, end));
- start = end;
- }
- }
- catch (EncodeException e) {
- // ignore it.
- }
- return result;
+ return SmsMessage.fragmentText(text);
}
/**
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index b60da5a..775b034 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -17,12 +17,17 @@
package android.telephony;
import android.os.Parcel;
+import android.util.Log;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
+
+import java.lang.Math;
+import java.util.ArrayList;
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
@@ -44,19 +49,41 @@ public class SmsMessage {
UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
}
- /** Unknown encoding scheme (see TS 23.038) */
+ /**
+ * TODO(cleanup): given that we now have more than one possible
+ * 7bit encoding, this result starts to look rather vague and
+ * maybe confusing... If this is just an indication of code unit
+ * size, maybe that is no problem. Otherwise, should we try to
+ * create an aggregate collection of GSM and CDMA encodings? CDMA
+ * contains a superset of the encodings we use (it does not
+ * support 8-bit GSM, but we also do not use that encoding
+ * currently)... We could get rid of these and directly reference
+ * the CDMA encoding definitions...
+ */
+
+ /** User data text encoding code unit size */
public static final int ENCODING_UNKNOWN = 0;
- /** 7-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_7BIT = 1;
- /** 8-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_8BIT = 2;
- /** 16-bit encoding scheme (see TS 23.038) */
public static final int ENCODING_16BIT = 3;
/** The maximum number of payload bytes per message */
public static final int MAX_USER_DATA_BYTES = 140;
/**
+ * TODO(cleanup): It would be more flexible and less fragile to
+ * rewrite this (meaning get rid of the following constant) such
+ * that an actual UDH is taken into consideration (meaning its
+ * length is measured), allowing for messages that actually
+ * contain other UDH fields... Hence it is actually a shame to
+ * extend the API with this constant. If necessary, maybe define
+ * the size of such a header and let the math for calculating
+ * max_octets/septets be done elsewhere. And, while I am griping,
+ * if we use the word septet, we should use the word octet in
+ * corresponding places, not byte...
+ */
+
+ /**
* The maximum number of payload bytes per message if a user data header
* is present. This assumes the header only contains the
* CONCATENATED_8_BIT_REFERENCE element.
@@ -222,6 +249,15 @@ public class SmsMessage {
}
}
+ /*
+ * TODO(cleanup): It would make some sense if the result of
+ * preprocessing a message to determine the proper encoding (ie
+ * the resulting datastructure from calculateLength) could be
+ * passed as an argument to the actual final encoding function.
+ * This would better ensure that the logic behind size calculation
+ * actually matched the encoding.
+ */
+
/**
* Calculates the number of SMS's required to encode the message body and
* the number of characters remaining until the next message.
@@ -232,46 +268,76 @@ public class SmsMessage {
* space chars. If false, and if the messageBody contains
* non-7-bit encodable characters, length is calculated
* using a 16-bit encoding.
- * @return an int[4] with int[0] being the number of SMS's required, int[1]
- * the number of code units used, and int[2] is the number of code
- * units remaining until the next message. int[3] is the encoding
- * type that should be used for the message.
+ * @return an int[4] with int[0] being the number of SMS's
+ * required, int[1] the number of code units used, and
+ * int[2] is the number of code units remaining until the
+ * next message. int[3] is an indicator of the encoding
+ * code unit size (see the ENCODING_* definitions in this
+ * class).
*/
public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
int activePhone = TelephonyManager.getDefault().getPhoneType();
+ TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly) :
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly);
int ret[] = new int[4];
+ ret[0] = ted.msgCount;
+ ret[1] = ted.codeUnitCount;
+ ret[2] = ted.codeUnitsRemaining;
+ ret[3] = ted.codeUnitSize;
+ return ret;
+ }
- int septets = (PHONE_TYPE_CDMA == activePhone) ?
- com.android.internal.telephony.cdma.SmsMessage.calc7bitEncodedLength(msgBody,
- use7bitOnly) :
- com.android.internal.telephony.gsm.SmsMessage.calc7bitEncodedLength(msgBody,
- use7bitOnly);
- if (septets != -1) {
- ret[1] = septets;
- if (septets > MAX_USER_DATA_SEPTETS) {
- ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
- ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
- - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
- } else {
- ret[0] = 1;
- ret[2] = MAX_USER_DATA_SEPTETS - septets;
- }
- ret[3] = ENCODING_7BIT;
+ /**
+ * Divide a message text into several fragments, none bigger than
+ * the maximum SMS message text size.
+ *
+ * @param text text, must not be null.
+ * @return an <code>ArrayList</code> of strings that, in order,
+ * comprise the original msg text
+ */
+ public static ArrayList<String> fragmentText(String text) {
+ int activePhone = TelephonyManager.getDefault().getPhoneType();
+ TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false) :
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false);
+
+ // TODO(cleanup): The code here could be rolled into the logic
+ // below cleanly if these MAX_* constants were defined more
+ // flexibly...
+
+ int limit;
+ if (ted.msgCount > 1) {
+ limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+ MAX_USER_DATA_SEPTETS_WITH_HEADER : MAX_USER_DATA_BYTES_WITH_HEADER;
} else {
- int octets = msgBody.length() * 2;
- ret[1] = msgBody.length();
- if (octets > MAX_USER_DATA_BYTES) {
- ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
- } else {
- ret[0] = 1;
- ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
- }
- ret[3] = ENCODING_16BIT;
+ limit = (ted.codeUnitSize == ENCODING_7BIT) ?
+ MAX_USER_DATA_SEPTETS : MAX_USER_DATA_BYTES;
}
- return ret;
+ int pos = 0; // Index in code units.
+ int textLen = text.length();
+ ArrayList<String> result = new ArrayList<String>(ted.msgCount);
+ while (pos < textLen) {
+ int nextPos = 0; // Counts code units.
+ if (ted.codeUnitSize == ENCODING_7BIT) {
+ if (PHONE_TYPE_CDMA == activePhone) {
+ nextPos = pos + Math.min(limit, textLen - pos);
+ } else {
+ nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit);
+ }
+ } else { // Assume unicode.
+ nextPos = pos + Math.min(limit / 2, textLen - pos);
+ }
+ if ((nextPos <= pos) || (nextPos > textLen)) {
+ Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
+ nextPos + " >= " + textLen + ")");
+ break;
+ }
+ result.add(text.substring(pos, nextPos));
+ pos = nextPos;
+ }
+ return result;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 8e2941b..e8095e1 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -576,52 +576,6 @@ public class GsmAlphabet {
return size;
}
- /**
- * Returns the index into <code>s</code> of the first character
- * after <code>limit</code> octets have been reached, starting at
- * index <code>start</code>. This is used when dividing messages
- * in UCS2 encoding into units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. <code>MAX_USER_DATA_BYTES</code>
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findUCS2LimitIndex(String s, int start, int limit) {
- int numCharToBeEncoded = s.length() - start;
- return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start;
- }
-
- /**
- * Returns the index into <code>s</code> of the first character
- * after <code>limit</code> septets/octets have been reached
- * according to the <code>encodingType</code>, starting at
- * index <code>start</code>. This is used when dividing messages
- * units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. <code>MAX_USER_DATA_BYTES</code>
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
- if (encodingType == SmsMessage.ENCODING_7BIT) {
- return findGsmSeptetLimitIndex(s, start, limit);
- }
- else if (encodingType == SmsMessage.ENCODING_16BIT) {
- return findUCS2LimitIndex(s, start, limit);
- }
- else {
- throw new EncodeException("Unsupported encoding type: " + encodingType);
- }
- }
-
// Set in the static initializer
private static int sGsmSpaceChar;
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 07fc7c6..c6b7601 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1268,7 +1268,11 @@ public final class RIL extends BaseCommands implements CommandsInterface {
rr.mp.writeString(user);
rr.mp.writeString(password);
//TODO(): Add to the APN database, AuthType is set to CHAP/PAP
- rr.mp.writeString("3");
+ // 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");
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
+ apn);
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 4d32c35..3c7dd45 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -86,6 +86,38 @@ public abstract class SmsMessageBase {
/** TP-Message-Reference - Message Reference of sent message. @hide */
public int messageRef;
+ /**
+ * For a specific text string, this object describes protocol
+ * properties of encoding it for transmission as message user
+ * data.
+ */
+ public static class TextEncodingDetails {
+ /**
+ *The number of SMS's required to encode the text.
+ */
+ public int msgCount;
+
+ /**
+ * The number of code units consumed so far, where code units
+ * are basically characters in the encoding -- for example,
+ * septets for the standard ASCII and GSM encodings, and 16
+ * bits for Unicode.
+ */
+ public int codeUnitCount;
+
+ /**
+ * How many code units are still available without spilling
+ * into an additional message.
+ */
+ public int codeUnitsRemaining;
+
+ /**
+ * The encoding code unit size (specified using
+ * android.telephony.SmsMessage ENCODING_*).
+ */
+ public int codeUnitSize;
+ }
+
public static abstract class SubmitPduBase {
public byte[] encodedScAddress; // Null if not applicable.
public byte[] encodedMessage;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 79e1cd6..2b4a700 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -34,6 +34,7 @@ import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.cdma.SmsMessage;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
import java.io.ByteArrayOutputStream;
@@ -302,8 +303,12 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
deliveryIntent = deliveryIntents.get(i);
}
- SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(scAddr, destAddr,
- parts.get(i), deliveryIntent != null, smsHeader);
+ UserData uData = new UserData();
+ uData.payloadStr = parts.get(i);
+ uData.userDataHeader = smsHeader;
+
+ SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr,
+ uData, deliveryIntent != null);
sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index bbdd0dd..63d2c47 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -357,14 +357,18 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Calculate the number of septets needed to encode the message.
+ * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
*
- * @param messageBody the message to encode
- * @param force ignore (but still count) illegal characters if true
- * @return septet count, or -1 on failure
+ * @param destAddr the address of the destination for the message
+ * @param userDara the data for the message
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
*/
- public static int calc7bitEncodedLength(CharSequence msgBody, boolean force) {
- return BearerData.calc7bitEncodedLength(msgBody.toString(), force);
+ public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
+ boolean statusReportRequested) {
+ return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
}
/**
@@ -442,6 +446,18 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Calculate the number of septets needed to encode the message.
+ *
+ * @param messageBody the message to encode
+ * @param use7bitOnly ignore (but still count) illegal characters if true
+ * @return TextEncodingDetails
+ */
+ public static TextEncodingDetails calculateLength(CharSequence messageBody,
+ boolean use7bitOnly) {
+ return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+ }
+
+ /**
* Returns the teleservice type of the message.
* @return the teleservice:
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
@@ -627,12 +643,15 @@ public class SmsMessage extends SmsMessageBase {
bearerData.userData = userData;
bearerData.hasUserDataHeader = (userData.userDataHeader != null);
+ int teleservice = bearerData.hasUserDataHeader ?
+ SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+
byte[] encodedBearerData = BearerData.encode(bearerData);
if (encodedBearerData == null) return null;
SmsEnvelope envelope = new SmsEnvelope();
envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
- envelope.teleService = SmsEnvelope.TELESERVICE_WMT;
+ envelope.teleService = teleservice;
envelope.destAddress = destAddr;
envelope.bearerReply = RETURN_ACK;
envelope.bearerData = encodedBearerData;
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 3c45aa4..a835dee 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.cdma.sms;
import android.util.Log;
+import android.util.SparseIntArray;
import android.telephony.SmsMessage;
@@ -26,6 +27,7 @@ import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import com.android.internal.util.HexDump;
import com.android.internal.util.BitwiseInputStream;
@@ -35,7 +37,7 @@ import com.android.internal.util.BitwiseOutputStream;
/**
* An object to encode and decode CDMA SMS bearer data.
*/
-public final class BearerData{
+public final class BearerData {
private final static String LOG_TAG = "SMS";
/**
@@ -385,59 +387,64 @@ public final class BearerData{
outStream.skip(3);
}
- private static class SeptetData {
- byte data[];
- int septetCount;
+ private static int countAsciiSeptets(CharSequence msg, boolean force) {
+ int msgLen = msg.length();
+ if (force) return msgLen;
+ for (int i = 0; i < msgLen; i++) {
+ if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
+ return -1;
+ }
+ }
+ return msgLen;
+ }
- SeptetData(byte[] data, int septetCount) {
- this.data = data;
- this.septetCount = septetCount;
+ /**
+ * Calculate the message text encoding length, fragmentation, and other details.
+ *
+ * @param force ignore (but still count) illegal characters if true
+ * @return septet count, or -1 on failure
+ */
+ public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
+ boolean force7BitEncoding) {
+ TextEncodingDetails ted;
+ int septets = countAsciiSeptets(msg, force7BitEncoding);
+ if (septets != -1 && septets <= SmsMessage.MAX_USER_DATA_SEPTETS) {
+ ted = new TextEncodingDetails();
+ ted.msgCount = 1;
+ ted.codeUnitCount = septets;
+ ted.codeUnitsRemaining = SmsMessage.MAX_USER_DATA_SEPTETS - septets;
+ ted.codeUnitSize = SmsMessage.ENCODING_7BIT;
+ } else {
+ ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
+ msg, force7BitEncoding);
}
+ return ted;
}
- private static SeptetData encode7bitAscii(String msg, boolean force)
+ private static byte[] encode7bitAscii(String msg, boolean force)
throws CodingException
{
try {
BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
- byte[] expandedData = msg.getBytes("US-ASCII");
- for (int i = 0; i < expandedData.length; i++) {
- int charCode = expandedData[i];
- // Test ourselves for ASCII membership, since Java seems not to care.
- if ((charCode < UserData.PRINTABLE_ASCII_MIN_INDEX) ||
- (charCode > UserData.PRINTABLE_ASCII_MAX_INDEX)) {
+ int msgLen = msg.length();
+ for (int i = 0; i < msgLen; i++) {
+ int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
+ if (charCode == -1) {
if (force) {
outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
} else {
- throw new CodingException("illegal ASCII code (" + charCode + ")");
+ throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
}
} else {
- outStream.write(7, expandedData[i]);
+ outStream.write(7, charCode);
}
}
- return new SeptetData(outStream.toByteArray(), expandedData.length);
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("7bit ASCII encode failed: " + ex);
+ return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) {
throw new CodingException("7bit ASCII encode failed: " + ex);
}
}
- /**
- * Calculate the number of septets needed to encode the message.
- *
- * @param force ignore (but still count) illegal characters if true
- * @return septet count, or -1 on failure
- */
- public static int calc7bitEncodedLength(String msg, boolean force) {
- try {
- SeptetData data = encode7bitAscii(msg, force);
- return data.septetCount;
- } catch (CodingException ex) {
- return -1;
- }
- }
-
private static byte[] encodeUtf16(String msg)
throws CodingException
{
@@ -452,8 +459,10 @@ public final class BearerData{
throws CodingException
{
try {
- /**
- * TODO(cleanup): find some way to do this without the copy.
+ /*
+ * TODO(cleanup): It would be nice if GsmAlphabet provided
+ * an option to produce just the data without prepending
+ * the length.
*/
byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg);
byte []data = new byte[fullData.length - 1];
@@ -470,54 +479,65 @@ public final class BearerData{
throws CodingException
{
byte[] headerData = null;
+ // TODO: if there is a header, meaning EMS mode, we probably
+ // also want the total UD length prior to the UDH length...
if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet
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");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
payloadData = new byte[0];
+ codeUnitCount = 0;
} else {
payloadData = uData.payload;
+ codeUnitCount = uData.payload.length;
}
} else {
if (uData.payloadStr == null) {
Log.e(LOG_TAG, "non-octet user data with null payloadStr");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
uData.payloadStr = "";
}
if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
payloadData = encode7bitGsm(uData.payloadStr);
+ codeUnitCount = (payloadData.length * 8) / 7;
} else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
- SeptetData septetData = encode7bitAscii(uData.payloadStr, true);
- payloadData = septetData.data;
+ payloadData = encode7bitAscii(uData.payloadStr, true);
+ codeUnitCount = uData.payloadStr.length();
} else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
payloadData = encodeUtf16(uData.payloadStr);
+ codeUnitCount = uData.payloadStr.length();
} else {
throw new CodingException("unsupported user data encoding (" +
uData.msgEncoding + ")");
}
- uData.numFields = uData.payloadStr.length();
}
} else {
if (uData.payloadStr == null) {
Log.e(LOG_TAG, "user data with null payloadStr");
- // TODO(code_review): reasonable for fail case? or maybe bail on encoding?
uData.payloadStr = "";
}
try {
- SeptetData septetData = encode7bitAscii(uData.payloadStr, false);
- payloadData = septetData.data;
- uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+ 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.
+ payloadData = encode7bitGsm(uData.payloadStr);
+ codeUnitCount = (payloadData.length * 8) / 7;
+ uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ }
} catch (CodingException ex) {
payloadData = encodeUtf16(uData.payloadStr);
+ codeUnitCount = uData.payloadStr.length();
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
}
uData.msgEncodingSet = true;
- uData.numFields = uData.payloadStr.length();
}
int totalLength = payloadData.length + headerDataLen;
@@ -526,6 +546,7 @@ public final class BearerData{
" > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
}
+ uData.numFields = codeUnitCount;
uData.payload = new byte[totalLength];
if (headerData != null) {
uData.payload[0] = (byte)headerData.length;
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 8d4e769..d8a48cc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.cdma.sms;
+import android.util.SparseIntArray;
+
import com.android.internal.telephony.SmsHeader;
import com.android.internal.util.HexDump;
@@ -40,6 +42,10 @@ public class UserData {
/**
* IA5 data encoding character mappings.
* (See CCITT Rec. T.50 Tables 1 and 3)
+ *
+ * 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.
*/
public static final char[] IA5_MAP = {
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
@@ -61,7 +67,16 @@ public class UserData {
* Only elements between these indices in the ASCII table are printable.
*/
public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
- public static final int PRINTABLE_ASCII_MAX_INDEX = 0x7F;
+ public static final int ASCII_LF_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);
+ }
+ charToAscii.put('\r', ASCII_LF_INDEX);
+ charToAscii.put('\n', ASCII_CR_INDEX);
+ }
/**
* Mapping for IA5 values less than 32 are flow control signals
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index a15bbdf..f1207e4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -26,6 +26,7 @@ import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
@@ -742,17 +743,39 @@ public class SmsMessage extends SmsMessageBase{
/**
* Calculate the number of septets needed to encode the message.
*
- * @param messageBody the message to encode
- * @param force ignore (but still count) illegal characters if true
- * @return septet count, or -1 on failure
+ * @param msgBody the message to encode
+ * @param use7bitOnly ignore (but still count) illegal characters if true
+ * @return TextEncodingDetails
*/
- public static int calc7bitEncodedLength(CharSequence messageBody, boolean force) {
+ public static TextEncodingDetails calculateLength(CharSequence msgBody,
+ boolean use7bitOnly) {
+ TextEncodingDetails ted = new TextEncodingDetails();
try {
- return GsmAlphabet.countGsmSeptets(messageBody, !force);
+ int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
+ ted.codeUnitCount = septets;
+ if (septets > MAX_USER_DATA_SEPTETS) {
+ ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
+ ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
+ - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+ } else {
+ ted.msgCount = 1;
+ ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
+ }
+ ted.codeUnitSize = ENCODING_7BIT;
} catch (EncodeException ex) {
- /* Just fall through to the -1 error result below. */
+ int octets = msgBody.length() * 2;
+ ted.codeUnitCount = msgBody.length();
+ if (octets > MAX_USER_DATA_BYTES) {
+ ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
+ ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
+ - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ } else {
+ ted.msgCount = 1;
+ ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
+ }
+ ted.codeUnitSize = ENCODING_16BIT;
}
- return -1;
+ return ted;
}
/** {@inheritDoc} */
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 9e0cf2c..efc4880 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
@@ -100,6 +101,11 @@ public class MockContext extends Context {
}
@Override
+ public ApplicationInfo getApplicationInfo() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public String getPackageResourcePath() {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index f98a251..63a177e 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -16,10 +16,10 @@
package android.test.mock;
-import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDeleteObserver;
@@ -62,11 +62,6 @@ public class MockPackageManager extends PackageManager {
}
@Override
- public ResolveInfo resolveActivity(Intent intent, int flags, String packageName) {
- throw new UnsupportedOperationException();
- }
-
- @Override
public int[] getPackageGids(String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@@ -328,13 +323,13 @@ public class MockPackageManager extends PackageManager {
long idealStorageSize, IPackageDataObserver observer) {
throw new UnsupportedOperationException();
}
-
+
/**
* @hide - to match hiding in superclass
*/
@Override
public void freeStorage(
- long idealStorageSize, PendingIntent onFinishedIntent) {
+ long idealStorageSize, IntentSender pi) {
throw new UnsupportedOperationException();
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
index 3daa8ab..fb1b9ad 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -507,7 +507,7 @@ public class AppCacheTest extends AndroidTestCase {
try {
// Spin lock waiting for call back
synchronized(r) {
- getPm().freeStorage(idealStorageSize, pi);
+ getPm().freeStorage(idealStorageSize, pi.getIntentSender());
long waitTime = 0;
while(!r.isDone() && (waitTime < MAX_WAIT_TIME)) {
r.wait(WAIT_TIME_INCR);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 16aca4d..b2529811 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -103,6 +103,9 @@ public class CdmaSmsTest extends AndroidTestCase {
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "More @ testing\nis great^|^~woohoo";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index 50ccb24..49165d0 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -131,7 +131,7 @@ def CompareResults(ref_dir, results_dir):
result_file_name = "layout_tests_" + f + ".txt"
DiffResults(f, os.path.join(results_dir, result_file_name),
os.path.join(ref_dir, result_file_name), diff_result,
- False, files != "passed")
+ False, f != "passed")
logging.info("Detailed diffs are in " + diff_result)
def main(options, args):
diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
index af7dfd4..f0c3f93 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java
@@ -17,14 +17,17 @@
package com.android.backuptest;
import android.app.ListActivity;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataOutput;
import android.backup.BackupManager;
+import android.backup.FileBackupHelper;
+import android.backup.FileRestoreHelper;
+import android.backup.RestoreHelperDispatcher;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.PowerManager;
-import android.os.SystemClock;
+import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
@@ -32,6 +35,10 @@ import android.widget.ListView;
import android.widget.Toast;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
@@ -123,6 +130,48 @@ public class BackupTestActivity extends ListActivity
BackupManager bm = new BackupManager(BackupTestActivity.this);
bm.dataChanged();
}
+ },
+ new Test("Backup Helpers") {
+ void run() {
+ try {
+ writeFile("a", "a\naa", MODE_PRIVATE);
+ writeFile("empty", "", MODE_PRIVATE);
+
+ ParcelFileDescriptor state = ParcelFileDescriptor.open(
+ new File(getFilesDir(), "state"),
+ ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
+ ParcelFileDescriptor.MODE_TRUNCATE);
+ FileBackupHelper h = new FileBackupHelper(BackupTestActivity.this,
+ "FileBackupHelper");
+ FileOutputStream dataFile = openFileOutput("backup_test", MODE_WORLD_READABLE);
+ BackupDataOutput data = new BackupDataOutput(dataFile.getFD());
+ h.performBackup(null, data, state, new String[] { "a", "empty" });
+ dataFile.close();
+ state.close();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ },
+ new Test("Restore Helpers") {
+ void run() {
+ try {
+ RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
+ dispatch.addHelper("FileBackupHelper",
+ new FileRestoreHelper(BackupTestActivity.this));
+ FileInputStream dataFile = openFileInput("backup_test");
+ BackupDataInput data = new BackupDataInput(dataFile.getFD());
+ ParcelFileDescriptor state = ParcelFileDescriptor.open(
+ new File(getFilesDir(), "restore_state"),
+ ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE|
+ ParcelFileDescriptor.MODE_TRUNCATE);
+ dispatch.dispatch(data, state);
+ dataFile.close();
+ state.close();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
};
@@ -154,5 +203,14 @@ public class BackupTestActivity extends ListActivity
t.run();
}
+ void writeFile(String name, String contents, int mode) {
+ try {
+ PrintStream out = new PrintStream(openFileOutput(name, mode));
+ out.print(contents);
+ out.close();
+ } catch (FileNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
index a370d69..0da4151 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -17,28 +17,45 @@
package com.android.backuptest;
import android.app.BackupAgent;
+import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.FileBackupHelper;
+import android.backup.FileRestoreHelper;
+import android.backup.RestoreHelperDispatcher;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import java.io.IOException;
+
public class BackupTestAgent extends BackupAgent
{
static final String TAG = "BackupTestAgent";
+ static final String SHARED_PREFS = "shared_prefs";
+ static final String DATA_FILES = "data_files";
+ static final String[] FILES = new String[] {
+ BackupTestActivity.FILE_NAME
+ };
+
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Log.d(TAG, "onBackup");
- FileBackupHelper helper = new FileBackupHelper(this);
- helper.performBackup(oldState, data, newState, new String[] {
- BackupTestActivity.FILE_NAME
- });
+
+ (new FileBackupHelper(this, DATA_FILES)).performBackup(oldState, data, newState, FILES);
}
@Override
- public void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) {
+ public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
+ throws IOException {
Log.d(TAG, "onRestore");
+
+ RestoreHelperDispatcher dispatch = new RestoreHelperDispatcher();
+
+ // dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this));
+ dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this));
+
+ dispatch.dispatch(data, newState);
}
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
new file mode 100644
index 0000000..dc6860a
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
@@ -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.
+ */
+
+package com.android.framework.permission.tests;
+
+import junit.framework.TestCase;
+
+import android.os.Binder;
+import android.os.IHardwareService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Verify that Hardware apis cannot be called without required permissions.
+ */
+public class HardwareServicePermissionTest extends TestCase {
+
+ private IHardwareService mHardwareService;
+
+ @Override
+ protected void setUp() throws Exception {
+ mHardwareService = IHardwareService.Stub.asInterface(
+ ServiceManager.getService("hardware"));
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#vibrate(long)} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testVibrate() throws RemoteException {
+ try {
+ mHardwareService.vibrate(2000);
+ fail("vibrate did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#vibratePattern(long[],
+ * int, android.os.IBinder)} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testVibratePattern() throws RemoteException {
+ try {
+ mHardwareService.vibratePattern(new long[] {0}, 0, new Binder());
+ fail("vibratePattern did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#cancelVibrate()} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testCancelVibrate() throws RemoteException {
+ try {
+ mHardwareService.cancelVibrate();
+ fail("cancelVibrate did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#setFlashlightEnabled(boolean)}
+ * requires permissions.
+ * <p>Tests permissions:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * {@link android.Manifest.permission#FLASHLIGHT}
+ * @throws RemoteException
+ */
+ public void testSetFlashlightEnabled() throws RemoteException {
+ try {
+ mHardwareService.setFlashlightEnabled(true);
+ fail("setFlashlightEnabled did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#enableCameraFlash(int)} requires
+ * permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * {@link android.Manifest.permission#CAMERA}
+ * @throws RemoteException
+ */
+ public void testEnableCameraFlash() throws RemoteException {
+ try {
+ mHardwareService.enableCameraFlash(100);
+ fail("enableCameraFlash did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#setBacklights(int)} requires
+ * permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * @throws RemoteException
+ */
+ public void testSetBacklights() throws RemoteException {
+ try {
+ mHardwareService.setBacklights(0);
+ fail("setBacklights did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
new file mode 100644
index 0000000..273943f
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.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 com.android.framework.permission.tests;
+
+import java.util.ArrayList;
+
+import android.telephony.SmsManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Verify that SmsManager apis cannot be called without required permissions.
+ */
+public class SmsManagerPermissionTest extends AndroidTestCase {
+
+ private static final String MSG_CONTENTS = "hi";
+ private static final short DEST_PORT = (short)1004;
+ private static final String DEST_NUMBER = "4567";
+ private static final String SRC_NUMBER = "1234";
+
+ /**
+ * Verify that SmsManager.sendTextMessage requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#SEND_SMS}.
+ */
+ @SmallTest
+ public void testSendTextMessage() {
+ try {
+ SmsManager.getDefault().sendTextMessage(SRC_NUMBER, DEST_NUMBER, MSG_CONTENTS, null,
+ null);
+ fail("SmsManager.sendTextMessage did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that SmsManager.sendDataMessage requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#SEND_SMS}.
+ */
+ @SmallTest
+ public void testSendDataMessage() {
+ try {
+ SmsManager.getDefault().sendDataMessage(SRC_NUMBER, DEST_NUMBER, DEST_PORT,
+ MSG_CONTENTS.getBytes(), null, null);
+ fail("SmsManager.sendDataMessage did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that SmsManager.sendMultipartMessage requires permissions.
+ * <p>Tests Permission:
+ * {@link android.Manifest.permission#SEND_MMS}.
+ */
+ @SmallTest
+ public void testSendMultipartMessage() {
+ try {
+ ArrayList<String> msgParts = new ArrayList<String>(2);
+ msgParts.add(MSG_CONTENTS);
+ msgParts.add("foo");
+ SmsManager.getDefault().sendMultipartTextMessage(SRC_NUMBER, DEST_NUMBER, msgParts,
+ null, null);
+ fail("SmsManager.sendMultipartTextMessage did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 9e712b8..a671bd7 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -37,6 +37,7 @@ public:
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
mUpdate(false), mExtending(false),
mRequireLocalization(false), mPseudolocalize(false),
+ mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mAssetSourceDir(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
@@ -75,6 +76,8 @@ public:
void setRequireLocalization(bool val) { mRequireLocalization = val; }
bool getPseudolocalize(void) const { return mPseudolocalize; }
void setPseudolocalize(bool val) { mPseudolocalize = val; }
+ bool getValues(void) const { return mValues; }
+ void setValues(bool val) { mValues = val; }
int getCompressionMethod(void) const { return mCompressionMethod; }
void setCompressionMethod(int val) { mCompressionMethod = val; }
const char* getOutputAPKFile() const { return mOutputAPKFile; }
@@ -154,6 +157,7 @@ private:
bool mExtending;
bool mRequireLocalization;
bool mPseudolocalize;
+ bool mValues;
int mCompressionMethod;
const char* mOutputAPKFile;
const char* mAssetSourceDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0e889f5..dcda379 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -198,7 +198,7 @@ int doList(Bundle* bundle)
printf("\nNo resource table found.\n");
} else {
printf("\nResource table:\n");
- res.print();
+ res.print(false);
}
Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -382,7 +382,7 @@ int doDump(Bundle* bundle)
}
if (strcmp("resources", option) == 0) {
- res.print();
+ res.print(bundle->getValues());
} else if (strcmp("xmltree", option) == 0) {
if (bundle->getFileSpecCount() < 3) {
@@ -734,11 +734,12 @@ int doDump(Bundle* bundle)
activityIcon.string());
}
}
+
printf("locales:");
Vector<String8> locales;
res.getLocales(&locales);
- const size_t N = locales.size();
- for (size_t i=0; i<N; i++) {
+ const size_t NL = locales.size();
+ for (size_t i=0; i<NL; i++) {
const char* localeStr = locales[i].string();
if (localeStr == NULL || strlen(localeStr) == 0) {
localeStr = "--_--";
@@ -746,6 +747,24 @@ int doDump(Bundle* bundle)
printf(" '%s'", localeStr);
}
printf("\n");
+
+ Vector<ResTable_config> configs;
+ res.getConfigurations(&configs);
+ SortedVector<int> densities;
+ const size_t NC = configs.size();
+ for (size_t i=0; i<NC; i++) {
+ int dens = configs[i].density;
+ if (dens == 0) dens = 160;
+ densities.add(dens);
+ }
+
+ printf("densities:");
+ const size_t ND = densities.size();
+ for (size_t i=0; i<ND; i++) {
+ printf(" '%d'", densities[i]);
+ }
+ printf("\n");
+
AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
if (dir != NULL) {
if (dir->getFileCount() > 0) {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index a33b4d7..882714c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -47,7 +47,7 @@ void usage(void)
" %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
" List contents of Zip-compatible archive.\n\n", gProgName);
fprintf(stderr,
- " %s d[ump] WHAT file.{apk} [asset [asset ...]]\n"
+ " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
" badging Print the label and icon for the app declared in APK.\n"
" permissions Print the permissions from the APK.\n"
" resources Print the resource table from the APK.\n"
@@ -125,6 +125,8 @@ void usage(void)
" inserts android:targetSdkVersion in to manifest.\n"
" --max-sdk-version\n"
" inserts android:maxSdkVersion in to manifest.\n"
+ " --values\n"
+ " when used with \"dump resources\" also includes resource values.\n"
" --version-code\n"
" inserts android:versionCode in to manifest.\n"
" --version-name\n"
@@ -398,6 +400,8 @@ int main(int argc, char* const argv[])
goto bail;
}
bundle.setVersionName(argv[0]);
+ } else if (strcmp(cp, "-values") == 0) {
+ bundle.setValues(true);
} else {
fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
wantUsage = true;
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 47a7ec0..d0a1c46 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -55,6 +55,8 @@ import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
+import android.widget.TabHost;
+import android.widget.TabWidget;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
@@ -69,10 +71,10 @@ import java.util.Map;
* {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}.
*/
public final class Bridge implements ILayoutBridge {
-
+
private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
-
+
public static class StaticMethodNotImplementedException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -82,19 +84,20 @@ public final class Bridge implements ILayoutBridge {
}
/**
- * Maps from id to resource name/type.
+ * Maps from id to resource name/type. This is for android.R only.
*/
private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>();
/**
- * Same as sRMap except for int[] instead of int resources.
+ * Same as sRMap except for int[] instead of int resources. This is for android.R only.
*/
private final static Map<int[], String> sRArrayMap = new HashMap<int[], String>();
/**
- * Reverse map compared to sRMap, resource type -> (resource name -> id)
+ * Reverse map compared to sRMap, resource type -> (resource name -> id).
+ * This is for android.R only.
*/
private final static Map<String, Map<String, Integer>> sRFullMap =
new HashMap<String, Map<String,Integer>>();
-
+
private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
private final static Map<Object, Map<String, SoftReference<NinePatch>>> sProject9PatchCache =
@@ -104,7 +107,7 @@ public final class Bridge implements ILayoutBridge {
new HashMap<String, SoftReference<Bitmap>>();
private final static Map<String, SoftReference<NinePatch>> sFramework9PatchCache =
new HashMap<String, SoftReference<NinePatch>>();
-
+
private static Map<String, Map<String, Integer>> sEnumValueMap;
/**
@@ -156,14 +159,14 @@ public final class Bridge implements ILayoutBridge {
return sinit(fontOsLocation, enumValueMap);
}
-
+
private static synchronized boolean sinit(String fontOsLocation,
Map<String, Map<String, Integer>> enumValueMap) {
// When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener
// on static (native) methods which prints the signature on the console and
// throws an exception.
- // This is useful when testing the rendering in ADT to identify static native
+ // This is useful when testing the rendering in ADT to identify static native
// methods that are ignored -- layoutlib_create makes them returns 0/false/null
// which is generally OK yet might be a problem, so this is how you'd find out.
//
@@ -214,7 +217,7 @@ public final class Bridge implements ILayoutBridge {
} else {
return false;
}
-
+
sEnumValueMap = enumValueMap;
// now parse com.android.internal.R (and only this one as android.R is a subset of
@@ -226,13 +229,13 @@ public final class Bridge implements ILayoutBridge {
// int[] does not implement equals/hashCode, and if the parsing used a different class
// loader for the R class, this would NOT work.
Class<?> r = com.android.internal.R.class;
-
+
for (Class<?> inner : r.getDeclaredClasses()) {
String resType = inner.getSimpleName();
Map<String, Integer> fullMap = new HashMap<String, Integer>();
sRFullMap.put(resType, fullMap);
-
+
for (Field f : inner.getDeclaredFields()) {
// only process static final fields. Since the final attribute may have
// been altered by layoutlib_create, we only check static
@@ -243,7 +246,7 @@ public final class Bridge implements ILayoutBridge {
// if the object is an int[] we put it in sRArrayMap
sRArrayMap.put((int[]) f.get(null), f.getName());
} else if (type == int.class) {
- Integer value = (Integer) f.get(null);
+ Integer value = (Integer) f.get(null);
sRMap.put(value, new String[] { f.getName(), resType });
fullMap.put(f.getName(), value);
} else {
@@ -281,7 +284,7 @@ public final class Bridge implements ILayoutBridge {
themeName = themeName.substring(1);
isProjectTheme = true;
}
-
+
return computeLayout(layoutDescription, projectKey,
screenWidth, screenHeight, DisplayMetrics.DEFAULT_DENSITY,
DisplayMetrics.DEFAULT_DENSITY, DisplayMetrics.DEFAULT_DENSITY,
@@ -294,6 +297,7 @@ public final class Bridge implements ILayoutBridge {
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
+ @Deprecated
public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
Map<String, Map<String, IResourceValue>> projectResources,
@@ -319,7 +323,7 @@ public final class Bridge implements ILayoutBridge {
if (logger == null) {
logger = sDefaultLogger;
}
-
+
synchronized (sDefaultLogger) {
sLogger = logger;
}
@@ -327,12 +331,12 @@ public final class Bridge implements ILayoutBridge {
// find the current theme and compute the style inheritance map
Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
new HashMap<IStyleResourceValue, IStyleResourceValue>();
-
+
IStyleResourceValue currentTheme = computeStyleMaps(themeName, isProjectTheme,
projectResources.get(BridgeConstants.RES_STYLE),
frameworkResources.get(BridgeConstants.RES_STYLE), styleParentMap);
-
- BridgeContext context = null;
+
+ BridgeContext context = null;
try {
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
@@ -347,29 +351,32 @@ public final class Bridge implements ILayoutBridge {
frameworkResources, styleParentMap, customViewLoader, logger);
BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
context.setBridgeInflater(inflater);
-
+
IResourceValue windowBackground = null;
int screenOffset = 0;
if (currentTheme != null) {
windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
windowBackground = context.resolveResValue(windowBackground);
-
+
screenOffset = getScreenOffset(currentTheme, context);
}
-
+
// we need to make sure the Looper has been initialized for this thread.
// this is required for View that creates Handler objects.
if (Looper.myLooper() == null) {
Looper.prepare();
}
-
+
BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
context, false /* platformResourceFlag */);
-
+
ViewGroup root = new FrameLayout(context);
-
+
View view = inflater.inflate(parser, root);
-
+
+ // post-inflate process. For now this supports TabHost/TabWidget
+ postInflateProcess(view, customViewLoader);
+
// set the AttachInfo on the root view.
AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
new Handler(), null);
@@ -392,16 +399,19 @@ public final class Bridge implements ILayoutBridge {
// measure the views
view.measure(w_spec, h_spec);
view.layout(0, screenOffset, screenWidth, screenHeight);
-
+
// draw them
BridgeCanvas canvas = new BridgeCanvas(screenWidth, screenHeight - screenOffset,
logger);
-
+
root.draw(canvas);
canvas.dispose();
-
+
return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
canvas.getImage());
+ } catch (PostInflateException e) {
+ return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
+ + e.getMessage());
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -419,7 +429,7 @@ public final class Bridge implements ILayoutBridge {
// Make sure to remove static references, otherwise we could not unload the lib
BridgeResources.clearSystem();
BridgeAssetManager.clearSystem();
-
+
// Remove the global logger
synchronized (sDefaultLogger) {
sLogger = sDefaultLogger;
@@ -437,18 +447,18 @@ public final class Bridge implements ILayoutBridge {
sProject9PatchCache.remove(projectKey);
}
}
-
+
/**
* Returns details of a framework resource from its integer value.
* @param value the integer value
* @return an array of 2 strings containing the resource name and type, or null if the id
- * does not match any resource.
+ * does not match any resource.
*/
public static String[] resolveResourceValue(int value) {
return sRMap.get(value);
-
+
}
-
+
/**
* Returns the name of a framework resource whose value is an int array.
* @param array
@@ -456,7 +466,7 @@ public final class Bridge implements ILayoutBridge {
public static String resolveResourceValue(int[] array) {
return sRArrayMap.get(array);
}
-
+
/**
* Returns the integer id of a framework resource, from a given resource type and resource name.
* @param type the type of the resource
@@ -468,15 +478,15 @@ public final class Bridge implements ILayoutBridge {
if (map != null) {
return map.get(name);
}
-
+
return null;
}
-
+
static Map<String, Integer> getEnumValues(String attributeName) {
if (sEnumValueMap != null) {
return sEnumValueMap.get(attributeName);
}
-
+
return null;
}
@@ -507,13 +517,13 @@ public final class Bridge implements ILayoutBridge {
return result;
}
-
+
/**
* Compute style information from the given list of style for the project and framework.
* @param themeName the name of the current theme. In order to differentiate project and
* platform themes sharing the same name, all project themes must be prepended with
* a '*' character.
- * @param isProjectTheme Is this a project theme
+ * @param isProjectTheme Is this a project theme
* @param inProjectStyleMap the project style map
* @param inFrameworkStyleMap the framework style map
* @param outInheritanceMap the map of style inheritance. This is filled by the method
@@ -523,23 +533,23 @@ public final class Bridge implements ILayoutBridge {
String themeName, boolean isProjectTheme, Map<String,
IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap,
Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
-
+
if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
// first, get the theme
IResourceValue theme = null;
-
+
// project theme names have been prepended with a *
if (isProjectTheme) {
theme = inProjectStyleMap.get(themeName);
} else {
theme = inFrameworkStyleMap.get(themeName);
}
-
+
if (theme instanceof IStyleResourceValue) {
// compute the inheritance map for both the project and framework styles
computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
inFrameworkStyleMap, outInheritanceMap);
-
+
// Compute the style inheritance for the framework styles/themes.
// Since, for those, the style parent values do not contain 'android:'
// we want to force looking in the framework style only to avoid using
@@ -547,11 +557,11 @@ public final class Bridge implements ILayoutBridge {
// To do this, we pass null in lieu of the project style map.
computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
inFrameworkStyleMap, outInheritanceMap);
-
+
return (IStyleResourceValue)theme;
}
}
-
+
return null;
}
@@ -573,7 +583,7 @@ public final class Bridge implements ILayoutBridge {
// first look for a specified parent.
String parentName = style.getParentStyle();
-
+
// no specified parent? try to infer it from the name of the style.
if (parentName == null) {
parentName = getParentName(value.getName());
@@ -581,7 +591,7 @@ public final class Bridge implements ILayoutBridge {
if (parentName != null) {
parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
+
if (parentStyle != null) {
outInheritanceMap.put(style, parentStyle);
}
@@ -589,7 +599,7 @@ public final class Bridge implements ILayoutBridge {
}
}
}
-
+
/**
* Searches for and returns the {@link IStyleResourceValue} from a given name.
* <p/>The format of the name can be:
@@ -607,27 +617,27 @@ public final class Bridge implements ILayoutBridge {
Map<String, IResourceValue> inProjectStyleMap,
Map<String, IResourceValue> inFrameworkStyleMap) {
boolean frameworkOnly = false;
-
+
String name = parentName;
-
+
// remove the useless @ if it's there
if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
}
-
+
// check for framework identifier.
if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
frameworkOnly = true;
name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
}
-
+
// at this point we could have the format style/<name>. we want only the name
if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
}
IResourceValue parent = null;
-
+
// if allowed, search in the project resources.
if (frameworkOnly == false && inProjectStyleMap != null) {
parent = inProjectStyleMap.get(name);
@@ -637,17 +647,17 @@ public final class Bridge implements ILayoutBridge {
if (parent == null) {
parent = inFrameworkStyleMap.get(name);
}
-
+
// make sure the result is the proper class type and return it.
if (parent instanceof IStyleResourceValue) {
return (IStyleResourceValue)parent;
}
-
+
sLogger.error(String.format("Unable to resolve parent style name: ", parentName));
-
+
return null;
}
-
+
/**
* Computes the name of the parent style, or <code>null</code> if the style is a root style.
*/
@@ -656,10 +666,10 @@ public final class Bridge implements ILayoutBridge {
if (index != -1) {
return styleName.substring(0, index);
}
-
+
return null;
}
-
+
/**
* Returns the top screen offset. This depends on whether the current theme defines the user
* of the title and status bars.
@@ -670,7 +680,7 @@ public final class Bridge implements ILayoutBridge {
// get the title bar flag from the current theme.
IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
-
+
// because it may reference something else, we resolve it.
value = context.resolveResValue(value);
@@ -679,10 +689,10 @@ public final class Bridge implements ILayoutBridge {
XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
// get value from the theme.
value = context.findItemInStyle(currentTheme, "windowTitleSize");
-
+
// resolve it
value = context.resolveResValue(value);
-
+
// default value
offset = DEFAULT_TITLE_BAR_HEIGHT;
@@ -690,17 +700,17 @@ public final class Bridge implements ILayoutBridge {
if (value != null) {
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
- offset = (int)typedValue.getDimension(context.getResources().mMetrics);
+ offset = (int)typedValue.getDimension(context.getResources().mMetrics);
}
}
}
-
+
// get the fullscreen flag from the current theme.
value = context.findItemInStyle(currentTheme, "windowFullscreen");
-
+
// because it may reference something else, we resolve it.
value = context.resolveResValue(value);
-
+
if (value == null || value.getValue() == null ||
XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
// FIXME: Right now this is hard-coded in the platform, but once there's a constant, we'll need to use it.
@@ -711,6 +721,94 @@ public final class Bridge implements ILayoutBridge {
}
/**
+ * Post process on a view hierachy that was just inflated.
+ * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+ * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
+ * based on the content of the {@link FrameLayout}.
+ * @param view the root view to process.
+ * @param projectCallback callback to the project.
+ */
+ private void postInflateProcess(View view, IProjectCallback projectCallback)
+ throws PostInflateException {
+ if (view instanceof TabHost) {
+ setupTabHost((TabHost)view, projectCallback);
+ } else if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup)view;
+ final int count = group.getChildCount();
+ for (int c = 0 ; c < count ; c++) {
+ View child = group.getChildAt(c);
+ postInflateProcess(child, projectCallback);
+ }
+ }
+ }
+
+ /**
+ * Sets up a {@link TabHost} object.
+ * @param tabHost the TabHost to setup.
+ * @param projectCallback The project callback object to access the project R class.
+ * @throws PostInflateException
+ */
+ private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
+ throws PostInflateException {
+ // look for the TabWidget, and the FrameLayout. They have their own specific names
+ View v = tabHost.findViewById(android.R.id.tabs);
+
+ if (v == null) {
+ throw new PostInflateException(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
+ }
+
+ if ((v instanceof TabWidget) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
+ "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ v = tabHost.findViewById(android.R.id.tabcontent);
+
+ if (v == null) {
+ // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+ throw new PostInflateException(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
+ }
+
+ if ((v instanceof FrameLayout) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
+ "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ FrameLayout content = (FrameLayout)v;
+
+ // now process the content of the framelayout and dynamically create tabs for it.
+ final int count = content.getChildCount();
+
+ if (count == 0) {
+ throw new PostInflateException(
+ "The FrameLayout for the TabHost has no content. Rendering failed.\n");
+ }
+
+ // this must be called before addTab() so that the TabHost searches its TabWidget
+ // and FrameLayout.
+ tabHost.setup();
+
+ // for each child of the framelayout, add a new TabSpec
+ for (int i = 0 ; i < count ; i++) {
+ View child = content.getChildAt(i);
+ String tabSpec = String.format("tab_spec%d", i+1);
+ int id = child.getId();
+ String[] resource = projectCallback.resolveResourceValue(id);
+ String name;
+ if (resource != null) {
+ name = resource[0]; // 0 is resource name, 1 is resource type.
+ } else {
+ name = String.format("Tab %d", i+1); // default name if id is unresolved.
+ }
+ tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
+ }
+ }
+
+ /**
* Returns the bitmap for a specific path, from a specific project cache, or from the
* framework cache.
* @param value the path of the bitmap
@@ -750,7 +848,7 @@ public final class Bridge implements ILayoutBridge {
map = new HashMap<String, SoftReference<Bitmap>>();
sProjectBitmapCache.put(projectKey, map);
}
-
+
map.put(value, new SoftReference<Bitmap>(bmp));
} else {
sFrameworkBitmapCache.put(value, new SoftReference<Bitmap>(bmp));
@@ -767,7 +865,7 @@ public final class Bridge implements ILayoutBridge {
static NinePatch getCached9Patch(String value, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
-
+
if (map != null) {
SoftReference<NinePatch> ref = map.get(value);
if (ref != null) {
@@ -780,7 +878,7 @@ public final class Bridge implements ILayoutBridge {
return ref.get();
}
}
-
+
return null;
}
@@ -798,13 +896,21 @@ public final class Bridge implements ILayoutBridge {
map = new HashMap<String, SoftReference<NinePatch>>();
sProject9PatchCache.put(projectKey, map);
}
-
+
map.put(value, new SoftReference<NinePatch>(ninePatch));
} else {
sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
}
}
+ private static final class PostInflateException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public PostInflateException(String message) {
+ super(message);
+ }
+ }
+
/**
* Implementation of {@link IWindowSession} so that mSession is not null in
* the {@link SurfaceView}.
@@ -839,7 +945,7 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
return false;
}
-
+
@SuppressWarnings("unused")
public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
// pass for now.
@@ -863,7 +969,7 @@ public final class Bridge implements ILayoutBridge {
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
// pass for now.
}
-
+
@SuppressWarnings("unused")
public void remove(IWindow arg0) throws RemoteException {
// pass for now.
@@ -883,13 +989,13 @@ public final class Bridge implements ILayoutBridge {
Rect visibleInsets) {
// pass for now.
}
-
+
public IBinder asBinder() {
// pass for now.
return null;
}
}
-
+
/**
* Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
*/
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index d0896b5..69f3d9c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -960,6 +961,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public ApplicationInfo getApplicationInfo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public String getPackageResourcePath() {
// TODO Auto-generated method stub
return null;